mirror of
				https://github.com/TeaOSLab/EdgeAPI.git
				synced 2025-11-04 07:50:25 +08:00 
			
		
		
		
	新版IP库管理阶段性提交(未完成)
This commit is contained in:
		@@ -88,6 +88,7 @@ function build() {
 | 
				
			|||||||
		mkdir "$DIST"/bin
 | 
							mkdir "$DIST"/bin
 | 
				
			||||||
		mkdir "$DIST"/configs
 | 
							mkdir "$DIST"/configs
 | 
				
			||||||
		mkdir "$DIST"/logs
 | 
							mkdir "$DIST"/logs
 | 
				
			||||||
 | 
							mkdir "$DIST"/data
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
	cp "$ROOT"/configs/api.template.yaml "$DIST"/configs/
 | 
						cp "$ROOT"/configs/api.template.yaml "$DIST"/configs/
 | 
				
			||||||
	cp "$ROOT"/configs/db.template.yaml "$DIST"/configs/
 | 
						cp "$ROOT"/configs/db.template.yaml "$DIST"/configs/
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,23 +14,23 @@ type Admin struct {
 | 
				
			|||||||
	UpdatedAt uint64   `field:"updatedAt"` // 修改时间
 | 
						UpdatedAt uint64   `field:"updatedAt"` // 修改时间
 | 
				
			||||||
	State     uint8    `field:"state"`     // 状态
 | 
						State     uint8    `field:"state"`     // 状态
 | 
				
			||||||
	Modules   dbs.JSON `field:"modules"`   // 允许的模块
 | 
						Modules   dbs.JSON `field:"modules"`   // 允许的模块
 | 
				
			||||||
	CanLogin  uint8    `field:"canLogin"`  // 是否可以登录
 | 
						CanLogin  bool     `field:"canLogin"`  // 是否可以登录
 | 
				
			||||||
	Theme     string   `field:"theme"`     // 模板设置
 | 
						Theme     string   `field:"theme"`     // 模板设置
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type AdminOperator struct {
 | 
					type AdminOperator struct {
 | 
				
			||||||
	Id        interface{} // ID
 | 
						Id        any // ID
 | 
				
			||||||
	IsOn      interface{} // 是否启用
 | 
						IsOn      any // 是否启用
 | 
				
			||||||
	Username  interface{} // 用户名
 | 
						Username  any // 用户名
 | 
				
			||||||
	Password  interface{} // 密码
 | 
						Password  any // 密码
 | 
				
			||||||
	Fullname  interface{} // 全名
 | 
						Fullname  any // 全名
 | 
				
			||||||
	IsSuper   interface{} // 是否为超级管理员
 | 
						IsSuper   any // 是否为超级管理员
 | 
				
			||||||
	CreatedAt interface{} // 创建时间
 | 
						CreatedAt any // 创建时间
 | 
				
			||||||
	UpdatedAt interface{} // 修改时间
 | 
						UpdatedAt any // 修改时间
 | 
				
			||||||
	State     interface{} // 状态
 | 
						State     any // 状态
 | 
				
			||||||
	Modules   interface{} // 允许的模块
 | 
						Modules   any // 允许的模块
 | 
				
			||||||
	CanLogin  interface{} // 是否可以登录
 | 
						CanLogin  any // 是否可以登录
 | 
				
			||||||
	Theme     interface{} // 模板设置
 | 
						Theme     any // 模板设置
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewAdminOperator() *AdminOperator {
 | 
					func NewAdminOperator() *AdminOperator {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,23 +12,23 @@ type HTTPCacheTask struct {
 | 
				
			|||||||
	Day         string `field:"day"`         // 创建日期YYYYMMDD
 | 
						Day         string `field:"day"`         // 创建日期YYYYMMDD
 | 
				
			||||||
	IsDone      bool   `field:"isDone"`      // 是否已完成
 | 
						IsDone      bool   `field:"isDone"`      // 是否已完成
 | 
				
			||||||
	IsOk        bool   `field:"isOk"`        // 是否完全成功
 | 
						IsOk        bool   `field:"isOk"`        // 是否完全成功
 | 
				
			||||||
	IsReady     uint8  `field:"isReady"`     // 是否已准备好
 | 
						IsReady     bool   `field:"isReady"`     // 是否已准备好
 | 
				
			||||||
	Description string `field:"description"` // 描述
 | 
						Description string `field:"description"` // 描述
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type HTTPCacheTaskOperator struct {
 | 
					type HTTPCacheTaskOperator struct {
 | 
				
			||||||
	Id          interface{} // ID
 | 
						Id          any // ID
 | 
				
			||||||
	UserId      interface{} // 用户ID
 | 
						UserId      any // 用户ID
 | 
				
			||||||
	Type        interface{} // 任务类型:purge|fetch
 | 
						Type        any // 任务类型:purge|fetch
 | 
				
			||||||
	KeyType     interface{} // Key类型
 | 
						KeyType     any // Key类型
 | 
				
			||||||
	State       interface{} // 状态
 | 
						State       any // 状态
 | 
				
			||||||
	CreatedAt   interface{} // 创建时间
 | 
						CreatedAt   any // 创建时间
 | 
				
			||||||
	DoneAt      interface{} // 完成时间
 | 
						DoneAt      any // 完成时间
 | 
				
			||||||
	Day         interface{} // 创建日期YYYYMMDD
 | 
						Day         any // 创建日期YYYYMMDD
 | 
				
			||||||
	IsDone      interface{} // 是否已完成
 | 
						IsDone      any // 是否已完成
 | 
				
			||||||
	IsOk        interface{} // 是否完全成功
 | 
						IsOk        any // 是否完全成功
 | 
				
			||||||
	IsReady     interface{} // 是否已准备好
 | 
						IsReady     any // 是否已准备好
 | 
				
			||||||
	Description interface{} // 描述
 | 
						Description any // 描述
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewHTTPCacheTaskOperator() *HTTPCacheTaskOperator {
 | 
					func NewHTTPCacheTaskOperator() *HTTPCacheTaskOperator {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,7 @@ func init() {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 启用条目
 | 
					// EnableIPLibrary 启用条目
 | 
				
			||||||
func (this *IPLibraryDAO) EnableIPLibrary(tx *dbs.Tx, id int64) error {
 | 
					func (this *IPLibraryDAO) EnableIPLibrary(tx *dbs.Tx, id int64) error {
 | 
				
			||||||
	_, err := this.Query(tx).
 | 
						_, err := this.Query(tx).
 | 
				
			||||||
		Pk(id).
 | 
							Pk(id).
 | 
				
			||||||
@@ -42,7 +42,7 @@ func (this *IPLibraryDAO) EnableIPLibrary(tx *dbs.Tx, id int64) error {
 | 
				
			|||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 禁用条目
 | 
					// DisableIPLibrary 禁用条目
 | 
				
			||||||
func (this *IPLibraryDAO) DisableIPLibrary(tx *dbs.Tx, id int64) error {
 | 
					func (this *IPLibraryDAO) DisableIPLibrary(tx *dbs.Tx, id int64) error {
 | 
				
			||||||
	_, err := this.Query(tx).
 | 
						_, err := this.Query(tx).
 | 
				
			||||||
		Pk(id).
 | 
							Pk(id).
 | 
				
			||||||
@@ -51,7 +51,7 @@ func (this *IPLibraryDAO) DisableIPLibrary(tx *dbs.Tx, id int64) error {
 | 
				
			|||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 查找启用中的条目
 | 
					// FindEnabledIPLibrary 查找启用中的条目
 | 
				
			||||||
func (this *IPLibraryDAO) FindEnabledIPLibrary(tx *dbs.Tx, id int64) (*IPLibrary, error) {
 | 
					func (this *IPLibraryDAO) FindEnabledIPLibrary(tx *dbs.Tx, id int64) (*IPLibrary, error) {
 | 
				
			||||||
	result, err := this.Query(tx).
 | 
						result, err := this.Query(tx).
 | 
				
			||||||
		Pk(id).
 | 
							Pk(id).
 | 
				
			||||||
@@ -63,7 +63,7 @@ func (this *IPLibraryDAO) FindEnabledIPLibrary(tx *dbs.Tx, id int64) (*IPLibrary
 | 
				
			|||||||
	return result.(*IPLibrary), err
 | 
						return result.(*IPLibrary), err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 查找某个类型的IP库列表
 | 
					// FindAllEnabledIPLibrariesWithType 查找某个类型的IP库列表
 | 
				
			||||||
func (this *IPLibraryDAO) FindAllEnabledIPLibrariesWithType(tx *dbs.Tx, libraryType string) (result []*IPLibrary, err error) {
 | 
					func (this *IPLibraryDAO) FindAllEnabledIPLibrariesWithType(tx *dbs.Tx, libraryType string) (result []*IPLibrary, err error) {
 | 
				
			||||||
	_, err = this.Query(tx).
 | 
						_, err = this.Query(tx).
 | 
				
			||||||
		State(IPLibraryStateEnabled).
 | 
							State(IPLibraryStateEnabled).
 | 
				
			||||||
@@ -74,7 +74,7 @@ func (this *IPLibraryDAO) FindAllEnabledIPLibrariesWithType(tx *dbs.Tx, libraryT
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 查找某个类型的最新的IP库
 | 
					// FindLatestIPLibraryWithType 查找某个类型的最新的IP库
 | 
				
			||||||
func (this *IPLibraryDAO) FindLatestIPLibraryWithType(tx *dbs.Tx, libraryType string) (*IPLibrary, error) {
 | 
					func (this *IPLibraryDAO) FindLatestIPLibraryWithType(tx *dbs.Tx, libraryType string) (*IPLibrary, error) {
 | 
				
			||||||
	one, err := this.Query(tx).
 | 
						one, err := this.Query(tx).
 | 
				
			||||||
		State(IPLibraryStateEnabled).
 | 
							State(IPLibraryStateEnabled).
 | 
				
			||||||
@@ -90,7 +90,7 @@ func (this *IPLibraryDAO) FindLatestIPLibraryWithType(tx *dbs.Tx, libraryType st
 | 
				
			|||||||
	return one.(*IPLibrary), nil
 | 
						return one.(*IPLibrary), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 创建新的IP库
 | 
					// CreateIPLibrary 创建新的IP库
 | 
				
			||||||
func (this *IPLibraryDAO) CreateIPLibrary(tx *dbs.Tx, libraryType string, fileId int64) (int64, error) {
 | 
					func (this *IPLibraryDAO) CreateIPLibrary(tx *dbs.Tx, libraryType string, fileId int64) (int64, error) {
 | 
				
			||||||
	var op = NewIPLibraryOperator()
 | 
						var op = NewIPLibraryOperator()
 | 
				
			||||||
	op.Type = libraryType
 | 
						op.Type = libraryType
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										469
									
								
								internal/db/models/ip_library_file_dao.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										469
									
								
								internal/db/models/ip_library_file_dao.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,469 @@
 | 
				
			|||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/db/models/regions"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
 | 
				
			||||||
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/Tea"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/types"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						IPLibraryFileStateEnabled  = 1 // 已启用
 | 
				
			||||||
 | 
						IPLibraryFileStateDisabled = 0 // 已禁用
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type IPLibraryFileDAO dbs.DAO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewIPLibraryFileDAO() *IPLibraryFileDAO {
 | 
				
			||||||
 | 
						return dbs.NewDAO(&IPLibraryFileDAO{
 | 
				
			||||||
 | 
							DAOObject: dbs.DAOObject{
 | 
				
			||||||
 | 
								DB:     Tea.Env,
 | 
				
			||||||
 | 
								Table:  "edgeIPLibraryFiles",
 | 
				
			||||||
 | 
								Model:  new(IPLibraryFile),
 | 
				
			||||||
 | 
								PkName: "id",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}).(*IPLibraryFileDAO)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var SharedIPLibraryFileDAO *IPLibraryFileDAO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						dbs.OnReady(func() {
 | 
				
			||||||
 | 
							SharedIPLibraryFileDAO = NewIPLibraryFileDAO()
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EnableIPLibraryFile 启用条目
 | 
				
			||||||
 | 
					func (this *IPLibraryFileDAO) EnableIPLibraryFile(tx *dbs.Tx, id uint64) error {
 | 
				
			||||||
 | 
						_, err := this.Query(tx).
 | 
				
			||||||
 | 
							Pk(id).
 | 
				
			||||||
 | 
							Set("state", IPLibraryFileStateEnabled).
 | 
				
			||||||
 | 
							Update()
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DisableIPLibraryFile 禁用条目
 | 
				
			||||||
 | 
					func (this *IPLibraryFileDAO) DisableIPLibraryFile(tx *dbs.Tx, id int64) error {
 | 
				
			||||||
 | 
						_, err := this.Query(tx).
 | 
				
			||||||
 | 
							Pk(id).
 | 
				
			||||||
 | 
							Set("state", IPLibraryFileStateDisabled).
 | 
				
			||||||
 | 
							Update()
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindEnabledIPLibraryFile 查找启用中的条目
 | 
				
			||||||
 | 
					func (this *IPLibraryFileDAO) FindEnabledIPLibraryFile(tx *dbs.Tx, id int64) (*IPLibraryFile, error) {
 | 
				
			||||||
 | 
						result, err := this.Query(tx).
 | 
				
			||||||
 | 
							Pk(id).
 | 
				
			||||||
 | 
							State(IPLibraryFileStateEnabled).
 | 
				
			||||||
 | 
							Find()
 | 
				
			||||||
 | 
						if result == nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return result.(*IPLibraryFile), err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CreateLibraryFile 创建文件
 | 
				
			||||||
 | 
					func (this *IPLibraryFileDAO) CreateLibraryFile(tx *dbs.Tx, template string, emptyValues []string, fileId int64, countries []string, provinces [][2]string, cities [][3]string, towns [][4]string, providers []string) (int64, error) {
 | 
				
			||||||
 | 
						var op = NewIPLibraryFileOperator()
 | 
				
			||||||
 | 
						op.Template = template
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if emptyValues == nil {
 | 
				
			||||||
 | 
							emptyValues = []string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						emptyValuesJSON, err := json.Marshal(emptyValues)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return 0, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						op.EmptyValues = emptyValuesJSON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						op.FileId = fileId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if countries == nil {
 | 
				
			||||||
 | 
							countries = []string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						countriesJSON, err := json.Marshal(countries)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return 0, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						op.Countries = countriesJSON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if provinces == nil {
 | 
				
			||||||
 | 
							provinces = [][2]string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						provincesJSON, err := json.Marshal(provinces)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return 0, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						op.Provinces = provincesJSON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if cities == nil {
 | 
				
			||||||
 | 
							cities = [][3]string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						citiesJSON, err := json.Marshal(cities)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return 0, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						op.Cities = citiesJSON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if towns == nil {
 | 
				
			||||||
 | 
							towns = [][4]string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						townsJSON, err := json.Marshal(towns)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return 0, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						op.Towns = townsJSON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if providers == nil {
 | 
				
			||||||
 | 
							providers = []string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						providersJSON, err := json.Marshal(providers)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return 0, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						op.Providers = providersJSON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						op.IsFinished = false
 | 
				
			||||||
 | 
						op.State = IPLibraryFileStateEnabled
 | 
				
			||||||
 | 
						return this.SaveInt64(tx, op)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindAllUnfinishedLibraryFiles 查找所有未完成的文件
 | 
				
			||||||
 | 
					func (this *IPLibraryFileDAO) FindAllUnfinishedLibraryFiles(tx *dbs.Tx) (result []*IPLibraryFile, err error) {
 | 
				
			||||||
 | 
						_, err = this.Query(tx).
 | 
				
			||||||
 | 
							State(IPLibraryFileStateEnabled).
 | 
				
			||||||
 | 
							Result("id", "fileId", "createdAt"). // 这里不需要其他信息
 | 
				
			||||||
 | 
							Attr("isFinished", false).
 | 
				
			||||||
 | 
							DescPk().
 | 
				
			||||||
 | 
							Slice(&result).
 | 
				
			||||||
 | 
							FindAll()
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UpdateLibraryFileIsFinished 设置文件为已完成
 | 
				
			||||||
 | 
					func (this *IPLibraryFileDAO) UpdateLibraryFileIsFinished(tx *dbs.Tx, fileId int64) error {
 | 
				
			||||||
 | 
						return this.Query(tx).
 | 
				
			||||||
 | 
							Pk(fileId).
 | 
				
			||||||
 | 
							Set("isFinished", true).
 | 
				
			||||||
 | 
							UpdateQuickly()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindLibraryFileCountries 获取IP库中的国家/地区
 | 
				
			||||||
 | 
					func (this *IPLibraryFileDAO) FindLibraryFileCountries(tx *dbs.Tx, fileId int64) ([]string, error) {
 | 
				
			||||||
 | 
						countriesJSON, err := this.Query(tx).
 | 
				
			||||||
 | 
							Result("countries").
 | 
				
			||||||
 | 
							Pk(fileId).
 | 
				
			||||||
 | 
							FindJSONCol()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if IsNull(countriesJSON) {
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result = []string{}
 | 
				
			||||||
 | 
						err = json.Unmarshal(countriesJSON, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindLibraryFileProvinces 获取IP库中的省份
 | 
				
			||||||
 | 
					func (this *IPLibraryFileDAO) FindLibraryFileProvinces(tx *dbs.Tx, fileId int64) ([][2]string, error) {
 | 
				
			||||||
 | 
						provincesJSON, err := this.Query(tx).
 | 
				
			||||||
 | 
							Result("provinces").
 | 
				
			||||||
 | 
							Pk(fileId).
 | 
				
			||||||
 | 
							FindJSONCol()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if IsNull(provincesJSON) {
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result = [][2]string{}
 | 
				
			||||||
 | 
						err = json.Unmarshal(provincesJSON, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindLibraryFileCities 获取IP库中的城市
 | 
				
			||||||
 | 
					func (this *IPLibraryFileDAO) FindLibraryFileCities(tx *dbs.Tx, fileId int64) ([][3]string, error) {
 | 
				
			||||||
 | 
						citiesJSON, err := this.Query(tx).
 | 
				
			||||||
 | 
							Result("cities").
 | 
				
			||||||
 | 
							Pk(fileId).
 | 
				
			||||||
 | 
							FindJSONCol()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if IsNull(citiesJSON) {
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result = [][3]string{}
 | 
				
			||||||
 | 
						err = json.Unmarshal(citiesJSON, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindLibraryFileProviders 获取IP库中的ISP运营商
 | 
				
			||||||
 | 
					func (this *IPLibraryFileDAO) FindLibraryFileProviders(tx *dbs.Tx, fileId int64) ([]string, error) {
 | 
				
			||||||
 | 
						providersJSON, err := this.Query(tx).
 | 
				
			||||||
 | 
							Result("providers").
 | 
				
			||||||
 | 
							Pk(fileId).
 | 
				
			||||||
 | 
							FindJSONCol()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if IsNull(providersJSON) {
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result = []string{}
 | 
				
			||||||
 | 
						err = json.Unmarshal(providersJSON, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64) error {
 | 
				
			||||||
 | 
						one, err := this.Query(tx).Pk(libraryFileId).Find()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if one == nil {
 | 
				
			||||||
 | 
							return errors.New("the library file not found")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var libraryFile = one.(*IPLibraryFile)
 | 
				
			||||||
 | 
						template, err := iplibrary.NewTemplate(libraryFile.Template)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return errors.New("create template from '" + libraryFile.Template + "' failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var fileId = int64(libraryFile.FileId)
 | 
				
			||||||
 | 
						if fileId == 0 {
 | 
				
			||||||
 | 
							return errors.New("the library file has not been uploaded yet")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var dir = Tea.Root + "/data"
 | 
				
			||||||
 | 
						stat, err := os.Stat(dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if os.IsNotExist(err) {
 | 
				
			||||||
 | 
								err = os.Mkdir(dir, 0777)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return errors.New("can not open dir '" + dir + "' to write: " + err.Error())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return errors.New("can not open dir '" + dir + "' to write: " + err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if !stat.IsDir() {
 | 
				
			||||||
 | 
							_ = os.Remove(dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = os.Mkdir(dir, 0777)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return errors.New("can not open dir '" + dir + "' to write: " + err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO 删除以往生成的文件,但要考虑到文件正在被别的任务所使用
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 国家
 | 
				
			||||||
 | 
						var countries = []*iplibrary.Country{}
 | 
				
			||||||
 | 
						// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 省份
 | 
				
			||||||
 | 
						var provinces = []*iplibrary.Province{}
 | 
				
			||||||
 | 
						// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 城市
 | 
				
			||||||
 | 
						var cities = []*iplibrary.City{}
 | 
				
			||||||
 | 
						// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 区县
 | 
				
			||||||
 | 
						var towns = []*iplibrary.Town{}
 | 
				
			||||||
 | 
						// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ISP运营商
 | 
				
			||||||
 | 
						var providers = []*iplibrary.Provider{}
 | 
				
			||||||
 | 
						// TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var libraryCode = utils.Sha1RandomString() // 每次都生成新的code
 | 
				
			||||||
 | 
						var filePath = dir + "/" + this.composeFilename(libraryFileId, libraryCode)
 | 
				
			||||||
 | 
						writer, err := iplibrary.NewFileWriter(filePath, &iplibrary.Meta{
 | 
				
			||||||
 | 
							Author:    "", // 将来用户可以自行填写
 | 
				
			||||||
 | 
							CreatedAt: time.Now().Unix(),
 | 
				
			||||||
 | 
							Countries: countries,
 | 
				
			||||||
 | 
							Provinces: provinces,
 | 
				
			||||||
 | 
							Cities:    cities,
 | 
				
			||||||
 | 
							Towns:     towns,
 | 
				
			||||||
 | 
							Providers: providers,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							_ = writer.Close()
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = writer.WriteMeta()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return errors.New("write meta failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						chunkIds, err := SharedFileChunkDAO.FindAllFileChunkIds(tx, fileId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// countries etc ...
 | 
				
			||||||
 | 
						var countryMap = map[string]int64{} // countryName => countryId
 | 
				
			||||||
 | 
						dbCountries, err := regions.SharedRegionCountryDAO.FindAllCountries(tx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, country := range dbCountries {
 | 
				
			||||||
 | 
							for _, code := range country.AllCodes() {
 | 
				
			||||||
 | 
								countryMap[code] = int64(country.Id)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var provinceMap = map[string]int64{} // countryId_provinceName => provinceId
 | 
				
			||||||
 | 
						dbProvinces, err := regions.SharedRegionProvinceDAO.FindAllEnabledProvinces(tx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, province := range dbProvinces {
 | 
				
			||||||
 | 
							for _, code := range province.AllCodes() {
 | 
				
			||||||
 | 
								provinceMap[types.String(province.CountryId)+"_"+code] = int64(province.Id)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var cityMap = map[string]int64{} // provinceId_cityName => cityId
 | 
				
			||||||
 | 
						dbCities, err := regions.SharedRegionCityDAO.FindAllEnabledCities(tx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, city := range dbCities {
 | 
				
			||||||
 | 
							for _, code := range city.AllCodes() {
 | 
				
			||||||
 | 
								cityMap[types.String(city.ProvinceId)+"_"+code] = int64(city.Id)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var townMap = map[string]int64{} // cityId_townName => townId
 | 
				
			||||||
 | 
						// TODO 将来实现区县
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var providerMap = map[string]int64{} // providerName => providerId
 | 
				
			||||||
 | 
						dbProviders, err := regions.SharedRegionProviderDAO.FindAllEnabledProviders(tx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, provider := range dbProviders {
 | 
				
			||||||
 | 
							for _, code := range provider.AllCodes() {
 | 
				
			||||||
 | 
								providerMap[code] = int64(provider.Id)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dataParser, err := iplibrary.NewParser(&iplibrary.ParserConfig{
 | 
				
			||||||
 | 
							Template:    template,
 | 
				
			||||||
 | 
							EmptyValues: libraryFile.DecodeEmptyValues(),
 | 
				
			||||||
 | 
							Iterator: func(values map[string]string) error {
 | 
				
			||||||
 | 
								var ipFrom = values["ipFrom"]
 | 
				
			||||||
 | 
								var ipTo = values["ipTo"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var countryName = values["country"]
 | 
				
			||||||
 | 
								var provinceName = values["province"]
 | 
				
			||||||
 | 
								var cityName = values["city"]
 | 
				
			||||||
 | 
								var townName = values["town"]
 | 
				
			||||||
 | 
								var providerName = values["provider"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var countryId = countryMap[countryName]
 | 
				
			||||||
 | 
								var provinceId int64
 | 
				
			||||||
 | 
								var cityId int64 = 0
 | 
				
			||||||
 | 
								var townId int64 = 0
 | 
				
			||||||
 | 
								var providerId = providerMap[providerName]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if countryId > 0 {
 | 
				
			||||||
 | 
									provinceId = provinceMap[types.String(countryId)+"_"+provinceName]
 | 
				
			||||||
 | 
									if provinceId > 0 {
 | 
				
			||||||
 | 
										cityId = cityMap[types.String(provinceId)+"_"+cityName]
 | 
				
			||||||
 | 
										if cityId > 0 {
 | 
				
			||||||
 | 
											townId = townMap[types.String(cityId)+"_"+townName]
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								err = writer.Write(ipFrom, ipTo, countryId, provinceId, cityId, townId, providerId)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return errors.New("write failed: " + err.Error())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, chunkId := range chunkIds {
 | 
				
			||||||
 | 
							chunk, err := SharedFileChunkDAO.FindFileChunk(tx, chunkId)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if chunk == nil {
 | 
				
			||||||
 | 
								return errors.New("invalid chunk file, please upload again")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							dataParser.Write(chunk.Data)
 | 
				
			||||||
 | 
							err = dataParser.Parse()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = writer.Close()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 设置code
 | 
				
			||||||
 | 
						err = this.Query(tx).
 | 
				
			||||||
 | 
							Pk(libraryFileId).
 | 
				
			||||||
 | 
							Set("code", libraryCode).
 | 
				
			||||||
 | 
							Set("isFinished", true).
 | 
				
			||||||
 | 
							Set("generatedAt", time.Now().Unix()).
 | 
				
			||||||
 | 
							UpdateQuickly()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 组合IP库文件名
 | 
				
			||||||
 | 
					func (this *IPLibraryFileDAO) composeFilename(libraryFileId int64, code string) string {
 | 
				
			||||||
 | 
						return "ip-library-" + types.String(libraryFileId) + "-" + code + ".db"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								internal/db/models/ip_library_file_dao_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								internal/db/models/ip_library_file_dao_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					package models_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/db/models"
 | 
				
			||||||
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
 | 
						_ "github.com/iwind/TeaGo/bootstrap"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestIPLibraryFileDAO_GenerateIPLibrary(t *testing.T) {
 | 
				
			||||||
 | 
						dbs.NotifyReady()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx *dbs.Tx
 | 
				
			||||||
 | 
						err := models.SharedIPLibraryFileDAO.GenerateIPLibrary(tx, 3)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										44
									
								
								internal/db/models/ip_library_file_model.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								internal/db/models/ip_library_file_model.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IPLibraryFile IP库上传的文件
 | 
				
			||||||
 | 
					type IPLibraryFile struct {
 | 
				
			||||||
 | 
						Id              uint64   `field:"id"`              // ID
 | 
				
			||||||
 | 
						FileId          uint64   `field:"fileId"`          // 原始文件ID
 | 
				
			||||||
 | 
						Template        string   `field:"template"`        // 模板
 | 
				
			||||||
 | 
						EmptyValues     dbs.JSON `field:"emptyValues"`     // 空值列表
 | 
				
			||||||
 | 
						GeneratedFileId uint64   `field:"generatedFileId"` // 生成的文件ID
 | 
				
			||||||
 | 
						GeneratedAt     uint64   `field:"generatedAt"`     // 生成时间
 | 
				
			||||||
 | 
						IsFinished      bool     `field:"isFinished"`      // 是否已经完成
 | 
				
			||||||
 | 
						Countries       dbs.JSON `field:"countries"`       // 国家/地区
 | 
				
			||||||
 | 
						Provinces       dbs.JSON `field:"provinces"`       // 省份
 | 
				
			||||||
 | 
						Cities          dbs.JSON `field:"cities"`          // 城市
 | 
				
			||||||
 | 
						Towns           dbs.JSON `field:"towns"`           // 区县
 | 
				
			||||||
 | 
						Providers       dbs.JSON `field:"providers"`       // ISP服务商
 | 
				
			||||||
 | 
						Code            string   `field:"code"`            // 文件代号
 | 
				
			||||||
 | 
						CreatedAt       uint64   `field:"createdAt"`       // 上传时间
 | 
				
			||||||
 | 
						State           uint8    `field:"state"`           // 状态
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type IPLibraryFileOperator struct {
 | 
				
			||||||
 | 
						Id              any // ID
 | 
				
			||||||
 | 
						FileId          any // 原始文件ID
 | 
				
			||||||
 | 
						Template        any // 模板
 | 
				
			||||||
 | 
						EmptyValues     any // 空值列表
 | 
				
			||||||
 | 
						GeneratedFileId any // 生成的文件ID
 | 
				
			||||||
 | 
						GeneratedAt     any // 生成时间
 | 
				
			||||||
 | 
						IsFinished      any // 是否已经完成
 | 
				
			||||||
 | 
						Countries       any // 国家/地区
 | 
				
			||||||
 | 
						Provinces       any // 省份
 | 
				
			||||||
 | 
						Cities          any // 城市
 | 
				
			||||||
 | 
						Towns           any // 区县
 | 
				
			||||||
 | 
						Providers       any // ISP服务商
 | 
				
			||||||
 | 
						Code            any // 文件代号
 | 
				
			||||||
 | 
						CreatedAt       any // 上传时间
 | 
				
			||||||
 | 
						State           any // 状态
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewIPLibraryFileOperator() *IPLibraryFileOperator {
 | 
				
			||||||
 | 
						return &IPLibraryFileOperator{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										69
									
								
								internal/db/models/ip_library_file_model_ext.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								internal/db/models/ip_library_file_model_ext.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "encoding/json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *IPLibraryFile) DecodeCountries() []string {
 | 
				
			||||||
 | 
						var countries = []string{}
 | 
				
			||||||
 | 
						if IsNotNull(this.Countries) {
 | 
				
			||||||
 | 
							err := json.Unmarshal(this.Countries, &countries)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								// ignore error
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return countries
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *IPLibraryFile) DecodeProvinces() [][2]string {
 | 
				
			||||||
 | 
						var provinces = [][2]string{}
 | 
				
			||||||
 | 
						if IsNotNull(this.Provinces) {
 | 
				
			||||||
 | 
							err := json.Unmarshal(this.Provinces, &provinces)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								// ignore error
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return provinces
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *IPLibraryFile) DecodeCities() [][3]string {
 | 
				
			||||||
 | 
						var cities = [][3]string{}
 | 
				
			||||||
 | 
						if IsNotNull(this.Cities) {
 | 
				
			||||||
 | 
							err := json.Unmarshal(this.Cities, &cities)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								// ignore error
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return cities
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *IPLibraryFile) DecodeTowns() [][4]string {
 | 
				
			||||||
 | 
						var towns = [][4]string{}
 | 
				
			||||||
 | 
						if IsNotNull(this.Towns) {
 | 
				
			||||||
 | 
							err := json.Unmarshal(this.Towns, &towns)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								// ignore error
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return towns
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *IPLibraryFile) DecodeProviders() []string {
 | 
				
			||||||
 | 
						var providers = []string{}
 | 
				
			||||||
 | 
						if IsNotNull(this.Providers) {
 | 
				
			||||||
 | 
							err := json.Unmarshal(this.Providers, &providers)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								// ignore error
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return providers
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *IPLibraryFile) DecodeEmptyValues() []string {
 | 
				
			||||||
 | 
						var result = []string{}
 | 
				
			||||||
 | 
						if IsNotNull(this.EmptyValues) {
 | 
				
			||||||
 | 
							err := json.Unmarshal(this.EmptyValues, &result)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								// ignore error
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,22 +1,26 @@
 | 
				
			|||||||
package models
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IP库
 | 
					// IPLibrary IP库
 | 
				
			||||||
type IPLibrary struct {
 | 
					type IPLibrary struct {
 | 
				
			||||||
	Id        uint32 `field:"id"`        // ID
 | 
						Id        uint32 `field:"id"`        // ID
 | 
				
			||||||
	AdminId   uint32 `field:"adminId"`   // 管理员ID
 | 
						AdminId   uint32 `field:"adminId"`   // 管理员ID
 | 
				
			||||||
	FileId    uint32 `field:"fileId"`    // 文件ID
 | 
						FileId    uint32 `field:"fileId"`    // 文件ID
 | 
				
			||||||
	Type      string `field:"type"`      // 类型
 | 
						Type      string `field:"type"`      // 类型
 | 
				
			||||||
 | 
						Name      string `field:"name"`      // 名称
 | 
				
			||||||
 | 
						IsPublic  bool   `field:"isPublic"`  // 是否公用
 | 
				
			||||||
	State     uint8  `field:"state"`     // 状态
 | 
						State     uint8  `field:"state"`     // 状态
 | 
				
			||||||
	CreatedAt uint64 `field:"createdAt"` // 创建时间
 | 
						CreatedAt uint64 `field:"createdAt"` // 创建时间
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type IPLibraryOperator struct {
 | 
					type IPLibraryOperator struct {
 | 
				
			||||||
	Id        interface{} // ID
 | 
						Id        any // ID
 | 
				
			||||||
	AdminId   interface{} // 管理员ID
 | 
						AdminId   any // 管理员ID
 | 
				
			||||||
	FileId    interface{} // 文件ID
 | 
						FileId    any // 文件ID
 | 
				
			||||||
	Type      interface{} // 类型
 | 
						Type      any // 类型
 | 
				
			||||||
	State     interface{} // 状态
 | 
						Name      any // 名称
 | 
				
			||||||
	CreatedAt interface{} // 创建时间
 | 
						IsPublic  any // 是否公用
 | 
				
			||||||
 | 
						State     any // 状态
 | 
				
			||||||
 | 
						CreatedAt any // 创建时间
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewIPLibraryOperator() *IPLibraryOperator {
 | 
					func NewIPLibraryOperator() *IPLibraryOperator {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,14 @@ package regions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
 | 
				
			||||||
	_ "github.com/go-sql-driver/mysql"
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
	"github.com/iwind/TeaGo/Tea"
 | 
						"github.com/iwind/TeaGo/Tea"
 | 
				
			||||||
	"github.com/iwind/TeaGo/dbs"
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
	"github.com/iwind/TeaGo/types"
 | 
						"github.com/iwind/TeaGo/types"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -105,7 +108,18 @@ func (this *RegionCityDAO) CreateCity(tx *dbs.Tx, provinceId int64, name string,
 | 
				
			|||||||
	return types.Int64(op.Id), nil
 | 
						return types.Int64(op.Id), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindCityIdWithNameCacheable 根据城市名查找城市ID
 | 
					// FindCityIdWithName 根据城市名查找城市ID
 | 
				
			||||||
 | 
					func (this *RegionCityDAO) FindCityIdWithName(tx *dbs.Tx, provinceId int64, cityName string) (int64, error) {
 | 
				
			||||||
 | 
						return this.Query(tx).
 | 
				
			||||||
 | 
							Attr("provinceId", provinceId).
 | 
				
			||||||
 | 
							Where("(name=:cityName OR customName=:cityName OR JSON_CONTAINS(codes, :cityNameJSON) OR JSON_CONTAINS(customCodes, :cityNameJSON))").
 | 
				
			||||||
 | 
							Param("cityName", cityName).
 | 
				
			||||||
 | 
							Param("cityNameJSON", strconv.Quote(cityName)). // 查询的需要是个JSON字符串,所以这里加双引号
 | 
				
			||||||
 | 
							ResultPk().
 | 
				
			||||||
 | 
							FindInt64Col(0)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindCityIdWithNameCacheable 根据城市名查找城市ID,并加入缓存
 | 
				
			||||||
func (this *RegionCityDAO) FindCityIdWithNameCacheable(tx *dbs.Tx, provinceId int64, cityName string) (int64, error) {
 | 
					func (this *RegionCityDAO) FindCityIdWithNameCacheable(tx *dbs.Tx, provinceId int64, cityName string) (int64, error) {
 | 
				
			||||||
	key := cityName + "@" + numberutils.FormatInt64(provinceId)
 | 
						key := cityName + "@" + numberutils.FormatInt64(provinceId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -119,16 +133,19 @@ func (this *RegionCityDAO) FindCityIdWithNameCacheable(tx *dbs.Tx, provinceId in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	cityId, err := this.Query(tx).
 | 
						cityId, err := this.Query(tx).
 | 
				
			||||||
		Attr("provinceId", provinceId).
 | 
							Attr("provinceId", provinceId).
 | 
				
			||||||
		Where("JSON_CONTAINS(codes, :cityName)").
 | 
							Where("(name=:cityName OR customName=:cityName OR JSON_CONTAINS(codes, :cityNameJSON) OR JSON_CONTAINS(customCodes, :cityNameJSON))").
 | 
				
			||||||
		Param("cityName", strconv.Quote(cityName)). // 查询的需要是个JSON字符串,所以这里加双引号
 | 
							Param("cityName", cityName).
 | 
				
			||||||
 | 
							Param("cityNameJSON", strconv.Quote(cityName)). // 查询的需要是个JSON字符串,所以这里加双引号
 | 
				
			||||||
		ResultPk().
 | 
							ResultPk().
 | 
				
			||||||
		FindInt64Col(0)
 | 
							FindInt64Col(0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return 0, err
 | 
							return 0, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if cityId > 0 {
 | 
				
			||||||
		SharedCacheLocker.Lock()
 | 
							SharedCacheLocker.Lock()
 | 
				
			||||||
		regionCityNameAndIdCacheMap[key] = cityId
 | 
							regionCityNameAndIdCacheMap[key] = cityId
 | 
				
			||||||
		SharedCacheLocker.Unlock()
 | 
							SharedCacheLocker.Unlock()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cityId, nil
 | 
						return cityId, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -141,3 +158,75 @@ func (this *RegionCityDAO) FindAllEnabledCities(tx *dbs.Tx) (result []*RegionCit
 | 
				
			|||||||
		FindAll()
 | 
							FindAll()
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindAllEnabledCitiesWithProvinceId 获取某个省份下的所有城市
 | 
				
			||||||
 | 
					func (this *RegionCityDAO) FindAllEnabledCitiesWithProvinceId(tx *dbs.Tx, provinceId int64) (result []*RegionCity, err error) {
 | 
				
			||||||
 | 
						_, err = this.Query(tx).
 | 
				
			||||||
 | 
							Attr("provinceId", provinceId).
 | 
				
			||||||
 | 
							State(RegionCityStateEnabled).
 | 
				
			||||||
 | 
							Slice(&result).
 | 
				
			||||||
 | 
							FindAll()
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UpdateCityCustom 自定义城市信息
 | 
				
			||||||
 | 
					func (this *RegionCityDAO) UpdateCityCustom(tx *dbs.Tx, cityId int64, customName string, customCodes []string) error {
 | 
				
			||||||
 | 
						if customCodes == nil {
 | 
				
			||||||
 | 
							customCodes = []string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						customCodesJSON, err := json.Marshal(customCodes)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							SharedCacheLocker.Lock()
 | 
				
			||||||
 | 
							regionCityNameAndIdCacheMap = map[string]int64{}
 | 
				
			||||||
 | 
							SharedCacheLocker.Unlock()
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return this.Query(tx).
 | 
				
			||||||
 | 
							Pk(cityId).
 | 
				
			||||||
 | 
							Set("customName", customName).
 | 
				
			||||||
 | 
							Set("customCodes", customCodesJSON).
 | 
				
			||||||
 | 
							UpdateQuickly()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindSimilarCities 查找类似城市名
 | 
				
			||||||
 | 
					func (this *RegionCityDAO) FindSimilarCities(cities []*RegionCity, cityName string, size int) (result []*RegionCity) {
 | 
				
			||||||
 | 
						if len(cities) == 0 {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var similarResult = []maps.Map{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, city := range cities {
 | 
				
			||||||
 | 
							var similarityList = []float32{}
 | 
				
			||||||
 | 
							for _, code := range city.AllCodes() {
 | 
				
			||||||
 | 
								var similarity = utils.Similar(cityName, code)
 | 
				
			||||||
 | 
								if similarity > 0 {
 | 
				
			||||||
 | 
									similarityList = append(similarityList, similarity)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(similarityList) > 0 {
 | 
				
			||||||
 | 
								similarResult = append(similarResult, maps.Map{
 | 
				
			||||||
 | 
									"similarity": numberutils.Max(similarityList...),
 | 
				
			||||||
 | 
									"city":       city,
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sort.Slice(similarResult, func(i, j int) bool {
 | 
				
			||||||
 | 
							return similarResult[i].GetFloat32("similarity") > similarResult[j].GetFloat32("similarity")
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(similarResult) > size {
 | 
				
			||||||
 | 
							similarResult = similarResult[:size]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, r := range similarResult {
 | 
				
			||||||
 | 
							result = append(result, r.Get("city").(*RegionCity))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,12 +2,14 @@ package regions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import "github.com/iwind/TeaGo/dbs"
 | 
					import "github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RegionCity 区域城市
 | 
					// RegionCity 区域-城市
 | 
				
			||||||
type RegionCity struct {
 | 
					type RegionCity struct {
 | 
				
			||||||
	Id          uint32   `field:"id"`          // ID
 | 
						Id          uint32   `field:"id"`          // ID
 | 
				
			||||||
	ProvinceId  uint32   `field:"provinceId"`  // 省份ID
 | 
						ProvinceId  uint32   `field:"provinceId"`  // 省份ID
 | 
				
			||||||
	Name        string   `field:"name"`        // 名称
 | 
						Name        string   `field:"name"`        // 名称
 | 
				
			||||||
	Codes       dbs.JSON `field:"codes"`       // 代号
 | 
						Codes       dbs.JSON `field:"codes"`       // 代号
 | 
				
			||||||
 | 
						CustomName  string   `field:"customName"`  // 自定义名称
 | 
				
			||||||
 | 
						CustomCodes dbs.JSON `field:"customCodes"` // 自定义代号
 | 
				
			||||||
	State       uint8    `field:"state"`       // 状态
 | 
						State       uint8    `field:"state"`       // 状态
 | 
				
			||||||
	DataId      string   `field:"dataId"`      // 原始数据ID
 | 
						DataId      string   `field:"dataId"`      // 原始数据ID
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -17,6 +19,8 @@ type RegionCityOperator struct {
 | 
				
			|||||||
	ProvinceId  interface{} // 省份ID
 | 
						ProvinceId  interface{} // 省份ID
 | 
				
			||||||
	Name        interface{} // 名称
 | 
						Name        interface{} // 名称
 | 
				
			||||||
	Codes       interface{} // 代号
 | 
						Codes       interface{} // 代号
 | 
				
			||||||
 | 
						CustomName  interface{} // 自定义名称
 | 
				
			||||||
 | 
						CustomCodes interface{} // 自定义代号
 | 
				
			||||||
	State       interface{} // 状态
 | 
						State       interface{} // 状态
 | 
				
			||||||
	DataId      interface{} // 原始数据ID
 | 
						DataId      interface{} // 原始数据ID
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,17 +2,56 @@ package regions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"github.com/iwind/TeaGo/logs"
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/lists"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *RegionCity) DecodeCodes() []string {
 | 
					func (this *RegionCity) DecodeCodes() []string {
 | 
				
			||||||
	if len(this.Codes) == 0 {
 | 
						if len(this.Codes) == 0 {
 | 
				
			||||||
		return []string{}
 | 
							return []string{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	result := []string{}
 | 
						var result = []string{}
 | 
				
			||||||
	err := json.Unmarshal(this.Codes, &result)
 | 
						err := json.Unmarshal(this.Codes, &result)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		logs.Error(err)
 | 
							remotelogs.Error("RegionCity.DecodeCodes", err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return result
 | 
						return result
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionCity) DecodeCustomCodes() []string {
 | 
				
			||||||
 | 
						if len(this.CustomCodes) == 0 {
 | 
				
			||||||
 | 
							return []string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var result = []string{}
 | 
				
			||||||
 | 
						err := json.Unmarshal(this.CustomCodes, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							remotelogs.Error("RegionCity.DecodeCustomCodes", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionCity) DisplayName() string {
 | 
				
			||||||
 | 
						if len(this.CustomName) > 0 {
 | 
				
			||||||
 | 
							return this.CustomName
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return this.Name
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionCity) AllCodes() []string {
 | 
				
			||||||
 | 
						var codes = this.DecodeCodes()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(this.Name) > 0 && !lists.ContainsString(codes, this.Name) {
 | 
				
			||||||
 | 
							codes = append(codes, this.Name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(this.CustomName) > 0 && !lists.ContainsString(codes, this.CustomName) {
 | 
				
			||||||
 | 
							codes = append(codes, this.CustomName)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, code := range this.DecodeCustomCodes() {
 | 
				
			||||||
 | 
							if !lists.ContainsString(codes, code) {
 | 
				
			||||||
 | 
								codes = append(codes, code)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return codes
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,15 @@ package regions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
 | 
				
			||||||
	_ "github.com/go-sql-driver/mysql"
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
	"github.com/iwind/TeaGo/Tea"
 | 
						"github.com/iwind/TeaGo/Tea"
 | 
				
			||||||
	"github.com/iwind/TeaGo/dbs"
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
	"github.com/iwind/TeaGo/types"
 | 
						"github.com/iwind/TeaGo/types"
 | 
				
			||||||
	"github.com/mozillazg/go-pinyin"
 | 
						"github.com/mozillazg/go-pinyin"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -16,6 +20,10 @@ const (
 | 
				
			|||||||
	RegionCountryStateDisabled = 0 // 已禁用
 | 
						RegionCountryStateDisabled = 0 // 已禁用
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						CountryChinaId = 1
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var regionCountryNameAndIdCacheMap = map[string]int64{} // country name => id
 | 
					var regionCountryNameAndIdCacheMap = map[string]int64{} // country name => id
 | 
				
			||||||
var regionCountryIdAndNameCacheMap = map[int64]string{} // country id => name
 | 
					var regionCountryIdAndNameCacheMap = map[int64]string{} // country id => name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -88,7 +96,9 @@ func (this *RegionCountryDAO) FindRegionCountryName(tx *dbs.Tx, id int64) (strin
 | 
				
			|||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(name) > 0 {
 | 
				
			||||||
		regionCountryIdAndNameCacheMap[id] = name
 | 
							regionCountryIdAndNameCacheMap[id] = name
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return name, nil
 | 
						return name, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -103,8 +113,9 @@ func (this *RegionCountryDAO) FindCountryIdWithDataId(tx *dbs.Tx, dataId string)
 | 
				
			|||||||
// FindCountryIdWithName 根据国家名查找国家ID
 | 
					// FindCountryIdWithName 根据国家名查找国家ID
 | 
				
			||||||
func (this *RegionCountryDAO) FindCountryIdWithName(tx *dbs.Tx, countryName string) (int64, error) {
 | 
					func (this *RegionCountryDAO) FindCountryIdWithName(tx *dbs.Tx, countryName string) (int64, error) {
 | 
				
			||||||
	return this.Query(tx).
 | 
						return this.Query(tx).
 | 
				
			||||||
		Where("JSON_CONTAINS(codes, :countryName)").
 | 
							Where("(name=:countryName OR JSON_CONTAINS(codes, :countryNameJSON) OR customName=:countryName OR JSON_CONTAINS(customCodes, :countryNameJSON))").
 | 
				
			||||||
		Param("countryName", strconv.Quote(countryName)). // 查询的需要是个JSON字符串,所以这里加双引号
 | 
							Param("countryName", countryName).
 | 
				
			||||||
 | 
							Param("countryNameJSON", strconv.Quote(countryName)). // 查询的需要是个JSON字符串,所以这里加双引号
 | 
				
			||||||
		ResultPk().
 | 
							ResultPk().
 | 
				
			||||||
		FindInt64Col(0)
 | 
							FindInt64Col(0)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -124,9 +135,11 @@ func (this *RegionCountryDAO) FindCountryIdWithNameCacheable(tx *dbs.Tx, country
 | 
				
			|||||||
		return 0, err
 | 
							return 0, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if countryId > 0 {
 | 
				
			||||||
		SharedCacheLocker.Lock()
 | 
							SharedCacheLocker.Lock()
 | 
				
			||||||
		regionCountryNameAndIdCacheMap[countryName] = countryId
 | 
							regionCountryNameAndIdCacheMap[countryName] = countryId
 | 
				
			||||||
		SharedCacheLocker.Unlock()
 | 
							SharedCacheLocker.Unlock()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return countryId, nil
 | 
						return countryId, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -160,7 +173,7 @@ func (this *RegionCountryDAO) CreateCountry(tx *dbs.Tx, name string, dataId stri
 | 
				
			|||||||
	return types.Int64(op.Id), nil
 | 
						return types.Int64(op.Id), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindAllEnabledCountriesOrderByPinyin 查找所有可用的国家
 | 
					// FindAllEnabledCountriesOrderByPinyin 查找所有可用的国家并按拼音排序
 | 
				
			||||||
func (this *RegionCountryDAO) FindAllEnabledCountriesOrderByPinyin(tx *dbs.Tx) (result []*RegionCountry, err error) {
 | 
					func (this *RegionCountryDAO) FindAllEnabledCountriesOrderByPinyin(tx *dbs.Tx) (result []*RegionCountry, err error) {
 | 
				
			||||||
	_, err = this.Query(tx).
 | 
						_, err = this.Query(tx).
 | 
				
			||||||
		State(RegionCountryStateEnabled).
 | 
							State(RegionCountryStateEnabled).
 | 
				
			||||||
@@ -169,3 +182,76 @@ func (this *RegionCountryDAO) FindAllEnabledCountriesOrderByPinyin(tx *dbs.Tx) (
 | 
				
			|||||||
		FindAll()
 | 
							FindAll()
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindAllCountries 查找所有可用的国家
 | 
				
			||||||
 | 
					func (this *RegionCountryDAO) FindAllCountries(tx *dbs.Tx) (result []*RegionCountry, err error) {
 | 
				
			||||||
 | 
						_, err = this.Query(tx).
 | 
				
			||||||
 | 
							State(RegionCountryStateEnabled).
 | 
				
			||||||
 | 
							Slice(&result).
 | 
				
			||||||
 | 
							AscPk().
 | 
				
			||||||
 | 
							FindAll()
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UpdateCountryCustom 修改国家/地区自定义
 | 
				
			||||||
 | 
					func (this *RegionCountryDAO) UpdateCountryCustom(tx *dbs.Tx, countryId int64, customName string, customCodes []string) error {
 | 
				
			||||||
 | 
						if customCodes == nil {
 | 
				
			||||||
 | 
							customCodes = []string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						customCodesJSON, err := json.Marshal(customCodes)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							SharedCacheLocker.Lock()
 | 
				
			||||||
 | 
							regionCountryNameAndIdCacheMap = map[string]int64{}
 | 
				
			||||||
 | 
							regionCountryIdAndNameCacheMap = map[int64]string{}
 | 
				
			||||||
 | 
							SharedCacheLocker.Unlock()
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return this.Query(tx).
 | 
				
			||||||
 | 
							Pk(countryId).
 | 
				
			||||||
 | 
							Set("customName", customName).
 | 
				
			||||||
 | 
							Set("customCodes", customCodesJSON).
 | 
				
			||||||
 | 
							UpdateQuickly()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindSimilarCountries 查找类似国家/地区名
 | 
				
			||||||
 | 
					func (this *RegionCountryDAO) FindSimilarCountries(countries []*RegionCountry, countryName string, size int) (result []*RegionCountry) {
 | 
				
			||||||
 | 
						if len(countries) == 0 {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var similarResult = []maps.Map{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, country := range countries {
 | 
				
			||||||
 | 
							var similarityList = []float32{}
 | 
				
			||||||
 | 
							for _, code := range country.AllCodes() {
 | 
				
			||||||
 | 
								var similarity = utils.Similar(countryName, code)
 | 
				
			||||||
 | 
								if similarity > 0 {
 | 
				
			||||||
 | 
									similarityList = append(similarityList, similarity)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(similarityList) > 0 {
 | 
				
			||||||
 | 
								similarResult = append(similarResult, maps.Map{
 | 
				
			||||||
 | 
									"similarity": numberutils.Max(similarityList...),
 | 
				
			||||||
 | 
									"country":    country,
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sort.Slice(similarResult, func(i, j int) bool {
 | 
				
			||||||
 | 
							return similarResult[i].GetFloat32("similarity") > similarResult[j].GetFloat32("similarity")
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(similarResult) > size {
 | 
				
			||||||
 | 
							similarResult = similarResult[:size]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, r := range similarResult {
 | 
				
			||||||
 | 
							result = append(result, r.Get("country").(*RegionCountry))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,11 +8,29 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestRegionCountryDAO_FindCountryIdWithName(t *testing.T) {
 | 
				
			||||||
 | 
						dbs.NotifyReady()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, name := range []string{
 | 
				
			||||||
 | 
							"中国",
 | 
				
			||||||
 | 
							"中华人民共和国",
 | 
				
			||||||
 | 
							"美国",
 | 
				
			||||||
 | 
							"美利坚合众国",
 | 
				
			||||||
 | 
							"美利坚",
 | 
				
			||||||
 | 
						} {
 | 
				
			||||||
 | 
							countryId, err := SharedRegionCountryDAO.FindCountryIdWithName(nil, name)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.Fatal(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							t.Log(name, ":", countryId)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestRegionCountryDAO_FindCountryIdWithCountryNameCacheable(t *testing.T) {
 | 
					func TestRegionCountryDAO_FindCountryIdWithCountryNameCacheable(t *testing.T) {
 | 
				
			||||||
	dbs.NotifyReady()
 | 
						dbs.NotifyReady()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i := 0; i < 5; i++ {
 | 
						for i := 0; i < 5; i++ {
 | 
				
			||||||
		now := time.Now()
 | 
							var now = time.Now()
 | 
				
			||||||
		countryId, err := SharedRegionCountryDAO.FindCountryIdWithNameCacheable(nil, "中国")
 | 
							countryId, err := SharedRegionCountryDAO.FindCountryIdWithNameCacheable(nil, "中国")
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Fatal(err)
 | 
								t.Fatal(err)
 | 
				
			||||||
@@ -20,3 +38,24 @@ func TestRegionCountryDAO_FindCountryIdWithCountryNameCacheable(t *testing.T) {
 | 
				
			|||||||
		t.Log("countryId", countryId, time.Since(now).Seconds()*1000, "ms")
 | 
							t.Log("countryId", countryId, time.Since(now).Seconds()*1000, "ms")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestRegionCountryDAO_FindSimilarCountries(t *testing.T) {
 | 
				
			||||||
 | 
						dbs.NotifyReady()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx *dbs.Tx
 | 
				
			||||||
 | 
						countries, err := SharedRegionCountryDAO.FindAllCountries(tx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, countryName := range []string{"中国", "布基纳法索", "哥伦比亚", "德意志共和国", "美利坚", "刚果金"} {
 | 
				
			||||||
 | 
							t.Log("====" + countryName + "====")
 | 
				
			||||||
 | 
							var countries = SharedRegionCountryDAO.FindSimilarCountries(countries, countryName, 5)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.Fatal(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, country := range countries {
 | 
				
			||||||
 | 
								t.Log(country.Name, country.AllCodes())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,13 @@ package regions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import "github.com/iwind/TeaGo/dbs"
 | 
					import "github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RegionCountry 区域国家|地区
 | 
					// RegionCountry 区域-国家/地区
 | 
				
			||||||
type RegionCountry struct {
 | 
					type RegionCountry struct {
 | 
				
			||||||
	Id          uint32   `field:"id"`          // ID
 | 
						Id          uint32   `field:"id"`          // ID
 | 
				
			||||||
	Name        string   `field:"name"`        // 名称
 | 
						Name        string   `field:"name"`        // 名称
 | 
				
			||||||
	Codes       dbs.JSON `field:"codes"`       // 代号
 | 
						Codes       dbs.JSON `field:"codes"`       // 代号
 | 
				
			||||||
 | 
						CustomName  string   `field:"customName"`  // 自定义名称
 | 
				
			||||||
 | 
						CustomCodes dbs.JSON `field:"customCodes"` // 自定义代号
 | 
				
			||||||
	State       uint8    `field:"state"`       // 状态
 | 
						State       uint8    `field:"state"`       // 状态
 | 
				
			||||||
	DataId      string   `field:"dataId"`      // 原始数据ID
 | 
						DataId      string   `field:"dataId"`      // 原始数据ID
 | 
				
			||||||
	Pinyin      dbs.JSON `field:"pinyin"`      // 拼音
 | 
						Pinyin      dbs.JSON `field:"pinyin"`      // 拼音
 | 
				
			||||||
@@ -16,6 +18,8 @@ type RegionCountryOperator struct {
 | 
				
			|||||||
	Id          interface{} // ID
 | 
						Id          interface{} // ID
 | 
				
			||||||
	Name        interface{} // 名称
 | 
						Name        interface{} // 名称
 | 
				
			||||||
	Codes       interface{} // 代号
 | 
						Codes       interface{} // 代号
 | 
				
			||||||
 | 
						CustomName  interface{} // 自定义名称
 | 
				
			||||||
 | 
						CustomCodes interface{} // 自定义代号
 | 
				
			||||||
	State       interface{} // 状态
 | 
						State       interface{} // 状态
 | 
				
			||||||
	DataId      interface{} // 原始数据ID
 | 
						DataId      interface{} // 原始数据ID
 | 
				
			||||||
	Pinyin      interface{} // 拼音
 | 
						Pinyin      interface{} // 拼音
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,17 +2,56 @@ package regions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"github.com/iwind/TeaGo/logs"
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/lists"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *RegionCountry) DecodeCodes() []string {
 | 
					func (this *RegionCountry) DecodeCodes() []string {
 | 
				
			||||||
	if len(this.Codes) == 0 {
 | 
						if len(this.Codes) == 0 {
 | 
				
			||||||
		return []string{}
 | 
							return []string{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	result := []string{}
 | 
						var result = []string{}
 | 
				
			||||||
	err := json.Unmarshal(this.Codes, &result)
 | 
						err := json.Unmarshal(this.Codes, &result)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		logs.Error(err)
 | 
							remotelogs.Error("RegionCountry.DecodeCodes", err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return result
 | 
						return result
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionCountry) DecodeCustomCodes() []string {
 | 
				
			||||||
 | 
						if len(this.CustomCodes) == 0 {
 | 
				
			||||||
 | 
							return []string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var result = []string{}
 | 
				
			||||||
 | 
						err := json.Unmarshal(this.CustomCodes, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							remotelogs.Error("RegionCountry.DecodeCustomCodes", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionCountry) DisplayName() string {
 | 
				
			||||||
 | 
						if len(this.CustomName) > 0 {
 | 
				
			||||||
 | 
							return this.CustomName
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return this.Name
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionCountry) AllCodes() []string {
 | 
				
			||||||
 | 
						var codes = this.DecodeCodes()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(this.Name) > 0 && !lists.ContainsString(codes, this.Name) {
 | 
				
			||||||
 | 
							codes = append(codes, this.Name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(this.CustomName) > 0 && !lists.ContainsString(codes, this.CustomName) {
 | 
				
			||||||
 | 
							codes = append(codes, this.CustomName)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, code := range this.DecodeCustomCodes() {
 | 
				
			||||||
 | 
							if !lists.ContainsString(codes, code) {
 | 
				
			||||||
 | 
								codes = append(codes, code)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return codes
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,9 +2,13 @@ package regions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
 | 
				
			||||||
	_ "github.com/go-sql-driver/mysql"
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
	"github.com/iwind/TeaGo/Tea"
 | 
						"github.com/iwind/TeaGo/Tea"
 | 
				
			||||||
	"github.com/iwind/TeaGo/dbs"
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -74,7 +78,17 @@ func (this *RegionProviderDAO) FindRegionProviderName(tx *dbs.Tx, id uint32) (st
 | 
				
			|||||||
		FindStringCol("")
 | 
							FindStringCol("")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindProviderIdWithNameCacheable 根据服务商名称查找服务商ID
 | 
					// FindProviderIdWithName 根据服务商名称查找服务商ID
 | 
				
			||||||
 | 
					func (this *RegionProviderDAO) FindProviderIdWithName(tx *dbs.Tx, providerName string) (int64, error) {
 | 
				
			||||||
 | 
						return this.Query(tx).
 | 
				
			||||||
 | 
							Where("(name=:providerName OR customName=:providerName OR JSON_CONTAINS(codes, :providerNameJSON) OR JSON_CONTAINS(customCodes, :providerNameJSON))").
 | 
				
			||||||
 | 
							Param("providerName", providerName).
 | 
				
			||||||
 | 
							Param("providerNameJSON", strconv.Quote(providerName)). // 查询的需要是个JSON字符串,所以这里加双引号
 | 
				
			||||||
 | 
							ResultPk().
 | 
				
			||||||
 | 
							FindInt64Col(0)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindProviderIdWithNameCacheable 根据服务商名称查找服务商ID,并保存进缓存
 | 
				
			||||||
func (this *RegionProviderDAO) FindProviderIdWithNameCacheable(tx *dbs.Tx, providerName string) (int64, error) {
 | 
					func (this *RegionProviderDAO) FindProviderIdWithNameCacheable(tx *dbs.Tx, providerName string) (int64, error) {
 | 
				
			||||||
	SharedCacheLocker.RLock()
 | 
						SharedCacheLocker.RLock()
 | 
				
			||||||
	providerId, ok := regionProviderNameAndIdCacheMap[providerName]
 | 
						providerId, ok := regionProviderNameAndIdCacheMap[providerName]
 | 
				
			||||||
@@ -85,17 +99,20 @@ func (this *RegionProviderDAO) FindProviderIdWithNameCacheable(tx *dbs.Tx, provi
 | 
				
			|||||||
	SharedCacheLocker.RUnlock()
 | 
						SharedCacheLocker.RUnlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	providerId, err := this.Query(tx).
 | 
						providerId, err := this.Query(tx).
 | 
				
			||||||
		Where("JSON_CONTAINS(codes, :providerName)").
 | 
							Where("(name=:providerName OR customName=:providerName OR JSON_CONTAINS(codes, :providerNameJSON) OR JSON_CONTAINS(customCodes, :providerNameJSON))").
 | 
				
			||||||
		Param("providerName", strconv.Quote(providerName)). // 查询的需要是个JSON字符串,所以这里加双引号
 | 
							Param("providerName", providerName).
 | 
				
			||||||
 | 
							Param("providerNameJSON", strconv.Quote(providerName)). // 查询的需要是个JSON字符串,所以这里加双引号
 | 
				
			||||||
		ResultPk().
 | 
							ResultPk().
 | 
				
			||||||
		FindInt64Col(0)
 | 
							FindInt64Col(0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return 0, err
 | 
							return 0, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if providerId > 0 {
 | 
				
			||||||
		SharedCacheLocker.Lock()
 | 
							SharedCacheLocker.Lock()
 | 
				
			||||||
		regionProviderNameAndIdCacheMap[providerName] = providerId
 | 
							regionProviderNameAndIdCacheMap[providerName] = providerId
 | 
				
			||||||
		SharedCacheLocker.Unlock()
 | 
							SharedCacheLocker.Unlock()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return providerId, nil
 | 
						return providerId, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -121,3 +138,65 @@ func (this *RegionProviderDAO) FindAllEnabledProviders(tx *dbs.Tx) (result []*Re
 | 
				
			|||||||
		FindAll()
 | 
							FindAll()
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UpdateProviderCustom 修改ISP自定义信息
 | 
				
			||||||
 | 
					func (this *RegionProviderDAO) UpdateProviderCustom(tx *dbs.Tx, providerId int64, customName string, customCodes []string) error {
 | 
				
			||||||
 | 
						if customCodes == nil {
 | 
				
			||||||
 | 
							customCodes = []string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						customCodesJSON, err := json.Marshal(customCodes)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							SharedCacheLocker.Lock()
 | 
				
			||||||
 | 
							regionProviderNameAndIdCacheMap = map[string]int64{}
 | 
				
			||||||
 | 
							SharedCacheLocker.Unlock()
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return this.Query(tx).
 | 
				
			||||||
 | 
							Pk(providerId).
 | 
				
			||||||
 | 
							Set("customName", customName).
 | 
				
			||||||
 | 
							Set("customCodes", customCodesJSON).
 | 
				
			||||||
 | 
							UpdateQuickly()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindSimilarProviders 查找类似ISP运营商
 | 
				
			||||||
 | 
					func (this *RegionProviderDAO) FindSimilarProviders(providers []*RegionProvider, providerName string, size int) (result []*RegionProvider) {
 | 
				
			||||||
 | 
						if len(providers) == 0 {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var similarResult = []maps.Map{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, provider := range providers {
 | 
				
			||||||
 | 
							var similarityList = []float32{}
 | 
				
			||||||
 | 
							for _, code := range provider.AllCodes() {
 | 
				
			||||||
 | 
								var similarity = utils.Similar(providerName, code)
 | 
				
			||||||
 | 
								if similarity > 0 {
 | 
				
			||||||
 | 
									similarityList = append(similarityList, similarity)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(similarityList) > 0 {
 | 
				
			||||||
 | 
								similarResult = append(similarResult, maps.Map{
 | 
				
			||||||
 | 
									"similarity": numberutils.Max(similarityList...),
 | 
				
			||||||
 | 
									"provider":   provider,
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sort.Slice(similarResult, func(i, j int) bool {
 | 
				
			||||||
 | 
							return similarResult[i].GetFloat32("similarity") > similarResult[j].GetFloat32("similarity")
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(similarResult) > size {
 | 
				
			||||||
 | 
							similarResult = similarResult[:size]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, r := range similarResult {
 | 
				
			||||||
 | 
							result = append(result, r.Get("provider").(*RegionProvider))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,13 @@ package regions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import "github.com/iwind/TeaGo/dbs"
 | 
					import "github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RegionProvider 区域ISP
 | 
					// RegionProvider 区域-运营商
 | 
				
			||||||
type RegionProvider struct {
 | 
					type RegionProvider struct {
 | 
				
			||||||
	Id          uint32   `field:"id"`          // ID
 | 
						Id          uint32   `field:"id"`          // ID
 | 
				
			||||||
	Name        string   `field:"name"`        // 名称
 | 
						Name        string   `field:"name"`        // 名称
 | 
				
			||||||
	Codes       dbs.JSON `field:"codes"`       // 代号
 | 
						Codes       dbs.JSON `field:"codes"`       // 代号
 | 
				
			||||||
 | 
						CustomName  string   `field:"customName"`  // 自定义名称
 | 
				
			||||||
 | 
						CustomCodes dbs.JSON `field:"customCodes"` // 自定义代号
 | 
				
			||||||
	State       uint8    `field:"state"`       // 状态
 | 
						State       uint8    `field:"state"`       // 状态
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -14,6 +16,8 @@ type RegionProviderOperator struct {
 | 
				
			|||||||
	Id          interface{} // ID
 | 
						Id          interface{} // ID
 | 
				
			||||||
	Name        interface{} // 名称
 | 
						Name        interface{} // 名称
 | 
				
			||||||
	Codes       interface{} // 代号
 | 
						Codes       interface{} // 代号
 | 
				
			||||||
 | 
						CustomName  interface{} // 自定义名称
 | 
				
			||||||
 | 
						CustomCodes interface{} // 自定义代号
 | 
				
			||||||
	State       interface{} // 状态
 | 
						State       interface{} // 状态
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,17 +2,56 @@ package regions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"github.com/iwind/TeaGo/logs"
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/lists"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *RegionProvider) DecodeCodes() []string {
 | 
					func (this *RegionProvider) DecodeCodes() []string {
 | 
				
			||||||
	if len(this.Codes) == 0 {
 | 
						if len(this.Codes) == 0 {
 | 
				
			||||||
		return []string{}
 | 
							return []string{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	result := []string{}
 | 
						var result = []string{}
 | 
				
			||||||
	err := json.Unmarshal(this.Codes, &result)
 | 
						err := json.Unmarshal(this.Codes, &result)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		logs.Error(err)
 | 
							remotelogs.Error("RegionProvider.DecodeCodes", err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return result
 | 
						return result
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionProvider) DecodeCustomCodes() []string {
 | 
				
			||||||
 | 
						if len(this.CustomCodes) == 0 {
 | 
				
			||||||
 | 
							return []string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var result = []string{}
 | 
				
			||||||
 | 
						err := json.Unmarshal(this.CustomCodes, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							remotelogs.Error("RegionProvider.DecodeCustomCodes", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionProvider) DisplayName() string {
 | 
				
			||||||
 | 
						if len(this.CustomName) > 0 {
 | 
				
			||||||
 | 
							return this.CustomName
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return this.Name
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionProvider) AllCodes() []string {
 | 
				
			||||||
 | 
						var codes = this.DecodeCodes()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(this.Name) > 0 && !lists.ContainsString(codes, this.Name) {
 | 
				
			||||||
 | 
							codes = append(codes, this.Name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(this.CustomName) > 0 && !lists.ContainsString(codes, this.CustomName) {
 | 
				
			||||||
 | 
							codes = append(codes, this.CustomName)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, code := range this.DecodeCustomCodes() {
 | 
				
			||||||
 | 
							if !lists.ContainsString(codes, code) {
 | 
				
			||||||
 | 
								codes = append(codes, code)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return codes
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,14 @@ package regions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
 | 
				
			||||||
	_ "github.com/go-sql-driver/mysql"
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
	"github.com/iwind/TeaGo/Tea"
 | 
						"github.com/iwind/TeaGo/Tea"
 | 
				
			||||||
	"github.com/iwind/TeaGo/dbs"
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
	"github.com/iwind/TeaGo/types"
 | 
						"github.com/iwind/TeaGo/types"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -38,7 +41,7 @@ func init() {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 启用条目
 | 
					// EnableRegionProvince 启用条目
 | 
				
			||||||
func (this *RegionProvinceDAO) EnableRegionProvince(tx *dbs.Tx, id int64) error {
 | 
					func (this *RegionProvinceDAO) EnableRegionProvince(tx *dbs.Tx, id int64) error {
 | 
				
			||||||
	_, err := this.Query(tx).
 | 
						_, err := this.Query(tx).
 | 
				
			||||||
		Pk(id).
 | 
							Pk(id).
 | 
				
			||||||
@@ -47,7 +50,7 @@ func (this *RegionProvinceDAO) EnableRegionProvince(tx *dbs.Tx, id int64) error
 | 
				
			|||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 禁用条目
 | 
					// DisableRegionProvince 禁用条目
 | 
				
			||||||
func (this *RegionProvinceDAO) DisableRegionProvince(tx *dbs.Tx, id int64) error {
 | 
					func (this *RegionProvinceDAO) DisableRegionProvince(tx *dbs.Tx, id int64) error {
 | 
				
			||||||
	_, err := this.Query(tx).
 | 
						_, err := this.Query(tx).
 | 
				
			||||||
		Pk(id).
 | 
							Pk(id).
 | 
				
			||||||
@@ -56,7 +59,7 @@ func (this *RegionProvinceDAO) DisableRegionProvince(tx *dbs.Tx, id int64) error
 | 
				
			|||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 查找启用中的条目
 | 
					// FindEnabledRegionProvince 查找启用中的条目
 | 
				
			||||||
func (this *RegionProvinceDAO) FindEnabledRegionProvince(tx *dbs.Tx, id int64) (*RegionProvince, error) {
 | 
					func (this *RegionProvinceDAO) FindEnabledRegionProvince(tx *dbs.Tx, id int64) (*RegionProvince, error) {
 | 
				
			||||||
	result, err := this.Query(tx).
 | 
						result, err := this.Query(tx).
 | 
				
			||||||
		Pk(id).
 | 
							Pk(id).
 | 
				
			||||||
@@ -68,7 +71,7 @@ func (this *RegionProvinceDAO) FindEnabledRegionProvince(tx *dbs.Tx, id int64) (
 | 
				
			|||||||
	return result.(*RegionProvince), err
 | 
						return result.(*RegionProvince), err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 根据主键查找名称
 | 
					// FindRegionProvinceName 根据主键查找名称
 | 
				
			||||||
func (this *RegionProvinceDAO) FindRegionProvinceName(tx *dbs.Tx, id int64) (string, error) {
 | 
					func (this *RegionProvinceDAO) FindRegionProvinceName(tx *dbs.Tx, id int64) (string, error) {
 | 
				
			||||||
	return this.Query(tx).
 | 
						return this.Query(tx).
 | 
				
			||||||
		Pk(id).
 | 
							Pk(id).
 | 
				
			||||||
@@ -76,7 +79,7 @@ func (this *RegionProvinceDAO) FindRegionProvinceName(tx *dbs.Tx, id int64) (str
 | 
				
			|||||||
		FindStringCol("")
 | 
							FindStringCol("")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 根据数据ID查找省份
 | 
					// FindProvinceIdWithDataId 根据数据ID查找省份
 | 
				
			||||||
func (this *RegionProvinceDAO) FindProvinceIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
 | 
					func (this *RegionProvinceDAO) FindProvinceIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
 | 
				
			||||||
	return this.Query(tx).
 | 
						return this.Query(tx).
 | 
				
			||||||
		Attr("dataId", dataId).
 | 
							Attr("dataId", dataId).
 | 
				
			||||||
@@ -84,17 +87,18 @@ func (this *RegionProvinceDAO) FindProvinceIdWithDataId(tx *dbs.Tx, dataId strin
 | 
				
			|||||||
		FindInt64Col(0)
 | 
							FindInt64Col(0)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 根据省份名查找省份ID
 | 
					// FindProvinceIdWithName 根据省份名查找省份ID
 | 
				
			||||||
func (this *RegionProvinceDAO) FindProvinceIdWithName(tx *dbs.Tx, countryId int64, provinceName string) (int64, error) {
 | 
					func (this *RegionProvinceDAO) FindProvinceIdWithName(tx *dbs.Tx, countryId int64, provinceName string) (int64, error) {
 | 
				
			||||||
	return this.Query(tx).
 | 
						return this.Query(tx).
 | 
				
			||||||
		Attr("countryId", countryId).
 | 
							Attr("countryId", countryId).
 | 
				
			||||||
		Where("JSON_CONTAINS(codes, :provinceName)").
 | 
							Where("(name=:provinceName OR customName=:provinceName OR JSON_CONTAINS(codes, :provinceNameJSON) OR JSON_CONTAINS(customCodes, :provinceNameJSON))").
 | 
				
			||||||
		Param("provinceName", strconv.Quote(provinceName)). // 查询的需要是个JSON字符串,所以这里加双引号
 | 
							Param("provinceName", provinceName).
 | 
				
			||||||
 | 
							Param("provinceNameJSON", strconv.Quote(provinceName)). // 查询的需要是个JSON字符串,所以这里加双引号
 | 
				
			||||||
		ResultPk().
 | 
							ResultPk().
 | 
				
			||||||
		FindInt64Col(0)
 | 
							FindInt64Col(0)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 根据省份名查找省份ID,并可使用缓存
 | 
					// FindProvinceIdWithNameCacheable 根据省份名查找省份ID,并可使用缓存
 | 
				
			||||||
func (this *RegionProvinceDAO) FindProvinceIdWithNameCacheable(tx *dbs.Tx, countryId int64, provinceName string) (int64, error) {
 | 
					func (this *RegionProvinceDAO) FindProvinceIdWithNameCacheable(tx *dbs.Tx, countryId int64, provinceName string) (int64, error) {
 | 
				
			||||||
	var key = provinceName + "@" + numberutils.FormatInt64(countryId)
 | 
						var key = provinceName + "@" + numberutils.FormatInt64(countryId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -110,14 +114,16 @@ func (this *RegionProvinceDAO) FindProvinceIdWithNameCacheable(tx *dbs.Tx, count
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return 0, err
 | 
							return 0, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if provinceId > 0 {
 | 
				
			||||||
		SharedCacheLocker.Lock()
 | 
							SharedCacheLocker.Lock()
 | 
				
			||||||
		regionProvinceNameAndIdCacheMap[key] = provinceId
 | 
							regionProvinceNameAndIdCacheMap[key] = provinceId
 | 
				
			||||||
		SharedCacheLocker.Unlock()
 | 
							SharedCacheLocker.Unlock()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return provinceId, nil
 | 
						return provinceId, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 创建省份
 | 
					// CreateProvince 创建省份
 | 
				
			||||||
func (this *RegionProvinceDAO) CreateProvince(tx *dbs.Tx, countryId int64, name string, dataId string) (int64, error) {
 | 
					func (this *RegionProvinceDAO) CreateProvince(tx *dbs.Tx, countryId int64, name string, dataId string) (int64, error) {
 | 
				
			||||||
	var op = NewRegionProvinceOperator()
 | 
						var op = NewRegionProvinceOperator()
 | 
				
			||||||
	op.CountryId = countryId
 | 
						op.CountryId = countryId
 | 
				
			||||||
@@ -138,7 +144,7 @@ func (this *RegionProvinceDAO) CreateProvince(tx *dbs.Tx, countryId int64, name
 | 
				
			|||||||
	return types.Int64(op.Id), nil
 | 
						return types.Int64(op.Id), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 查找所有省份
 | 
					// FindAllEnabledProvincesWithCountryId 查找某个国家/地区的所有省份
 | 
				
			||||||
func (this *RegionProvinceDAO) FindAllEnabledProvincesWithCountryId(tx *dbs.Tx, countryId int64) (result []*RegionProvince, err error) {
 | 
					func (this *RegionProvinceDAO) FindAllEnabledProvincesWithCountryId(tx *dbs.Tx, countryId int64) (result []*RegionProvince, err error) {
 | 
				
			||||||
	_, err = this.Query(tx).
 | 
						_, err = this.Query(tx).
 | 
				
			||||||
		State(RegionProvinceStateEnabled).
 | 
							State(RegionProvinceStateEnabled).
 | 
				
			||||||
@@ -148,3 +154,76 @@ func (this *RegionProvinceDAO) FindAllEnabledProvincesWithCountryId(tx *dbs.Tx,
 | 
				
			|||||||
		FindAll()
 | 
							FindAll()
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindAllEnabledProvinces 查找所有省份
 | 
				
			||||||
 | 
					func (this *RegionProvinceDAO) FindAllEnabledProvinces(tx *dbs.Tx) (result []*RegionProvince, err error) {
 | 
				
			||||||
 | 
						_, err = this.Query(tx).
 | 
				
			||||||
 | 
							State(RegionProvinceStateEnabled).
 | 
				
			||||||
 | 
							Asc().
 | 
				
			||||||
 | 
							Slice(&result).
 | 
				
			||||||
 | 
							FindAll()
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UpdateProvinceCustom 修改自定义省份信息
 | 
				
			||||||
 | 
					func (this *RegionProvinceDAO) UpdateProvinceCustom(tx *dbs.Tx, provinceId int64, customName string, customCodes []string) error {
 | 
				
			||||||
 | 
						if customCodes == nil {
 | 
				
			||||||
 | 
							customCodes = []string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						customCodesJSON, err := json.Marshal(customCodes)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 清空缓存
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							SharedCacheLocker.Lock()
 | 
				
			||||||
 | 
							regionProvinceNameAndIdCacheMap = map[string]int64{}
 | 
				
			||||||
 | 
							SharedCacheLocker.Unlock()
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return this.Query(tx).
 | 
				
			||||||
 | 
							Pk(provinceId).
 | 
				
			||||||
 | 
							Set("customName", customName).
 | 
				
			||||||
 | 
							Set("customCodes", customCodesJSON).
 | 
				
			||||||
 | 
							UpdateQuickly()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindSimilarProvinces 查找类似省份名
 | 
				
			||||||
 | 
					func (this *RegionProvinceDAO) FindSimilarProvinces(provinces []*RegionProvince, provinceName string, size int) (result []*RegionProvince) {
 | 
				
			||||||
 | 
						if len(provinces) == 0 {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var similarResult = []maps.Map{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, province := range provinces {
 | 
				
			||||||
 | 
							var similarityList = []float32{}
 | 
				
			||||||
 | 
							for _, code := range province.AllCodes() {
 | 
				
			||||||
 | 
								var similarity = utils.Similar(provinceName, code)
 | 
				
			||||||
 | 
								if similarity > 0 {
 | 
				
			||||||
 | 
									similarityList = append(similarityList, similarity)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(similarityList) > 0 {
 | 
				
			||||||
 | 
								similarResult = append(similarResult, maps.Map{
 | 
				
			||||||
 | 
									"similarity": numberutils.Max(similarityList...),
 | 
				
			||||||
 | 
									"province":   province,
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sort.Slice(similarResult, func(i, j int) bool {
 | 
				
			||||||
 | 
							return similarResult[i].GetFloat32("similarity") > similarResult[j].GetFloat32("similarity")
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(similarResult) > size {
 | 
				
			||||||
 | 
							similarResult = similarResult[:size]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, r := range similarResult {
 | 
				
			||||||
 | 
							result = append(result, r.Get("province").(*RegionProvince))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestRegionProvinceDAO_FindProvinceIdWithProvinceName(t *testing.T) {
 | 
					func TestRegionProvinceDAO_FindProvinceIdWithNameCacheable(t *testing.T) {
 | 
				
			||||||
	dbs.NotifyReady()
 | 
						dbs.NotifyReady()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i := 0; i < 5; i++ {
 | 
						for i := 0; i < 5; i++ {
 | 
				
			||||||
@@ -29,3 +29,51 @@ func TestRegionProvinceDAO_FindProvinceIdWithProvinceName(t *testing.T) {
 | 
				
			|||||||
		t.Log(provinceId, time.Since(now).Seconds()*1000, "ms")
 | 
							t.Log(provinceId, time.Since(now).Seconds()*1000, "ms")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestRegionProvinceDAO_FindProvinceIdWithName(t *testing.T) {
 | 
				
			||||||
 | 
						dbs.NotifyReady()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx *dbs.Tx
 | 
				
			||||||
 | 
						for _, name := range []string{
 | 
				
			||||||
 | 
							"安徽",
 | 
				
			||||||
 | 
							"安徽省",
 | 
				
			||||||
 | 
							"广西",
 | 
				
			||||||
 | 
							"广西省",
 | 
				
			||||||
 | 
							"广西壮族自治区",
 | 
				
			||||||
 | 
							"皖",
 | 
				
			||||||
 | 
						} {
 | 
				
			||||||
 | 
							provinceId, err := SharedRegionProvinceDAO.FindProvinceIdWithName(tx, 1, name)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.Fatal(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							t.Log(name, "=>", provinceId)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestRegionProvinceDAO_FindSimilarProvinces(t *testing.T) {
 | 
				
			||||||
 | 
						dbs.NotifyReady()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx *dbs.Tx
 | 
				
			||||||
 | 
						var countryId int64 = 1
 | 
				
			||||||
 | 
						provinces, err := SharedRegionProvinceDAO.FindAllEnabledProvincesWithCountryId(tx, countryId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, provinceName := range []string{
 | 
				
			||||||
 | 
							"北京",
 | 
				
			||||||
 | 
							"北京市",
 | 
				
			||||||
 | 
							"安徽",
 | 
				
			||||||
 | 
							"安徽省",
 | 
				
			||||||
 | 
							"大北京",
 | 
				
			||||||
 | 
						} {
 | 
				
			||||||
 | 
							t.Log("====" + provinceName + "====")
 | 
				
			||||||
 | 
							var provinces = SharedRegionProvinceDAO.FindSimilarProvinces(provinces, provinceName, 5)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.Fatal(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, province := range provinces {
 | 
				
			||||||
 | 
								t.Log(province.Name, province.AllCodes())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,12 +2,14 @@ package regions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import "github.com/iwind/TeaGo/dbs"
 | 
					import "github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RegionProvince 区域省份
 | 
					// RegionProvince 区域-省份
 | 
				
			||||||
type RegionProvince struct {
 | 
					type RegionProvince struct {
 | 
				
			||||||
	Id          uint32   `field:"id"`          // ID
 | 
						Id          uint32   `field:"id"`          // ID
 | 
				
			||||||
	CountryId   uint32   `field:"countryId"`   // 国家ID
 | 
						CountryId   uint32   `field:"countryId"`   // 国家ID
 | 
				
			||||||
	Name        string   `field:"name"`        // 名称
 | 
						Name        string   `field:"name"`        // 名称
 | 
				
			||||||
	Codes       dbs.JSON `field:"codes"`       // 代号
 | 
						Codes       dbs.JSON `field:"codes"`       // 代号
 | 
				
			||||||
 | 
						CustomName  string   `field:"customName"`  // 自定义名称
 | 
				
			||||||
 | 
						CustomCodes dbs.JSON `field:"customCodes"` // 自定义代号
 | 
				
			||||||
	State       uint8    `field:"state"`       // 状态
 | 
						State       uint8    `field:"state"`       // 状态
 | 
				
			||||||
	DataId      string   `field:"dataId"`      // 原始数据ID
 | 
						DataId      string   `field:"dataId"`      // 原始数据ID
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -17,6 +19,8 @@ type RegionProvinceOperator struct {
 | 
				
			|||||||
	CountryId   interface{} // 国家ID
 | 
						CountryId   interface{} // 国家ID
 | 
				
			||||||
	Name        interface{} // 名称
 | 
						Name        interface{} // 名称
 | 
				
			||||||
	Codes       interface{} // 代号
 | 
						Codes       interface{} // 代号
 | 
				
			||||||
 | 
						CustomName  interface{} // 自定义名称
 | 
				
			||||||
 | 
						CustomCodes interface{} // 自定义代号
 | 
				
			||||||
	State       interface{} // 状态
 | 
						State       interface{} // 状态
 | 
				
			||||||
	DataId      interface{} // 原始数据ID
 | 
						DataId      interface{} // 原始数据ID
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,17 +2,56 @@ package regions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"github.com/iwind/TeaGo/logs"
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/lists"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *RegionProvince) DecodeCodes() []string {
 | 
					func (this *RegionProvince) DecodeCodes() []string {
 | 
				
			||||||
	if len(this.Codes) == 0 {
 | 
						if len(this.Codes) == 0 {
 | 
				
			||||||
		return []string{}
 | 
							return []string{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	result := []string{}
 | 
						var result = []string{}
 | 
				
			||||||
	err := json.Unmarshal(this.Codes, &result)
 | 
						err := json.Unmarshal(this.Codes, &result)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		logs.Error(err)
 | 
							remotelogs.Error("RegionProvince.DecodeCodes", err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return result
 | 
						return result
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionProvince) DecodeCustomCodes() []string {
 | 
				
			||||||
 | 
						if len(this.CustomCodes) == 0 {
 | 
				
			||||||
 | 
							return []string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var result = []string{}
 | 
				
			||||||
 | 
						err := json.Unmarshal(this.CustomCodes, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							remotelogs.Error("RegionProvince.DecodeCustomCodes", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionProvince) DisplayName() string {
 | 
				
			||||||
 | 
						if len(this.CustomName) > 0 {
 | 
				
			||||||
 | 
							return this.CustomName
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return this.Name
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionProvince) AllCodes() []string {
 | 
				
			||||||
 | 
						var codes = this.DecodeCodes()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(this.Name) > 0 && !lists.ContainsString(codes, this.Name) {
 | 
				
			||||||
 | 
							codes = append(codes, this.Name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(this.CustomName) > 0 && !lists.ContainsString(codes, this.CustomName) {
 | 
				
			||||||
 | 
							codes = append(codes, this.CustomName)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, code := range this.DecodeCustomCodes() {
 | 
				
			||||||
 | 
							if !lists.ContainsString(codes, code) {
 | 
				
			||||||
 | 
								codes = append(codes, code)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return codes
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										131
									
								
								internal/db/models/regions/region_town_dao.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								internal/db/models/regions/region_town_dao.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,131 @@
 | 
				
			|||||||
 | 
					package regions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
 | 
				
			||||||
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/Tea"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						RegionTownStateEnabled  = 1 // 已启用
 | 
				
			||||||
 | 
						RegionTownStateDisabled = 0 // 已禁用
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type RegionTownDAO dbs.DAO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewRegionTownDAO() *RegionTownDAO {
 | 
				
			||||||
 | 
						return dbs.NewDAO(&RegionTownDAO{
 | 
				
			||||||
 | 
							DAOObject: dbs.DAOObject{
 | 
				
			||||||
 | 
								DB:     Tea.Env,
 | 
				
			||||||
 | 
								Table:  "edgeRegionTowns",
 | 
				
			||||||
 | 
								Model:  new(RegionTown),
 | 
				
			||||||
 | 
								PkName: "id",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}).(*RegionTownDAO)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var SharedRegionTownDAO *RegionTownDAO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						dbs.OnReady(func() {
 | 
				
			||||||
 | 
							SharedRegionTownDAO = NewRegionTownDAO()
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EnableRegionTown 启用条目
 | 
				
			||||||
 | 
					func (this *RegionTownDAO) EnableRegionTown(tx *dbs.Tx, id uint32) error {
 | 
				
			||||||
 | 
						_, err := this.Query(tx).
 | 
				
			||||||
 | 
							Pk(id).
 | 
				
			||||||
 | 
							Set("state", RegionTownStateEnabled).
 | 
				
			||||||
 | 
							Update()
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DisableRegionTown 禁用条目
 | 
				
			||||||
 | 
					func (this *RegionTownDAO) DisableRegionTown(tx *dbs.Tx, id uint32) error {
 | 
				
			||||||
 | 
						_, err := this.Query(tx).
 | 
				
			||||||
 | 
							Pk(id).
 | 
				
			||||||
 | 
							Set("state", RegionTownStateDisabled).
 | 
				
			||||||
 | 
							Update()
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindEnabledRegionTown 查找启用中的条目
 | 
				
			||||||
 | 
					func (this *RegionTownDAO) FindEnabledRegionTown(tx *dbs.Tx, id uint32) (*RegionTown, error) {
 | 
				
			||||||
 | 
						result, err := this.Query(tx).
 | 
				
			||||||
 | 
							Pk(id).
 | 
				
			||||||
 | 
							Attr("state", RegionTownStateEnabled).
 | 
				
			||||||
 | 
							Find()
 | 
				
			||||||
 | 
						if result == nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return result.(*RegionTown), err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindRegionTownName 根据主键查找名称
 | 
				
			||||||
 | 
					func (this *RegionTownDAO) FindRegionTownName(tx *dbs.Tx, id uint32) (string, error) {
 | 
				
			||||||
 | 
						return this.Query(tx).
 | 
				
			||||||
 | 
							Pk(id).
 | 
				
			||||||
 | 
							Result("name").
 | 
				
			||||||
 | 
							FindStringCol("")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UpdateTownCustom 修改自定义县级信息
 | 
				
			||||||
 | 
					func (this *RegionTownDAO) UpdateTownCustom(tx *dbs.Tx, townId int64, customName string, customCodes []string) error {
 | 
				
			||||||
 | 
						if customCodes == nil {
 | 
				
			||||||
 | 
							customCodes = []string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						customCodesJSON, err := json.Marshal(customCodes)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return this.Query(tx).
 | 
				
			||||||
 | 
							Pk(townId).
 | 
				
			||||||
 | 
							Set("customName", customName).
 | 
				
			||||||
 | 
							Set("customCodes", customCodesJSON).
 | 
				
			||||||
 | 
							UpdateQuickly()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindSimilarTowns 查找类似区县
 | 
				
			||||||
 | 
					func (this *RegionTownDAO) FindSimilarTowns(towns []*RegionTown, townName string, size int) (result []*RegionTown) {
 | 
				
			||||||
 | 
						if len(towns) == 0 {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var similarResult = []maps.Map{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, town := range towns {
 | 
				
			||||||
 | 
							var similarityList = []float32{}
 | 
				
			||||||
 | 
							for _, code := range town.AllCodes() {
 | 
				
			||||||
 | 
								var similarity = utils.Similar(townName, code)
 | 
				
			||||||
 | 
								if similarity > 0 {
 | 
				
			||||||
 | 
									similarityList = append(similarityList, similarity)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(similarityList) > 0 {
 | 
				
			||||||
 | 
								similarResult = append(similarResult, maps.Map{
 | 
				
			||||||
 | 
									"similarity": numberutils.Max(similarityList...),
 | 
				
			||||||
 | 
									"town":       town,
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sort.Slice(similarResult, func(i, j int) bool {
 | 
				
			||||||
 | 
							return similarResult[i].GetFloat32("similarity") > similarResult[j].GetFloat32("similarity")
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(similarResult) > size {
 | 
				
			||||||
 | 
							similarResult = similarResult[:size]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, r := range similarResult {
 | 
				
			||||||
 | 
							result = append(result, r.Get("town").(*RegionTown))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								internal/db/models/regions/region_town_dao_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								internal/db/models/regions/region_town_dao_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					package regions_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
 | 
						_ "github.com/iwind/TeaGo/bootstrap"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										30
									
								
								internal/db/models/regions/region_town_model.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								internal/db/models/regions/region_town_model.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					package regions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RegionTown 区域-省份
 | 
				
			||||||
 | 
					type RegionTown struct {
 | 
				
			||||||
 | 
						Id          uint32   `field:"id"`          // ID
 | 
				
			||||||
 | 
						CityId      uint32   `field:"cityId"`      // 城市ID
 | 
				
			||||||
 | 
						Name        string   `field:"name"`        // 名称
 | 
				
			||||||
 | 
						Codes       dbs.JSON `field:"codes"`       // 代号
 | 
				
			||||||
 | 
						CustomName  string   `field:"customName"`  // 自定义名称
 | 
				
			||||||
 | 
						CustomCodes dbs.JSON `field:"customCodes"` // 自定义代号
 | 
				
			||||||
 | 
						State       uint8    `field:"state"`       // 状态
 | 
				
			||||||
 | 
						DataId      string   `field:"dataId"`      // 原始数据ID
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type RegionTownOperator struct {
 | 
				
			||||||
 | 
						Id          interface{} // ID
 | 
				
			||||||
 | 
						CityId      interface{} // 城市ID
 | 
				
			||||||
 | 
						Name        interface{} // 名称
 | 
				
			||||||
 | 
						Codes       interface{} // 代号
 | 
				
			||||||
 | 
						CustomName  interface{} // 自定义名称
 | 
				
			||||||
 | 
						CustomCodes interface{} // 自定义代号
 | 
				
			||||||
 | 
						State       interface{} // 状态
 | 
				
			||||||
 | 
						DataId      interface{} // 原始数据ID
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewRegionTownOperator() *RegionTownOperator {
 | 
				
			||||||
 | 
						return &RegionTownOperator{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										57
									
								
								internal/db/models/regions/region_town_model_ext.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								internal/db/models/regions/region_town_model_ext.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					package regions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/lists"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionTown) DecodeCodes() []string {
 | 
				
			||||||
 | 
						if len(this.Codes) == 0 {
 | 
				
			||||||
 | 
							return []string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var result = []string{}
 | 
				
			||||||
 | 
						err := json.Unmarshal(this.Codes, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							remotelogs.Error("RegionTown.DecodeCodes", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionTown) DecodeCustomCodes() []string {
 | 
				
			||||||
 | 
						if len(this.CustomCodes) == 0 {
 | 
				
			||||||
 | 
							return []string{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var result = []string{}
 | 
				
			||||||
 | 
						err := json.Unmarshal(this.CustomCodes, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							remotelogs.Error("RegionTown.DecodeCustomCodes", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionTown) DisplayName() string {
 | 
				
			||||||
 | 
						if len(this.CustomName) > 0 {
 | 
				
			||||||
 | 
							return this.CustomName
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return this.Name
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *RegionTown) AllCodes() []string {
 | 
				
			||||||
 | 
						var codes = this.DecodeCodes()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(this.Name) > 0 && !lists.ContainsString(codes, this.Name) {
 | 
				
			||||||
 | 
							codes = append(codes, this.Name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(this.CustomName) > 0 && !lists.ContainsString(codes, this.CustomName) {
 | 
				
			||||||
 | 
							codes = append(codes, this.CustomName)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, code := range this.DecodeCustomCodes() {
 | 
				
			||||||
 | 
							if !lists.ContainsString(codes, code) {
 | 
				
			||||||
 | 
								codes = append(codes, code)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return codes
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -242,6 +242,11 @@ func (this *APINode) registerServices(server *grpc.Server) {
 | 
				
			|||||||
		pb.RegisterIPLibraryServiceServer(server, instance)
 | 
							pb.RegisterIPLibraryServiceServer(server, instance)
 | 
				
			||||||
		this.rest(instance)
 | 
							this.rest(instance)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var instance = this.serviceInstance(&services.IPLibraryFileService{}).(*services.IPLibraryFileService)
 | 
				
			||||||
 | 
							pb.RegisterIPLibraryFileServiceServer(server, instance)
 | 
				
			||||||
 | 
							this.rest(instance)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		var instance = this.serviceInstance(&services.FileChunkService{}).(*services.FileChunkService)
 | 
							var instance = this.serviceInstance(&services.FileChunkService{}).(*services.FileChunkService)
 | 
				
			||||||
		pb.RegisterFileChunkServiceServer(server, instance)
 | 
							pb.RegisterFileChunkServiceServer(server, instance)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -187,7 +187,7 @@ func (this *AdminService) FindEnabledAdmin(ctx context.Context, req *pb.FindEnab
 | 
				
			|||||||
		IsSuper:  admin.IsSuper,
 | 
							IsSuper:  admin.IsSuper,
 | 
				
			||||||
		Modules:  pbModules,
 | 
							Modules:  pbModules,
 | 
				
			||||||
		OtpLogin: pbOtpAuth,
 | 
							OtpLogin: pbOtpAuth,
 | 
				
			||||||
		CanLogin: admin.CanLogin == 1,
 | 
							CanLogin: admin.CanLogin,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return &pb.FindEnabledAdminResponse{Admin: result}, nil
 | 
						return &pb.FindEnabledAdminResponse{Admin: result}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -407,7 +407,7 @@ func (this *AdminService) ListEnabledAdmins(ctx context.Context, req *pb.ListEna
 | 
				
			|||||||
			IsSuper:   admin.IsSuper,
 | 
								IsSuper:   admin.IsSuper,
 | 
				
			||||||
			CreatedAt: int64(admin.CreatedAt),
 | 
								CreatedAt: int64(admin.CreatedAt),
 | 
				
			||||||
			OtpLogin:  pbOtpAuth,
 | 
								OtpLogin:  pbOtpAuth,
 | 
				
			||||||
			CanLogin:  admin.CanLogin == 1,
 | 
								CanLogin:  admin.CanLogin,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										495
									
								
								internal/rpc/services/service_ip_library_file.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										495
									
								
								internal/rpc/services/service_ip_library_file.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,495 @@
 | 
				
			|||||||
 | 
					// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package services
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/db/models"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/db/models/regions"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/lists"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/types"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IPLibraryFileService IP库文件管理
 | 
				
			||||||
 | 
					type IPLibraryFileService struct {
 | 
				
			||||||
 | 
						BaseService
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindAllUnfinishedIPLibraryFiles 查找所有未完成的IP库文件
 | 
				
			||||||
 | 
					func (this *IPLibraryFileService) FindAllUnfinishedIPLibraryFiles(ctx context.Context, req *pb.FindAllUnfinishedIPLibraryFilesRequest) (*pb.FindAllUnfinishedIPLibraryFilesResponse, error) {
 | 
				
			||||||
 | 
						_, err := this.ValidateAdmin(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						libraryFiles, err := models.SharedIPLibraryFileDAO.FindAllUnfinishedLibraryFiles(tx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var pbLibraryFiles = []*pb.IPLibraryFile{}
 | 
				
			||||||
 | 
						for _, libraryFile := range libraryFiles {
 | 
				
			||||||
 | 
							var pbCountryNames = libraryFile.DecodeCountries()
 | 
				
			||||||
 | 
							var pbProviderNames = libraryFile.DecodeProviders()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var pbProvinces = []*pb.IPLibraryFile_Province{}
 | 
				
			||||||
 | 
							for _, province := range libraryFile.DecodeProvinces() {
 | 
				
			||||||
 | 
								pbProvinces = append(pbProvinces, &pb.IPLibraryFile_Province{
 | 
				
			||||||
 | 
									CountryName:  province[0],
 | 
				
			||||||
 | 
									ProvinceName: province[1],
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var pbCities = []*pb.IPLibraryFile_City{}
 | 
				
			||||||
 | 
							for _, city := range libraryFile.DecodeCities() {
 | 
				
			||||||
 | 
								pbCities = append(pbCities, &pb.IPLibraryFile_City{
 | 
				
			||||||
 | 
									CountryName:  city[0],
 | 
				
			||||||
 | 
									ProvinceName: city[1],
 | 
				
			||||||
 | 
									CityName:     city[2],
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var pbTowns = []*pb.IPLibraryFile_Town{}
 | 
				
			||||||
 | 
							for _, town := range libraryFile.DecodeTowns() {
 | 
				
			||||||
 | 
								pbTowns = append(pbTowns, &pb.IPLibraryFile_Town{
 | 
				
			||||||
 | 
									CountryName:  town[0],
 | 
				
			||||||
 | 
									ProvinceName: town[1],
 | 
				
			||||||
 | 
									CityName:     town[2],
 | 
				
			||||||
 | 
									TownName:     town[3],
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pbLibraryFiles = append(pbLibraryFiles, &pb.IPLibraryFile{
 | 
				
			||||||
 | 
								Id:            int64(libraryFile.Id),
 | 
				
			||||||
 | 
								FileId:        int64(libraryFile.FileId),
 | 
				
			||||||
 | 
								IsFinished:    libraryFile.IsFinished,
 | 
				
			||||||
 | 
								CreatedAt:     int64(libraryFile.CreatedAt),
 | 
				
			||||||
 | 
								CountryNames:  pbCountryNames,
 | 
				
			||||||
 | 
								Provinces:     pbProvinces,
 | 
				
			||||||
 | 
								Cities:        pbCities,
 | 
				
			||||||
 | 
								Towns:         pbTowns,
 | 
				
			||||||
 | 
								ProviderNames: pbProviderNames,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.FindAllUnfinishedIPLibraryFilesResponse{
 | 
				
			||||||
 | 
							IpLibraryFiles: pbLibraryFiles,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindIPLibraryFile 查找单个IP库文件
 | 
				
			||||||
 | 
					func (this *IPLibraryFileService) FindIPLibraryFile(ctx context.Context, req *pb.FindIPLibraryFileRequest) (*pb.FindIPLibraryFileResponse, error) {
 | 
				
			||||||
 | 
						_, err := this.ValidateAdmin(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						libraryFile, err := models.SharedIPLibraryFileDAO.FindEnabledIPLibraryFile(tx, req.IpLibraryFileId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if libraryFile == nil {
 | 
				
			||||||
 | 
							return &pb.FindIPLibraryFileResponse{
 | 
				
			||||||
 | 
								IpLibraryFile: nil,
 | 
				
			||||||
 | 
							}, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var pbCountryNames = libraryFile.DecodeCountries()
 | 
				
			||||||
 | 
						var pbProviderNames = libraryFile.DecodeProviders()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var pbProvinces = []*pb.IPLibraryFile_Province{}
 | 
				
			||||||
 | 
						for _, province := range libraryFile.DecodeProvinces() {
 | 
				
			||||||
 | 
							pbProvinces = append(pbProvinces, &pb.IPLibraryFile_Province{
 | 
				
			||||||
 | 
								CountryName:  province[0],
 | 
				
			||||||
 | 
								ProvinceName: province[1],
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var pbCities = []*pb.IPLibraryFile_City{}
 | 
				
			||||||
 | 
						for _, city := range libraryFile.DecodeCities() {
 | 
				
			||||||
 | 
							pbCities = append(pbCities, &pb.IPLibraryFile_City{
 | 
				
			||||||
 | 
								CountryName:  city[0],
 | 
				
			||||||
 | 
								ProvinceName: city[1],
 | 
				
			||||||
 | 
								CityName:     city[2],
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var pbTowns = []*pb.IPLibraryFile_Town{}
 | 
				
			||||||
 | 
						for _, town := range libraryFile.DecodeTowns() {
 | 
				
			||||||
 | 
							pbTowns = append(pbTowns, &pb.IPLibraryFile_Town{
 | 
				
			||||||
 | 
								CountryName:  town[0],
 | 
				
			||||||
 | 
								ProvinceName: town[1],
 | 
				
			||||||
 | 
								CityName:     town[2],
 | 
				
			||||||
 | 
								TownName:     town[3],
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.FindIPLibraryFileResponse{IpLibraryFile: &pb.IPLibraryFile{
 | 
				
			||||||
 | 
							Id:            int64(libraryFile.Id),
 | 
				
			||||||
 | 
							FileId:        int64(libraryFile.FileId),
 | 
				
			||||||
 | 
							IsFinished:    libraryFile.IsFinished,
 | 
				
			||||||
 | 
							CreatedAt:     int64(libraryFile.CreatedAt),
 | 
				
			||||||
 | 
							CountryNames:  pbCountryNames,
 | 
				
			||||||
 | 
							Provinces:     pbProvinces,
 | 
				
			||||||
 | 
							Cities:        pbCities,
 | 
				
			||||||
 | 
							Towns:         pbTowns,
 | 
				
			||||||
 | 
							ProviderNames: pbProviderNames,
 | 
				
			||||||
 | 
						}}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CreateIPLibraryFile 创建IP库文件
 | 
				
			||||||
 | 
					func (this *IPLibraryFileService) CreateIPLibraryFile(ctx context.Context, req *pb.CreateIPLibraryFileRequest) (*pb.CreateIPLibraryFileResponse, error) {
 | 
				
			||||||
 | 
						_, err := this.ValidateAdmin(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var countries = []string{}
 | 
				
			||||||
 | 
						var provinces = [][2]string{}
 | 
				
			||||||
 | 
						var cities = [][3]string{}
 | 
				
			||||||
 | 
						var towns = [][4]string{}
 | 
				
			||||||
 | 
						var providers = []string{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = json.Unmarshal(req.CountriesJSON, &countries)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("decode countries failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = json.Unmarshal(req.ProvincesJSON, &provinces)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("decode provinces failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = json.Unmarshal(req.CitiesJSON, &cities)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("decode cities failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = json.Unmarshal(req.TownsJSON, &towns)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("decode towns failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = json.Unmarshal(req.ProvidersJSON, &providers)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("decode providers failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						libraryFileId, err := models.SharedIPLibraryFileDAO.CreateLibraryFile(tx, req.Template, req.EmptyValues, req.FileId, countries, provinces, cities, towns, providers)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &pb.CreateIPLibraryFileResponse{
 | 
				
			||||||
 | 
							IpLibraryFileId: libraryFileId,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CheckCountriesWithIPLibraryFileId 检查国家/地区
 | 
				
			||||||
 | 
					func (this *IPLibraryFileService) CheckCountriesWithIPLibraryFileId(ctx context.Context, req *pb.CheckCountriesWithIPLibraryFileIdRequest) (*pb.CheckCountriesWithIPLibraryFileIdResponse, error) {
 | 
				
			||||||
 | 
						_, err := this.ValidateAdmin(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						allCountries, err := regions.SharedRegionCountryDAO.FindAllCountries(tx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						countryNames, err := models.SharedIPLibraryFileDAO.FindLibraryFileCountries(tx, req.IpLibraryFileId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var pbMissingCountries = []*pb.CheckCountriesWithIPLibraryFileIdResponse_MissingCountry{}
 | 
				
			||||||
 | 
						for _, countryName := range countryNames {
 | 
				
			||||||
 | 
							if len(countryName) == 0 {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 检查是否存在
 | 
				
			||||||
 | 
							countryId, err := regions.SharedRegionCountryDAO.FindCountryIdWithName(tx, countryName)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if countryId > 0 {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var pbMissingCountry = &pb.CheckCountriesWithIPLibraryFileIdResponse_MissingCountry{
 | 
				
			||||||
 | 
								CountryName:      countryName,
 | 
				
			||||||
 | 
								SimilarCountries: nil,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 查找相似
 | 
				
			||||||
 | 
							var similarCountries = regions.SharedRegionCountryDAO.FindSimilarCountries(allCountries, countryName, 5)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, similarCountry := range similarCountries {
 | 
				
			||||||
 | 
								pbMissingCountry.SimilarCountries = append(pbMissingCountry.SimilarCountries, &pb.RegionCountry{
 | 
				
			||||||
 | 
									Id:          int64(similarCountry.Id),
 | 
				
			||||||
 | 
									Name:        similarCountry.Name,
 | 
				
			||||||
 | 
									DisplayName: similarCountry.DisplayName(),
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pbMissingCountries = append(pbMissingCountries, pbMissingCountry)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.CheckCountriesWithIPLibraryFileIdResponse{
 | 
				
			||||||
 | 
							MissingCountries: pbMissingCountries,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CheckProvincesWithIPLibraryFileId 检查省份/州
 | 
				
			||||||
 | 
					func (this *IPLibraryFileService) CheckProvincesWithIPLibraryFileId(ctx context.Context, req *pb.CheckProvincesWithIPLibraryFileIdRequest) (*pb.CheckProvincesWithIPLibraryFileIdResponse, error) {
 | 
				
			||||||
 | 
						_, err := this.ValidateAdmin(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						provinces, err := models.SharedIPLibraryFileDAO.FindLibraryFileProvinces(tx, req.IpLibraryFileId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var countryMap = map[string]int64{}            // countryName => countryId
 | 
				
			||||||
 | 
						var provinceNamesMap = map[int64][][2]string{} // countryId => [][2]{countryName, provinceName}
 | 
				
			||||||
 | 
						var countryIds = []int64{}
 | 
				
			||||||
 | 
						for _, province := range provinces {
 | 
				
			||||||
 | 
							var countryName = province[0]
 | 
				
			||||||
 | 
							var provinceName = province[1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							countryId, ok := countryMap[countryName]
 | 
				
			||||||
 | 
							if ok {
 | 
				
			||||||
 | 
								provinceNamesMap[countryId] = append(provinceNamesMap[countryId], [2]string{countryName, provinceName})
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							countryId, err := regions.SharedRegionCountryDAO.FindCountryIdWithName(tx, countryName)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							countryMap[countryName] = countryId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							provinceNamesMap[countryId] = append(provinceNamesMap[countryId], [2]string{countryName, provinceName})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if countryId > 0 && !lists.ContainsInt64(countryIds, countryId) {
 | 
				
			||||||
 | 
								countryIds = append(countryIds, countryId)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var pbMissingProvinces = []*pb.CheckProvincesWithIPLibraryFileIdResponse_MissingProvince{}
 | 
				
			||||||
 | 
						for _, countryId := range countryIds {
 | 
				
			||||||
 | 
							allProvinces, err := regions.SharedRegionProvinceDAO.FindAllEnabledProvincesWithCountryId(tx, countryId)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, province := range provinceNamesMap[countryId] {
 | 
				
			||||||
 | 
								var countryName = province[0]
 | 
				
			||||||
 | 
								var provinceName = province[1]
 | 
				
			||||||
 | 
								provinceId, err := regions.SharedRegionProvinceDAO.FindProvinceIdWithName(tx, countryId, provinceName)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if provinceId > 0 {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var similarProvinces = regions.SharedRegionProvinceDAO.FindSimilarProvinces(allProvinces, provinceName, 5)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								var pbMissingProvince = &pb.CheckProvincesWithIPLibraryFileIdResponse_MissingProvince{}
 | 
				
			||||||
 | 
								pbMissingProvince.CountryName = countryName
 | 
				
			||||||
 | 
								pbMissingProvince.ProvinceName = provinceName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for _, similarProvince := range similarProvinces {
 | 
				
			||||||
 | 
									pbMissingProvince.SimilarProvinces = append(pbMissingProvince.SimilarProvinces, &pb.RegionProvince{
 | 
				
			||||||
 | 
										Id:          int64(similarProvince.Id),
 | 
				
			||||||
 | 
										Name:        similarProvince.Name,
 | 
				
			||||||
 | 
										DisplayName: similarProvince.DisplayName(),
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								pbMissingProvinces = append(pbMissingProvinces, pbMissingProvince)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.CheckProvincesWithIPLibraryFileIdResponse{MissingProvinces: pbMissingProvinces}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CheckCitiesWithIPLibraryFileId 检查城市/市
 | 
				
			||||||
 | 
					func (this *IPLibraryFileService) CheckCitiesWithIPLibraryFileId(ctx context.Context, req *pb.CheckCitiesWithIPLibraryFileIdRequest) (*pb.CheckCitiesWithIPLibraryFileIdResponse, error) {
 | 
				
			||||||
 | 
						_, err := this.ValidateAdmin(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cities, err := models.SharedIPLibraryFileDAO.FindLibraryFileCities(tx, req.IpLibraryFileId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var countryMap = map[string]int64{}            // countryName => countryId
 | 
				
			||||||
 | 
						var provinceMap = map[string]int64{}           // countryId_provinceName => provinceId
 | 
				
			||||||
 | 
						var provinceNamesMap = map[int64][][3]string{} // provinceId => [][3]{countryName, provinceName, cityName}
 | 
				
			||||||
 | 
						var provinceIds = []int64{}
 | 
				
			||||||
 | 
						for _, city := range cities {
 | 
				
			||||||
 | 
							var countryName = city[0]
 | 
				
			||||||
 | 
							var provinceName = city[1]
 | 
				
			||||||
 | 
							var cityName = city[2]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							countryId, ok := countryMap[countryName]
 | 
				
			||||||
 | 
							if !ok {
 | 
				
			||||||
 | 
								countryId, err = regions.SharedRegionCountryDAO.FindCountryIdWithName(tx, countryName)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							countryMap[countryName] = countryId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var key = types.String(countryId) + "_" + provinceName
 | 
				
			||||||
 | 
							provinceId, ok := provinceMap[key]
 | 
				
			||||||
 | 
							if ok {
 | 
				
			||||||
 | 
								provinceNamesMap[provinceId] = append(provinceNamesMap[provinceId], [3]string{countryName, provinceName, cityName})
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								provinceId, err := regions.SharedRegionProvinceDAO.FindProvinceIdWithName(tx, countryId, provinceName)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								provinceMap[key] = provinceId
 | 
				
			||||||
 | 
								provinceNamesMap[provinceId] = append(provinceNamesMap[provinceId], [3]string{countryName, provinceName, cityName})
 | 
				
			||||||
 | 
								if provinceId > 0 {
 | 
				
			||||||
 | 
									provinceIds = append(provinceIds, provinceId)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var pbMissingCities = []*pb.CheckCitiesWithIPLibraryFileIdResponse_MissingCity{}
 | 
				
			||||||
 | 
						for _, provinceId := range provinceIds {
 | 
				
			||||||
 | 
							allCities, err := regions.SharedRegionCityDAO.FindAllEnabledCitiesWithProvinceId(tx, provinceId)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, city := range provinceNamesMap[provinceId] {
 | 
				
			||||||
 | 
								var countryName = city[0]
 | 
				
			||||||
 | 
								var provinceName = city[1]
 | 
				
			||||||
 | 
								var cityName = city[2]
 | 
				
			||||||
 | 
								cityId, err := regions.SharedRegionCityDAO.FindCityIdWithName(tx, provinceId, cityName)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if cityId > 0 {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var similarCities = regions.SharedRegionCityDAO.FindSimilarCities(allCities, cityName, 5)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								var pbMissingCity = &pb.CheckCitiesWithIPLibraryFileIdResponse_MissingCity{}
 | 
				
			||||||
 | 
								pbMissingCity.CountryName = countryName
 | 
				
			||||||
 | 
								pbMissingCity.ProvinceName = provinceName
 | 
				
			||||||
 | 
								pbMissingCity.CityName = cityName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for _, similarCity := range similarCities {
 | 
				
			||||||
 | 
									pbMissingCity.SimilarCities = append(pbMissingCity.SimilarCities, &pb.RegionCity{
 | 
				
			||||||
 | 
										Id:          int64(similarCity.Id),
 | 
				
			||||||
 | 
										Name:        similarCity.Name,
 | 
				
			||||||
 | 
										DisplayName: similarCity.DisplayName(),
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								pbMissingCities = append(pbMissingCities, pbMissingCity)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.CheckCitiesWithIPLibraryFileIdResponse{MissingCities: pbMissingCities}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CheckProvidersWithIPLibraryFileId 检查ISP运营商
 | 
				
			||||||
 | 
					func (this *IPLibraryFileService) CheckProvidersWithIPLibraryFileId(ctx context.Context, req *pb.CheckProvidersWithIPLibraryFileIdRequest) (*pb.CheckProvidersWithIPLibraryFileIdResponse, error) {
 | 
				
			||||||
 | 
						_, err := this.ValidateAdmin(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						allProviders, err := regions.SharedRegionProviderDAO.FindAllEnabledProviders(tx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						providerNames, err := models.SharedIPLibraryFileDAO.FindLibraryFileProviders(tx, req.IpLibraryFileId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var pbMissingProviders = []*pb.CheckProvidersWithIPLibraryFileIdResponse_MissingProvider{}
 | 
				
			||||||
 | 
						for _, providerName := range providerNames {
 | 
				
			||||||
 | 
							if len(providerName) == 0 {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 检查是否存在
 | 
				
			||||||
 | 
							providerId, err := regions.SharedRegionProviderDAO.FindProviderIdWithName(tx, providerName)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if providerId > 0 {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var pbMissingProvider = &pb.CheckProvidersWithIPLibraryFileIdResponse_MissingProvider{
 | 
				
			||||||
 | 
								ProviderName:     providerName,
 | 
				
			||||||
 | 
								SimilarProviders: nil,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 查找相似
 | 
				
			||||||
 | 
							var similarProviders = regions.SharedRegionProviderDAO.FindSimilarProviders(allProviders, providerName, 5)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, similarProvider := range similarProviders {
 | 
				
			||||||
 | 
								pbMissingProvider.SimilarProviders = append(pbMissingProvider.SimilarProviders, &pb.RegionProvider{
 | 
				
			||||||
 | 
									Id:          int64(similarProvider.Id),
 | 
				
			||||||
 | 
									Name:        similarProvider.Name,
 | 
				
			||||||
 | 
									DisplayName: similarProvider.DisplayName(),
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pbMissingProviders = append(pbMissingProviders, pbMissingProvider)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.CheckProvidersWithIPLibraryFileIdResponse{
 | 
				
			||||||
 | 
							MissingProviders: pbMissingProviders,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GenerateIPLibraryFile 生成IP库文件
 | 
				
			||||||
 | 
					func (this *IPLibraryFileService) GenerateIPLibraryFile(ctx context.Context, req *pb.GenerateIPLibraryFileRequest) (*pb.RPCSuccess, error) {
 | 
				
			||||||
 | 
						_, err := this.ValidateAdmin(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						err = models.SharedIPLibraryFileDAO.GenerateIPLibrary(tx, req.IpLibraryFileId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return this.Success()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -14,6 +14,7 @@ type RegionCityService struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindAllEnabledRegionCities 查找所有城市
 | 
					// FindAllEnabledRegionCities 查找所有城市
 | 
				
			||||||
 | 
					// Deprecated
 | 
				
			||||||
func (this *RegionCityService) FindAllEnabledRegionCities(ctx context.Context, req *pb.FindAllEnabledRegionCitiesRequest) (*pb.FindAllEnabledRegionCitiesResponse, error) {
 | 
					func (this *RegionCityService) FindAllEnabledRegionCities(ctx context.Context, req *pb.FindAllEnabledRegionCitiesRequest) (*pb.FindAllEnabledRegionCitiesResponse, error) {
 | 
				
			||||||
	_, _, err := this.ValidateNodeId(ctx)
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -51,6 +52,7 @@ func (this *RegionCityService) FindAllEnabledRegionCities(ctx context.Context, r
 | 
				
			|||||||
				Id:          int64(province.Id),
 | 
									Id:          int64(province.Id),
 | 
				
			||||||
				Name:        province.Name,
 | 
									Name:        province.Name,
 | 
				
			||||||
				Codes:       province.DecodeCodes(),
 | 
									Codes:       province.DecodeCodes(),
 | 
				
			||||||
 | 
									DisplayName: province.DisplayName(),
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -60,6 +62,9 @@ func (this *RegionCityService) FindAllEnabledRegionCities(ctx context.Context, r
 | 
				
			|||||||
			Codes:            city.DecodeCodes(),
 | 
								Codes:            city.DecodeCodes(),
 | 
				
			||||||
			RegionProvinceId: int64(city.ProvinceId),
 | 
								RegionProvinceId: int64(city.ProvinceId),
 | 
				
			||||||
			RegionProvince:   pbProvince,
 | 
								RegionProvince:   pbProvince,
 | 
				
			||||||
 | 
								CustomName:       city.CustomName,
 | 
				
			||||||
 | 
								CustomCodes:      city.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName:      city.DisplayName(),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -68,7 +73,106 @@ func (this *RegionCityService) FindAllEnabledRegionCities(ctx context.Context, r
 | 
				
			|||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindAllRegionCities 查找所有城市
 | 
				
			||||||
 | 
					func (this *RegionCityService) FindAllRegionCities(ctx context.Context, req *pb.FindAllRegionCitiesRequest) (*pb.FindAllRegionCitiesResponse, error) {
 | 
				
			||||||
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						cities, err := regions.SharedRegionCityDAO.FindAllEnabledCities(tx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var pbCities = []*pb.RegionCity{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var provincesMap = map[int64]*regions.RegionProvince{} // provinceId => RegionProvince
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, city := range cities {
 | 
				
			||||||
 | 
							var provinceId = int64(city.ProvinceId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var pbProvince = &pb.RegionProvince{Id: provinceId}
 | 
				
			||||||
 | 
							if req.IncludeRegionProvince {
 | 
				
			||||||
 | 
								province, ok := provincesMap[provinceId]
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									province, err = regions.SharedRegionProvinceDAO.FindEnabledRegionProvince(tx, provinceId)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return nil, err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if province == nil {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									provincesMap[provinceId] = province
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								pbProvince = &pb.RegionProvince{
 | 
				
			||||||
 | 
									Id:          int64(province.Id),
 | 
				
			||||||
 | 
									Name:        province.Name,
 | 
				
			||||||
 | 
									Codes:       province.DecodeCodes(),
 | 
				
			||||||
 | 
									CustomName:  province.CustomName,
 | 
				
			||||||
 | 
									CustomCodes: province.DecodeCustomCodes(),
 | 
				
			||||||
 | 
									DisplayName: province.DisplayName(),
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pbCities = append(pbCities, &pb.RegionCity{
 | 
				
			||||||
 | 
								Id:               int64(city.Id),
 | 
				
			||||||
 | 
								Name:             city.Name,
 | 
				
			||||||
 | 
								Codes:            city.DecodeCodes(),
 | 
				
			||||||
 | 
								RegionProvinceId: int64(city.ProvinceId),
 | 
				
			||||||
 | 
								RegionProvince:   pbProvince,
 | 
				
			||||||
 | 
								CustomName:       city.CustomName,
 | 
				
			||||||
 | 
								CustomCodes:      city.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName:      city.DisplayName(),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.FindAllRegionCitiesResponse{
 | 
				
			||||||
 | 
							RegionCities: pbCities,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindAllRegionCitiesWithRegionProvinceId 查找某个省份的所有城市
 | 
				
			||||||
 | 
					func (this *RegionCityService) FindAllRegionCitiesWithRegionProvinceId(ctx context.Context, req *pb.FindAllRegionCitiesWithRegionProvinceIdRequest) (*pb.FindAllRegionCitiesWithRegionProvinceIdResponse, error) {
 | 
				
			||||||
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						cities, err := regions.SharedRegionCityDAO.FindAllEnabledCitiesWithProvinceId(tx, req.RegionProvinceId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var pbCities = []*pb.RegionCity{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, city := range cities {
 | 
				
			||||||
 | 
							var provinceId = int64(city.ProvinceId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var pbProvince = &pb.RegionProvince{Id: provinceId}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pbCities = append(pbCities, &pb.RegionCity{
 | 
				
			||||||
 | 
								Id:               int64(city.Id),
 | 
				
			||||||
 | 
								Name:             city.Name,
 | 
				
			||||||
 | 
								Codes:            city.DecodeCodes(),
 | 
				
			||||||
 | 
								RegionProvinceId: int64(city.ProvinceId),
 | 
				
			||||||
 | 
								RegionProvince:   pbProvince,
 | 
				
			||||||
 | 
								CustomName:       city.CustomName,
 | 
				
			||||||
 | 
								CustomCodes:      city.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName:      city.DisplayName(),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.FindAllRegionCitiesWithRegionProvinceIdResponse{
 | 
				
			||||||
 | 
							RegionCities: pbCities,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindEnabledRegionCity 查找单个城市信息
 | 
					// FindEnabledRegionCity 查找单个城市信息
 | 
				
			||||||
 | 
					// Deprecated
 | 
				
			||||||
func (this *RegionCityService) FindEnabledRegionCity(ctx context.Context, req *pb.FindEnabledRegionCityRequest) (*pb.FindEnabledRegionCityResponse, error) {
 | 
					func (this *RegionCityService) FindEnabledRegionCity(ctx context.Context, req *pb.FindEnabledRegionCityRequest) (*pb.FindEnabledRegionCityResponse, error) {
 | 
				
			||||||
	_, _, err := this.ValidateNodeId(ctx)
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -92,6 +196,55 @@ func (this *RegionCityService) FindEnabledRegionCity(ctx context.Context, req *p
 | 
				
			|||||||
			Name:             city.Name,
 | 
								Name:             city.Name,
 | 
				
			||||||
			Codes:            city.DecodeCodes(),
 | 
								Codes:            city.DecodeCodes(),
 | 
				
			||||||
			RegionProvinceId: int64(city.ProvinceId),
 | 
								RegionProvinceId: int64(city.ProvinceId),
 | 
				
			||||||
 | 
								CustomName:       city.CustomName,
 | 
				
			||||||
 | 
								CustomCodes:      city.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName:      city.DisplayName(),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindRegionCity 查找单个城市信息
 | 
				
			||||||
 | 
					func (this *RegionCityService) FindRegionCity(ctx context.Context, req *pb.FindRegionCityRequest) (*pb.FindRegionCityResponse, error) {
 | 
				
			||||||
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						city, err := regions.SharedRegionCityDAO.FindEnabledRegionCity(tx, req.RegionCityId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if city == nil {
 | 
				
			||||||
 | 
							return &pb.FindRegionCityResponse{
 | 
				
			||||||
 | 
								RegionCity: nil,
 | 
				
			||||||
 | 
							}, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.FindRegionCityResponse{
 | 
				
			||||||
 | 
							RegionCity: &pb.RegionCity{
 | 
				
			||||||
 | 
								Id:               int64(city.Id),
 | 
				
			||||||
 | 
								Name:             city.Name,
 | 
				
			||||||
 | 
								Codes:            city.DecodeCodes(),
 | 
				
			||||||
 | 
								RegionProvinceId: int64(city.ProvinceId),
 | 
				
			||||||
 | 
								CustomName:       city.CustomName,
 | 
				
			||||||
 | 
								CustomCodes:      city.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName:      city.DisplayName(),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UpdateRegionCityCustom 修改城市定制信息
 | 
				
			||||||
 | 
					func (this *RegionCityService) UpdateRegionCityCustom(ctx context.Context, req *pb.UpdateRegionCityCustomRequest) (*pb.RPCSuccess, error) {
 | 
				
			||||||
 | 
						_, err := this.ValidateAdmin(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						err = regions.SharedRegionCityDAO.UpdateCityCustom(tx, req.RegionCityId, req.CustomName, req.CustomCodes)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return this.Success()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@ type RegionCountryService struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindAllEnabledRegionCountries 查找所有的国家列表
 | 
					// FindAllEnabledRegionCountries 查找所有的国家列表
 | 
				
			||||||
 | 
					// Deprecated
 | 
				
			||||||
func (this *RegionCountryService) FindAllEnabledRegionCountries(ctx context.Context, req *pb.FindAllEnabledRegionCountriesRequest) (*pb.FindAllEnabledRegionCountriesResponse, error) {
 | 
					func (this *RegionCountryService) FindAllEnabledRegionCountries(ctx context.Context, req *pb.FindAllEnabledRegionCountriesRequest) (*pb.FindAllEnabledRegionCountriesResponse, error) {
 | 
				
			||||||
	// 校验请求
 | 
						// 校验请求
 | 
				
			||||||
	_, _, err := this.ValidateNodeId(ctx)
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
@@ -43,6 +44,9 @@ func (this *RegionCountryService) FindAllEnabledRegionCountries(ctx context.Cont
 | 
				
			|||||||
			Name:        country.Name,
 | 
								Name:        country.Name,
 | 
				
			||||||
			Codes:       country.DecodeCodes(),
 | 
								Codes:       country.DecodeCodes(),
 | 
				
			||||||
			Pinyin:      pinyinStrings,
 | 
								Pinyin:      pinyinStrings,
 | 
				
			||||||
 | 
								CustomName:  country.CustomName,
 | 
				
			||||||
 | 
								CustomCodes: country.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName: country.DisplayName(),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return &pb.FindAllEnabledRegionCountriesResponse{
 | 
						return &pb.FindAllEnabledRegionCountriesResponse{
 | 
				
			||||||
@@ -51,6 +55,7 @@ func (this *RegionCountryService) FindAllEnabledRegionCountries(ctx context.Cont
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindEnabledRegionCountry 查找单个国家信息
 | 
					// FindEnabledRegionCountry 查找单个国家信息
 | 
				
			||||||
 | 
					// Deprecated
 | 
				
			||||||
func (this *RegionCountryService) FindEnabledRegionCountry(ctx context.Context, req *pb.FindEnabledRegionCountryRequest) (*pb.FindEnabledRegionCountryResponse, error) {
 | 
					func (this *RegionCountryService) FindEnabledRegionCountry(ctx context.Context, req *pb.FindEnabledRegionCountryRequest) (*pb.FindEnabledRegionCountryResponse, error) {
 | 
				
			||||||
	// 校验请求
 | 
						// 校验请求
 | 
				
			||||||
	_, _, err := this.ValidateNodeId(ctx)
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
@@ -72,5 +77,92 @@ func (this *RegionCountryService) FindEnabledRegionCountry(ctx context.Context,
 | 
				
			|||||||
		Id:          int64(country.Id),
 | 
							Id:          int64(country.Id),
 | 
				
			||||||
		Name:        country.Name,
 | 
							Name:        country.Name,
 | 
				
			||||||
		Codes:       country.DecodeCodes(),
 | 
							Codes:       country.DecodeCodes(),
 | 
				
			||||||
 | 
							CustomName:  country.CustomName,
 | 
				
			||||||
 | 
							CustomCodes: country.DecodeCustomCodes(),
 | 
				
			||||||
 | 
							DisplayName: country.DisplayName(),
 | 
				
			||||||
	}}, nil
 | 
						}}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindAllRegionCountries 查找所有的国家列表
 | 
				
			||||||
 | 
					func (this *RegionCountryService) FindAllRegionCountries(ctx context.Context, req *pb.FindAllRegionCountriesRequest) (*pb.FindAllRegionCountriesResponse, error) {
 | 
				
			||||||
 | 
						// 校验请求
 | 
				
			||||||
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						countries, err := regions.SharedRegionCountryDAO.FindAllEnabledCountriesOrderByPinyin(tx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result = []*pb.RegionCountry{}
 | 
				
			||||||
 | 
						for _, country := range countries {
 | 
				
			||||||
 | 
							pinyinStrings := []string{}
 | 
				
			||||||
 | 
							err = json.Unmarshal(country.Pinyin, &pinyinStrings)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(pinyinStrings) == 0 {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							result = append(result, &pb.RegionCountry{
 | 
				
			||||||
 | 
								Id:          int64(country.Id),
 | 
				
			||||||
 | 
								Name:        country.Name,
 | 
				
			||||||
 | 
								Codes:       country.DecodeCodes(),
 | 
				
			||||||
 | 
								Pinyin:      pinyinStrings,
 | 
				
			||||||
 | 
								CustomName:  country.CustomName,
 | 
				
			||||||
 | 
								CustomCodes: country.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName: country.DisplayName(),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &pb.FindAllRegionCountriesResponse{
 | 
				
			||||||
 | 
							RegionCountries: result,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindRegionCountry 查找单个国家信息
 | 
				
			||||||
 | 
					func (this *RegionCountryService) FindRegionCountry(ctx context.Context, req *pb.FindRegionCountryRequest) (*pb.FindRegionCountryResponse, error) {
 | 
				
			||||||
 | 
						// 校验请求
 | 
				
			||||||
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						country, err := regions.SharedRegionCountryDAO.FindEnabledRegionCountry(tx, req.RegionCountryId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if country == nil {
 | 
				
			||||||
 | 
							return &pb.FindRegionCountryResponse{RegionCountry: nil}, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.FindRegionCountryResponse{RegionCountry: &pb.RegionCountry{
 | 
				
			||||||
 | 
							Id:          int64(country.Id),
 | 
				
			||||||
 | 
							Name:        country.Name,
 | 
				
			||||||
 | 
							Codes:       country.DecodeCodes(),
 | 
				
			||||||
 | 
							CustomName:  country.CustomName,
 | 
				
			||||||
 | 
							CustomCodes: country.DecodeCustomCodes(),
 | 
				
			||||||
 | 
							DisplayName: country.DisplayName(),
 | 
				
			||||||
 | 
						}}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UpdateRegionCountryCustom 修改城市定制信息
 | 
				
			||||||
 | 
					func (this *RegionCountryService) UpdateRegionCountryCustom(ctx context.Context, req *pb.UpdateRegionCountryCustomRequest) (*pb.RPCSuccess, error) {
 | 
				
			||||||
 | 
						_, err := this.ValidateAdmin(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						err = regions.SharedRegionCountryDAO.UpdateCountryCustom(tx, req.RegionCountryId, req.CustomName, req.CustomCodes)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return this.Success()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@ type RegionProviderService struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindAllEnabledRegionProviders 查找所有ISP
 | 
					// FindAllEnabledRegionProviders 查找所有ISP
 | 
				
			||||||
 | 
					// Deprecated
 | 
				
			||||||
func (this *RegionProviderService) FindAllEnabledRegionProviders(ctx context.Context, req *pb.FindAllEnabledRegionProvidersRequest) (*pb.FindAllEnabledRegionProvidersResponse, error) {
 | 
					func (this *RegionProviderService) FindAllEnabledRegionProviders(ctx context.Context, req *pb.FindAllEnabledRegionProvidersRequest) (*pb.FindAllEnabledRegionProvidersResponse, error) {
 | 
				
			||||||
	_, _, err := this.ValidateNodeId(ctx)
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -32,6 +33,9 @@ func (this *RegionProviderService) FindAllEnabledRegionProviders(ctx context.Con
 | 
				
			|||||||
			Id:          int64(provider.Id),
 | 
								Id:          int64(provider.Id),
 | 
				
			||||||
			Name:        provider.Name,
 | 
								Name:        provider.Name,
 | 
				
			||||||
			Codes:       provider.DecodeCodes(),
 | 
								Codes:       provider.DecodeCodes(),
 | 
				
			||||||
 | 
								CustomName:  provider.CustomName,
 | 
				
			||||||
 | 
								CustomCodes: provider.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName: provider.DisplayName(),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -41,6 +45,7 @@ func (this *RegionProviderService) FindAllEnabledRegionProviders(ctx context.Con
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindEnabledRegionProvider 查找单个ISP信息
 | 
					// FindEnabledRegionProvider 查找单个ISP信息
 | 
				
			||||||
 | 
					// Deprecated
 | 
				
			||||||
func (this *RegionProviderService) FindEnabledRegionProvider(ctx context.Context, req *pb.FindEnabledRegionProviderRequest) (*pb.FindEnabledRegionProviderResponse, error) {
 | 
					func (this *RegionProviderService) FindEnabledRegionProvider(ctx context.Context, req *pb.FindEnabledRegionProviderRequest) (*pb.FindEnabledRegionProviderResponse, error) {
 | 
				
			||||||
	_, _, err := this.ValidateNodeId(ctx)
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -63,6 +68,84 @@ func (this *RegionProviderService) FindEnabledRegionProvider(ctx context.Context
 | 
				
			|||||||
			Id:          int64(provider.Id),
 | 
								Id:          int64(provider.Id),
 | 
				
			||||||
			Name:        provider.Name,
 | 
								Name:        provider.Name,
 | 
				
			||||||
			Codes:       provider.DecodeCodes(),
 | 
								Codes:       provider.DecodeCodes(),
 | 
				
			||||||
 | 
								CustomName:  provider.CustomName,
 | 
				
			||||||
 | 
								CustomCodes: provider.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName: provider.DisplayName(),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindAllRegionProviders 查找所有ISP
 | 
				
			||||||
 | 
					func (this *RegionProviderService) FindAllRegionProviders(ctx context.Context, req *pb.FindAllRegionProvidersRequest) (*pb.FindAllRegionProvidersResponse, error) {
 | 
				
			||||||
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						providers, err := regions.SharedRegionProviderDAO.FindAllEnabledProviders(tx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var pbProviders = []*pb.RegionProvider{}
 | 
				
			||||||
 | 
						for _, provider := range providers {
 | 
				
			||||||
 | 
							pbProviders = append(pbProviders, &pb.RegionProvider{
 | 
				
			||||||
 | 
								Id:          int64(provider.Id),
 | 
				
			||||||
 | 
								Name:        provider.Name,
 | 
				
			||||||
 | 
								Codes:       provider.DecodeCodes(),
 | 
				
			||||||
 | 
								CustomName:  provider.CustomName,
 | 
				
			||||||
 | 
								CustomCodes: provider.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName: provider.DisplayName(),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.FindAllRegionProvidersResponse{
 | 
				
			||||||
 | 
							RegionProviders: pbProviders,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindRegionProvider 查找单个ISP信息
 | 
				
			||||||
 | 
					func (this *RegionProviderService) FindRegionProvider(ctx context.Context, req *pb.FindRegionProviderRequest) (*pb.FindRegionProviderResponse, error) {
 | 
				
			||||||
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						provider, err := regions.SharedRegionProviderDAO.FindEnabledRegionProvider(tx, req.RegionProviderId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if provider == nil {
 | 
				
			||||||
 | 
							return &pb.FindRegionProviderResponse{
 | 
				
			||||||
 | 
								RegionProvider: nil,
 | 
				
			||||||
 | 
							}, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.FindRegionProviderResponse{
 | 
				
			||||||
 | 
							RegionProvider: &pb.RegionProvider{
 | 
				
			||||||
 | 
								Id:          int64(provider.Id),
 | 
				
			||||||
 | 
								Name:        provider.Name,
 | 
				
			||||||
 | 
								Codes:       provider.DecodeCodes(),
 | 
				
			||||||
 | 
								CustomName:  provider.CustomName,
 | 
				
			||||||
 | 
								CustomCodes: provider.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName: provider.DisplayName(),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UpdateRegionProviderCustom 修改城市定制信息
 | 
				
			||||||
 | 
					func (this *RegionProviderService) UpdateRegionProviderCustom(ctx context.Context, req *pb.UpdateRegionProviderCustomRequest) (*pb.RPCSuccess, error) {
 | 
				
			||||||
 | 
						_, err := this.ValidateAdmin(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						err = regions.SharedRegionProviderDAO.UpdateProviderCustom(tx, req.RegionProviderId, req.CustomName, req.CustomCodes)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return this.Success()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ type RegionProvinceService struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindAllEnabledRegionProvincesWithCountryId 查找所有省份
 | 
					// FindAllEnabledRegionProvincesWithCountryId 查找所有省份
 | 
				
			||||||
 | 
					// Deprecated
 | 
				
			||||||
func (this *RegionProvinceService) FindAllEnabledRegionProvincesWithCountryId(ctx context.Context, req *pb.FindAllEnabledRegionProvincesWithCountryIdRequest) (*pb.FindAllEnabledRegionProvincesWithCountryIdResponse, error) {
 | 
					func (this *RegionProvinceService) FindAllEnabledRegionProvincesWithCountryId(ctx context.Context, req *pb.FindAllEnabledRegionProvincesWithCountryIdRequest) (*pb.FindAllEnabledRegionProvincesWithCountryIdResponse, error) {
 | 
				
			||||||
	// 校验请求
 | 
						// 校验请求
 | 
				
			||||||
	_, _, err := this.ValidateNodeId(ctx)
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
@@ -31,6 +32,9 @@ func (this *RegionProvinceService) FindAllEnabledRegionProvincesWithCountryId(ct
 | 
				
			|||||||
			Id:          int64(province.Id),
 | 
								Id:          int64(province.Id),
 | 
				
			||||||
			Name:        province.Name,
 | 
								Name:        province.Name,
 | 
				
			||||||
			Codes:       province.DecodeCodes(),
 | 
								Codes:       province.DecodeCodes(),
 | 
				
			||||||
 | 
								CustomName:  province.CustomName,
 | 
				
			||||||
 | 
								CustomCodes: province.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName: province.DisplayName(),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -40,6 +44,7 @@ func (this *RegionProvinceService) FindAllEnabledRegionProvincesWithCountryId(ct
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindEnabledRegionProvince 查找单个省份信息
 | 
					// FindEnabledRegionProvince 查找单个省份信息
 | 
				
			||||||
 | 
					// Deprecated
 | 
				
			||||||
func (this *RegionProvinceService) FindEnabledRegionProvince(ctx context.Context, req *pb.FindEnabledRegionProvinceRequest) (*pb.FindEnabledRegionProvinceResponse, error) {
 | 
					func (this *RegionProvinceService) FindEnabledRegionProvince(ctx context.Context, req *pb.FindEnabledRegionProvinceRequest) (*pb.FindEnabledRegionProvinceResponse, error) {
 | 
				
			||||||
	// 校验请求
 | 
						// 校验请求
 | 
				
			||||||
	_, _, err := this.ValidateNodeId(ctx)
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
@@ -62,6 +67,85 @@ func (this *RegionProvinceService) FindEnabledRegionProvince(ctx context.Context
 | 
				
			|||||||
			Id:          int64(province.Id),
 | 
								Id:          int64(province.Id),
 | 
				
			||||||
			Name:        province.Name,
 | 
								Name:        province.Name,
 | 
				
			||||||
			Codes:       province.DecodeCodes(),
 | 
								Codes:       province.DecodeCodes(),
 | 
				
			||||||
 | 
								CustomName:  province.CustomName,
 | 
				
			||||||
 | 
								CustomCodes: province.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName: province.DisplayName(),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindAllRegionProvincesWithRegionCountryId 查找所有省份
 | 
				
			||||||
 | 
					func (this *RegionProvinceService) FindAllRegionProvincesWithRegionCountryId(ctx context.Context, req *pb.FindAllRegionProvincesWithRegionCountryIdRequest) (*pb.FindAllRegionProvincesWithRegionCountryIdResponse, error) {
 | 
				
			||||||
 | 
						// 校验请求
 | 
				
			||||||
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						provinces, err := regions.SharedRegionProvinceDAO.FindAllEnabledProvincesWithCountryId(tx, req.RegionCountryId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						result := []*pb.RegionProvince{}
 | 
				
			||||||
 | 
						for _, province := range provinces {
 | 
				
			||||||
 | 
							result = append(result, &pb.RegionProvince{
 | 
				
			||||||
 | 
								Id:          int64(province.Id),
 | 
				
			||||||
 | 
								Name:        province.Name,
 | 
				
			||||||
 | 
								Codes:       province.DecodeCodes(),
 | 
				
			||||||
 | 
								CustomName:  province.CustomName,
 | 
				
			||||||
 | 
								CustomCodes: province.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName: province.DisplayName(),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.FindAllRegionProvincesWithRegionCountryIdResponse{
 | 
				
			||||||
 | 
							RegionProvinces: result,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindRegionProvince 查找单个省份信息
 | 
				
			||||||
 | 
					func (this *RegionProvinceService) FindRegionProvince(ctx context.Context, req *pb.FindRegionProvinceRequest) (*pb.FindRegionProvinceResponse, error) {
 | 
				
			||||||
 | 
						// 校验请求
 | 
				
			||||||
 | 
						_, _, err := this.ValidateNodeId(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						province, err := regions.SharedRegionProvinceDAO.FindEnabledRegionProvince(tx, req.RegionProvinceId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if province == nil {
 | 
				
			||||||
 | 
							return &pb.FindRegionProvinceResponse{RegionProvince: nil}, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.FindRegionProvinceResponse{
 | 
				
			||||||
 | 
							RegionProvince: &pb.RegionProvince{
 | 
				
			||||||
 | 
								Id:          int64(province.Id),
 | 
				
			||||||
 | 
								Name:        province.Name,
 | 
				
			||||||
 | 
								Codes:       province.DecodeCodes(),
 | 
				
			||||||
 | 
								CustomName:  province.CustomName,
 | 
				
			||||||
 | 
								CustomCodes: province.DecodeCustomCodes(),
 | 
				
			||||||
 | 
								DisplayName: province.DisplayName(),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UpdateRegionProvinceCustom 修改城市定制信息
 | 
				
			||||||
 | 
					func (this *RegionProvinceService) UpdateRegionProvinceCustom(ctx context.Context, req *pb.UpdateRegionProvinceCustomRequest) (*pb.RPCSuccess, error) {
 | 
				
			||||||
 | 
						_, err := this.ValidateAdmin(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						err = regions.SharedRegionProvinceDAO.UpdateProvinceCustom(tx, req.RegionProvinceId, req.CustomName, req.CustomCodes)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return this.Success()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -4,6 +4,7 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeAPI/internal/errors"
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/errors"
 | 
				
			||||||
	"github.com/iwind/TeaGo/dbs"
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/lists"
 | 
				
			||||||
	"github.com/iwind/TeaGo/types"
 | 
						"github.com/iwind/TeaGo/types"
 | 
				
			||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@@ -13,18 +14,22 @@ var recordsTables = []*SQLRecordsTable{
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		TableName:    "edgeRegionCities",
 | 
							TableName:    "edgeRegionCities",
 | 
				
			||||||
		UniqueFields: []string{"name", "provinceId"},
 | 
							UniqueFields: []string{"name", "provinceId"},
 | 
				
			||||||
 | 
							ExceptFields: []string{"customName", "customCodes"},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		TableName:    "edgeRegionCountries",
 | 
							TableName:    "edgeRegionCountries",
 | 
				
			||||||
		UniqueFields: []string{"name"},
 | 
							UniqueFields: []string{"name"},
 | 
				
			||||||
 | 
							ExceptFields: []string{"customName", "customCodes"},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		TableName:    "edgeRegionProvinces",
 | 
							TableName:    "edgeRegionProvinces",
 | 
				
			||||||
		UniqueFields: []string{"name", "countryId"},
 | 
							UniqueFields: []string{"name", "countryId"},
 | 
				
			||||||
 | 
							ExceptFields: []string{"customName", "customCodes"},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		TableName:    "edgeRegionProviders",
 | 
							TableName:    "edgeRegionProviders",
 | 
				
			||||||
		UniqueFields: []string{"name"},
 | 
							UniqueFields: []string{"name"},
 | 
				
			||||||
 | 
							ExceptFields: []string{"customName", "customCodes"},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -96,8 +101,14 @@ func (this *SQLDump) Dump(db *dbs.DB) (result *SQLDumpResult, err error) {
 | 
				
			|||||||
					Id:           one.GetInt64("id"),
 | 
										Id:           one.GetInt64("id"),
 | 
				
			||||||
					Values:       map[string]string{},
 | 
										Values:       map[string]string{},
 | 
				
			||||||
					UniqueFields: recordsTable.UniqueFields,
 | 
										UniqueFields: recordsTable.UniqueFields,
 | 
				
			||||||
 | 
										ExceptFields: recordsTable.ExceptFields,
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				for k, v := range one {
 | 
									for k, v := range one {
 | 
				
			||||||
 | 
										// 需要排除的字段
 | 
				
			||||||
 | 
										if lists.ContainsString(record.ExceptFields, k) {
 | 
				
			||||||
 | 
											continue
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					record.Values[k] = types.String(v)
 | 
										record.Values[k] = types.String(v)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				records = append(records, record)
 | 
									records = append(records, record)
 | 
				
			||||||
@@ -233,9 +244,9 @@ func (this *SQLDump) Apply(db *dbs.DB, newResult *SQLDumpResult, showLog bool) (
 | 
				
			|||||||
		// 对比记录
 | 
							// 对比记录
 | 
				
			||||||
		// +
 | 
							// +
 | 
				
			||||||
		for _, record := range newTable.Records {
 | 
							for _, record := range newTable.Records {
 | 
				
			||||||
			queryArgs := []string{}
 | 
								var queryArgs = []string{}
 | 
				
			||||||
			queryValues := []interface{}{}
 | 
								var queryValues = []interface{}{}
 | 
				
			||||||
			valueStrings := []string{}
 | 
								var valueStrings = []string{}
 | 
				
			||||||
			for _, field := range record.UniqueFields {
 | 
								for _, field := range record.UniqueFields {
 | 
				
			||||||
				queryArgs = append(queryArgs, field+"=?")
 | 
									queryArgs = append(queryArgs, field+"=?")
 | 
				
			||||||
				queryValues = append(queryValues, record.Values[field])
 | 
									queryValues = append(queryValues, record.Values[field])
 | 
				
			||||||
@@ -254,6 +265,11 @@ func (this *SQLDump) Apply(db *dbs.DB, newResult *SQLDumpResult, showLog bool) (
 | 
				
			|||||||
				args := []string{}
 | 
									args := []string{}
 | 
				
			||||||
				values := []interface{}{}
 | 
									values := []interface{}{}
 | 
				
			||||||
				for k, v := range record.Values {
 | 
									for k, v := range record.Values {
 | 
				
			||||||
 | 
										// 需要排除的字段
 | 
				
			||||||
 | 
										if lists.ContainsString(record.ExceptFields, k) {
 | 
				
			||||||
 | 
											continue
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					// ID需要保留,因为各个表格之间需要有对应关系
 | 
										// ID需要保留,因为各个表格之间需要有对应关系
 | 
				
			||||||
					params = append(params, "`"+k+"`")
 | 
										params = append(params, "`"+k+"`")
 | 
				
			||||||
					args = append(args, "?")
 | 
										args = append(args, "?")
 | 
				
			||||||
@@ -274,6 +290,12 @@ func (this *SQLDump) Apply(db *dbs.DB, newResult *SQLDumpResult, showLog bool) (
 | 
				
			|||||||
					if k == "id" {
 | 
										if k == "id" {
 | 
				
			||||||
						continue
 | 
											continue
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// 需要排除的字段
 | 
				
			||||||
 | 
										if lists.ContainsString(record.ExceptFields, k) {
 | 
				
			||||||
 | 
											continue
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					args = append(args, k+"=?")
 | 
										args = append(args, k+"=?")
 | 
				
			||||||
					values = append(values, v)
 | 
										values = append(values, v)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
package setup
 | 
					package setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/lists"
 | 
				
			||||||
	"github.com/iwind/TeaGo/maps"
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
	"github.com/iwind/TeaGo/types"
 | 
						"github.com/iwind/TeaGo/types"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -9,14 +10,22 @@ type SQLRecord struct {
 | 
				
			|||||||
	Id           int64             `json:"id"`
 | 
						Id           int64             `json:"id"`
 | 
				
			||||||
	Values       map[string]string `json:"values"`
 | 
						Values       map[string]string `json:"values"`
 | 
				
			||||||
	UniqueFields []string          `json:"uniqueFields"`
 | 
						UniqueFields []string          `json:"uniqueFields"`
 | 
				
			||||||
 | 
						ExceptFields []string          `json:"exceptFields"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *SQLRecord) ValuesEquals(values maps.Map) bool {
 | 
					func (this *SQLRecord) ValuesEquals(values maps.Map) bool {
 | 
				
			||||||
	for k, v := range values {
 | 
						for k, v := range values {
 | 
				
			||||||
 | 
							// 跳过ID
 | 
				
			||||||
		if k == "id" {
 | 
							if k == "id" {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		vString := types.String(v)
 | 
					
 | 
				
			||||||
 | 
							// 需要排除的字段
 | 
				
			||||||
 | 
							if lists.ContainsString(this.ExceptFields, k) {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var vString = types.String(v)
 | 
				
			||||||
		if this.Values[k] != vString {
 | 
							if this.Values[k] != vString {
 | 
				
			||||||
			return false
 | 
								return false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,4 +3,5 @@ package setup
 | 
				
			|||||||
type SQLRecordsTable struct {
 | 
					type SQLRecordsTable struct {
 | 
				
			||||||
	TableName    string
 | 
						TableName    string
 | 
				
			||||||
	UniqueFields []string
 | 
						UniqueFields []string
 | 
				
			||||||
 | 
						ExceptFields []string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,3 +9,33 @@ func FormatInt64(value int64) string {
 | 
				
			|||||||
func FormatInt(value int) string {
 | 
					func FormatInt(value int) string {
 | 
				
			||||||
	return strconv.Itoa(value)
 | 
						return strconv.Itoa(value)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Max[T int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | float32 | float64](values ...T) T {
 | 
				
			||||||
 | 
						if len(values) == 0 {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var max T
 | 
				
			||||||
 | 
						for index, value := range values {
 | 
				
			||||||
 | 
							if index == 0 {
 | 
				
			||||||
 | 
								max = value
 | 
				
			||||||
 | 
							} else if value > max {
 | 
				
			||||||
 | 
								max = value
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return max
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Min[T int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | float32 | float64](values ...T) T {
 | 
				
			||||||
 | 
						if len(values) == 0 {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var min T
 | 
				
			||||||
 | 
						for index, value := range values {
 | 
				
			||||||
 | 
							if index == 0 {
 | 
				
			||||||
 | 
								min = value
 | 
				
			||||||
 | 
							} else if value < min {
 | 
				
			||||||
 | 
								min = value
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return min
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								internal/utils/numberutils/utils_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								internal/utils/numberutils/utils_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package numberutils_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMax(t *testing.T) {
 | 
				
			||||||
 | 
						t.Log(numberutils.Max[int](1, 2, 3))
 | 
				
			||||||
 | 
						t.Log(numberutils.Max[int32](1, 2, 3))
 | 
				
			||||||
 | 
						t.Log(numberutils.Max[float32](1.2, 2.3, 3.4))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMin(t *testing.T) {
 | 
				
			||||||
 | 
						t.Log(numberutils.Min[int](1, 2, 3))
 | 
				
			||||||
 | 
						t.Log(numberutils.Min[int32](1, 2, 3))
 | 
				
			||||||
 | 
						t.Log(numberutils.Min[float32](1.2, 2.3, 3.4))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,7 +2,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package utils
 | 
					package utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "strings"
 | 
					import (
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SplitStrings 分隔字符串
 | 
					// SplitStrings 分隔字符串
 | 
				
			||||||
// 忽略其中为空的片段
 | 
					// 忽略其中为空的片段
 | 
				
			||||||
@@ -30,3 +32,33 @@ func ContainsStringInsensitive(list []string, search string) bool {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Similar 计算相似度
 | 
				
			||||||
 | 
					// between 0-1
 | 
				
			||||||
 | 
					func Similar(s1 string, s2 string) float32 {
 | 
				
			||||||
 | 
						var r1s = []rune(s1)
 | 
				
			||||||
 | 
						var r2s = []rune(s2)
 | 
				
			||||||
 | 
						var l1 = len(r1s)
 | 
				
			||||||
 | 
						var l2 = len(r2s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if l1 > l2 {
 | 
				
			||||||
 | 
							r1s, r2s = r2s, r1s
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(r1s) == 0 {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var count = 0
 | 
				
			||||||
 | 
						for _, r := range r1s {
 | 
				
			||||||
 | 
							for index, r2 := range r2s {
 | 
				
			||||||
 | 
								if r == r2 {
 | 
				
			||||||
 | 
									count++
 | 
				
			||||||
 | 
									r2s = r2s[index+1:]
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return (float32(count)/float32(l1) + float32(count)/float32(l2)) / 2
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,22 +1,30 @@
 | 
				
			|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
					// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package utils
 | 
					package utils_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils"
 | 
				
			||||||
	"github.com/iwind/TeaGo/assert"
 | 
						"github.com/iwind/TeaGo/assert"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestSplitStrings(t *testing.T) {
 | 
					func TestSplitStrings(t *testing.T) {
 | 
				
			||||||
	t.Log(SplitStrings("a, b, c", ","))
 | 
						t.Log(utils.SplitStrings("a, b, c", ","))
 | 
				
			||||||
	t.Log(SplitStrings("a,      b, c, ", ","))
 | 
						t.Log(utils.SplitStrings("a,      b, c, ", ","))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestContainsStringInsensitive(t *testing.T) {
 | 
					func TestContainsStringInsensitive(t *testing.T) {
 | 
				
			||||||
	var a = assert.NewAssertion(t)
 | 
						var a = assert.NewAssertion(t)
 | 
				
			||||||
	a.IsTrue(ContainsStringInsensitive([]string{"a", "b", "C"}, "A"))
 | 
						a.IsTrue(utils.ContainsStringInsensitive([]string{"a", "b", "C"}, "A"))
 | 
				
			||||||
	a.IsTrue(ContainsStringInsensitive([]string{"a", "b", "C"}, "b"))
 | 
						a.IsTrue(utils.ContainsStringInsensitive([]string{"a", "b", "C"}, "b"))
 | 
				
			||||||
	a.IsTrue(ContainsStringInsensitive([]string{"a", "b", "C"}, "c"))
 | 
						a.IsTrue(utils.ContainsStringInsensitive([]string{"a", "b", "C"}, "c"))
 | 
				
			||||||
	a.IsFalse(ContainsStringInsensitive([]string{"a", "b", "C"}, "d"))
 | 
						a.IsFalse(utils.ContainsStringInsensitive([]string{"a", "b", "C"}, "d"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSimilar(t *testing.T) {
 | 
				
			||||||
 | 
						t.Log(utils.Similar("", ""))
 | 
				
			||||||
 | 
						t.Log(utils.Similar("", "a"))
 | 
				
			||||||
 | 
						t.Log(utils.Similar("abc", "bcd"))
 | 
				
			||||||
 | 
						t.Log(utils.Similar("efgj", "hijk"))
 | 
				
			||||||
 | 
						t.Log(utils.Similar("efgj", "klmn"))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user