mirror of
https://github.com/TeaOSLab/EdgeAPI.git
synced 2025-11-06 01: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
|
||||||
}
|
}
|
||||||
SharedCacheLocker.Lock()
|
if cityId > 0 {
|
||||||
regionCityNameAndIdCacheMap[key] = cityId
|
SharedCacheLocker.Lock()
|
||||||
SharedCacheLocker.Unlock()
|
regionCityNameAndIdCacheMap[key] = cityId
|
||||||
|
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,23 +2,27 @@ 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"` // 代号
|
||||||
State uint8 `field:"state"` // 状态
|
CustomName string `field:"customName"` // 自定义名称
|
||||||
DataId string `field:"dataId"` // 原始数据ID
|
CustomCodes dbs.JSON `field:"customCodes"` // 自定义代号
|
||||||
|
State uint8 `field:"state"` // 状态
|
||||||
|
DataId string `field:"dataId"` // 原始数据ID
|
||||||
}
|
}
|
||||||
|
|
||||||
type RegionCityOperator struct {
|
type RegionCityOperator struct {
|
||||||
Id interface{} // ID
|
Id interface{} // ID
|
||||||
ProvinceId interface{} // 省份ID
|
ProvinceId interface{} // 省份ID
|
||||||
Name interface{} // 名称
|
Name interface{} // 名称
|
||||||
Codes interface{} // 代号
|
Codes interface{} // 代号
|
||||||
State interface{} // 状态
|
CustomName interface{} // 自定义名称
|
||||||
DataId interface{} // 原始数据ID
|
CustomCodes interface{} // 自定义代号
|
||||||
|
State interface{} // 状态
|
||||||
|
DataId interface{} // 原始数据ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRegionCityOperator() *RegionCityOperator {
|
func NewRegionCityOperator() *RegionCityOperator {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
regionCountryIdAndNameCacheMap[id] = name
|
if len(name) > 0 {
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedCacheLocker.Lock()
|
if countryId > 0 {
|
||||||
regionCountryNameAndIdCacheMap[countryName] = countryId
|
SharedCacheLocker.Lock()
|
||||||
SharedCacheLocker.Unlock()
|
regionCountryNameAndIdCacheMap[countryName] = countryId
|
||||||
|
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,23 +2,27 @@ 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"` // 代号
|
||||||
State uint8 `field:"state"` // 状态
|
CustomName string `field:"customName"` // 自定义名称
|
||||||
DataId string `field:"dataId"` // 原始数据ID
|
CustomCodes dbs.JSON `field:"customCodes"` // 自定义代号
|
||||||
Pinyin dbs.JSON `field:"pinyin"` // 拼音
|
State uint8 `field:"state"` // 状态
|
||||||
|
DataId string `field:"dataId"` // 原始数据ID
|
||||||
|
Pinyin dbs.JSON `field:"pinyin"` // 拼音
|
||||||
}
|
}
|
||||||
|
|
||||||
type RegionCountryOperator struct {
|
type RegionCountryOperator struct {
|
||||||
Id interface{} // ID
|
Id interface{} // ID
|
||||||
Name interface{} // 名称
|
Name interface{} // 名称
|
||||||
Codes interface{} // 代号
|
Codes interface{} // 代号
|
||||||
State interface{} // 状态
|
CustomName interface{} // 自定义名称
|
||||||
DataId interface{} // 原始数据ID
|
CustomCodes interface{} // 自定义代号
|
||||||
Pinyin interface{} // 拼音
|
State interface{} // 状态
|
||||||
|
DataId interface{} // 原始数据ID
|
||||||
|
Pinyin interface{} // 拼音
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRegionCountryOperator() *RegionCountryOperator {
|
func NewRegionCountryOperator() *RegionCountryOperator {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedCacheLocker.Lock()
|
if providerId > 0 {
|
||||||
regionProviderNameAndIdCacheMap[providerName] = providerId
|
SharedCacheLocker.Lock()
|
||||||
SharedCacheLocker.Unlock()
|
regionProviderNameAndIdCacheMap[providerName] = providerId
|
||||||
|
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,19 +2,23 @@ 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"` // 代号
|
||||||
State uint8 `field:"state"` // 状态
|
CustomName string `field:"customName"` // 自定义名称
|
||||||
|
CustomCodes dbs.JSON `field:"customCodes"` // 自定义代号
|
||||||
|
State uint8 `field:"state"` // 状态
|
||||||
}
|
}
|
||||||
|
|
||||||
type RegionProviderOperator struct {
|
type RegionProviderOperator struct {
|
||||||
Id interface{} // ID
|
Id interface{} // ID
|
||||||
Name interface{} // 名称
|
Name interface{} // 名称
|
||||||
Codes interface{} // 代号
|
Codes interface{} // 代号
|
||||||
State interface{} // 状态
|
CustomName interface{} // 自定义名称
|
||||||
|
CustomCodes interface{} // 自定义代号
|
||||||
|
State interface{} // 状态
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRegionProviderOperator() *RegionProviderOperator {
|
func NewRegionProviderOperator() *RegionProviderOperator {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
SharedCacheLocker.Lock()
|
if provinceId > 0 {
|
||||||
regionProvinceNameAndIdCacheMap[key] = provinceId
|
SharedCacheLocker.Lock()
|
||||||
SharedCacheLocker.Unlock()
|
regionProvinceNameAndIdCacheMap[key] = provinceId
|
||||||
|
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,23 +2,27 @@ 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"` // 代号
|
||||||
State uint8 `field:"state"` // 状态
|
CustomName string `field:"customName"` // 自定义名称
|
||||||
DataId string `field:"dataId"` // 原始数据ID
|
CustomCodes dbs.JSON `field:"customCodes"` // 自定义代号
|
||||||
|
State uint8 `field:"state"` // 状态
|
||||||
|
DataId string `field:"dataId"` // 原始数据ID
|
||||||
}
|
}
|
||||||
|
|
||||||
type RegionProvinceOperator struct {
|
type RegionProvinceOperator struct {
|
||||||
Id interface{} // ID
|
Id interface{} // ID
|
||||||
CountryId interface{} // 国家ID
|
CountryId interface{} // 国家ID
|
||||||
Name interface{} // 名称
|
Name interface{} // 名称
|
||||||
Codes interface{} // 代号
|
Codes interface{} // 代号
|
||||||
State interface{} // 状态
|
CustomName interface{} // 自定义名称
|
||||||
DataId interface{} // 原始数据ID
|
CustomCodes interface{} // 自定义代号
|
||||||
|
State interface{} // 状态
|
||||||
|
DataId interface{} // 原始数据ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRegionProvinceOperator() *RegionProvinceOperator {
|
func NewRegionProvinceOperator() *RegionProvinceOperator {
|
||||||
|
|||||||
@@ -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 {
|
||||||
@@ -48,9 +49,10 @@ func (this *RegionCityService) FindAllEnabledRegionCities(ctx context.Context, r
|
|||||||
}
|
}
|
||||||
|
|
||||||
pbProvince = &pb.RegionProvince{
|
pbProvince = &pb.RegionProvince{
|
||||||
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)
|
||||||
@@ -39,10 +40,13 @@ func (this *RegionCountryService) FindAllEnabledRegionCountries(ctx context.Cont
|
|||||||
}
|
}
|
||||||
|
|
||||||
result = append(result, &pb.RegionCountry{
|
result = append(result, &pb.RegionCountry{
|
||||||
Id: int64(country.Id),
|
Id: int64(country.Id),
|
||||||
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)
|
||||||
@@ -69,8 +74,95 @@ func (this *RegionCountryService) FindEnabledRegionCountry(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &pb.FindEnabledRegionCountryResponse{RegionCountry: &pb.RegionCountry{
|
return &pb.FindEnabledRegionCountryResponse{RegionCountry: &pb.RegionCountry{
|
||||||
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 {
|
||||||
@@ -29,9 +30,12 @@ func (this *RegionProviderService) FindAllEnabledRegionProviders(ctx context.Con
|
|||||||
var pbProviders = []*pb.RegionProvider{}
|
var pbProviders = []*pb.RegionProvider{}
|
||||||
for _, provider := range providers {
|
for _, provider := range providers {
|
||||||
pbProviders = append(pbProviders, &pb.RegionProvider{
|
pbProviders = append(pbProviders, &pb.RegionProvider{
|
||||||
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 {
|
||||||
@@ -60,9 +65,87 @@ func (this *RegionProviderService) FindEnabledRegionProvider(ctx context.Context
|
|||||||
|
|
||||||
return &pb.FindEnabledRegionProviderResponse{
|
return &pb.FindEnabledRegionProviderResponse{
|
||||||
RegionProvider: &pb.RegionProvider{
|
RegionProvider: &pb.RegionProvider{
|
||||||
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)
|
||||||
@@ -28,9 +29,12 @@ func (this *RegionProvinceService) FindAllEnabledRegionProvincesWithCountryId(ct
|
|||||||
result := []*pb.RegionProvince{}
|
result := []*pb.RegionProvince{}
|
||||||
for _, province := range provinces {
|
for _, province := range provinces {
|
||||||
result = append(result, &pb.RegionProvince{
|
result = append(result, &pb.RegionProvince{
|
||||||
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)
|
||||||
@@ -59,9 +64,88 @@ func (this *RegionProvinceService) FindEnabledRegionProvince(ctx context.Context
|
|||||||
|
|
||||||
return &pb.FindEnabledRegionProvinceResponse{
|
return &pb.FindEnabledRegionProvinceResponse{
|
||||||
RegionProvince: &pb.RegionProvince{
|
RegionProvince: &pb.RegionProvince{
|
||||||
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