Initial commit (code only without large binaries)
This commit is contained in:
172
EdgeUser/internal/web/actions/default/ns/accessLogs/index.go
Normal file
172
EdgeUser/internal/web/actions/default/ns/accessLogs/index.go
Normal file
@@ -0,0 +1,172 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package logs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
RequestId string
|
||||
Keyword string
|
||||
Day string
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
RecordType string
|
||||
}) {
|
||||
day := strings.ReplaceAll(params.Day, "-", "")
|
||||
if !regexp.MustCompile(`^\d{8}$`).MatchString(day) {
|
||||
day = timeutil.Format("Ymd")
|
||||
}
|
||||
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["day"] = day[:4] + "-" + day[4:6] + "-" + day[6:]
|
||||
this.Data["path"] = this.Request.URL.Path
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
this.Data["recordType"] = params.RecordType
|
||||
|
||||
var size = int64(10)
|
||||
|
||||
resp, err := this.RPC().NSAccessLogRPC().ListNSAccessLogs(this.UserContext(), &pb.ListNSAccessLogsRequest{
|
||||
RequestId: params.RequestId,
|
||||
NsClusterId: params.ClusterId,
|
||||
NsNodeId: params.NodeId,
|
||||
NsDomainId: 0,
|
||||
NsRecordId: 0,
|
||||
RecordType: params.RecordType,
|
||||
Size: size,
|
||||
Day: day,
|
||||
Keyword: params.Keyword,
|
||||
Reverse: false,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var ipList = []string{}
|
||||
var nodeIds = []int64{}
|
||||
var domainIds = []int64{}
|
||||
if len(resp.NsAccessLogs) == 0 {
|
||||
this.Data["accessLogs"] = []interface{}{}
|
||||
} else {
|
||||
this.Data["accessLogs"] = resp.NsAccessLogs
|
||||
for _, accessLog := range resp.NsAccessLogs {
|
||||
// IP
|
||||
if len(accessLog.RemoteAddr) > 0 {
|
||||
// 去掉端口
|
||||
ip, _, err := net.SplitHostPort(accessLog.RemoteAddr)
|
||||
if err == nil {
|
||||
accessLog.RemoteAddr = ip
|
||||
if !lists.ContainsString(ipList, ip) {
|
||||
ipList = append(ipList, ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 节点
|
||||
if !lists.ContainsInt64(nodeIds, accessLog.NsNodeId) {
|
||||
nodeIds = append(nodeIds, accessLog.NsNodeId)
|
||||
}
|
||||
|
||||
// 域名
|
||||
if !lists.ContainsInt64(domainIds, accessLog.NsDomainId) {
|
||||
domainIds = append(domainIds, accessLog.NsDomainId)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["hasMore"] = resp.HasMore
|
||||
this.Data["nextRequestId"] = resp.RequestId
|
||||
|
||||
// 上一个requestId
|
||||
this.Data["hasPrev"] = false
|
||||
this.Data["lastRequestId"] = ""
|
||||
if len(params.RequestId) > 0 {
|
||||
this.Data["hasPrev"] = true
|
||||
prevResp, err := this.RPC().NSAccessLogRPC().ListNSAccessLogs(this.UserContext(), &pb.ListNSAccessLogsRequest{
|
||||
RequestId: params.RequestId,
|
||||
NsClusterId: params.ClusterId,
|
||||
NsNodeId: params.NodeId,
|
||||
NsDomainId: 0,
|
||||
NsRecordId: 0,
|
||||
RecordType: params.RecordType,
|
||||
Day: day,
|
||||
Keyword: params.Keyword,
|
||||
Size: size,
|
||||
Reverse: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if int64(len(prevResp.NsAccessLogs)) == size {
|
||||
this.Data["lastRequestId"] = prevResp.RequestId
|
||||
}
|
||||
}
|
||||
|
||||
// 根据IP查询区域
|
||||
this.Data["regions"] = iplibrary.LookupIPSummaries(ipList)
|
||||
|
||||
// 节点信息
|
||||
var nodeMap = map[int64]interface{}{} // node id => { ... }
|
||||
for _, nodeId := range nodeIds {
|
||||
nodeResp, err := this.RPC().NSNodeRPC().FindNSNode(this.UserContext(), &pb.FindNSNodeRequest{NsNodeId: nodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var node = nodeResp.NsNode
|
||||
if node != nil {
|
||||
nodeMap[node.Id] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"cluster": maps.Map{
|
||||
"id": node.NsCluster.Id,
|
||||
"name": node.NsCluster.Name,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["nodes"] = nodeMap
|
||||
|
||||
// 域名信息
|
||||
var domainMap = map[int64]interface{}{} // domain id => { ... }
|
||||
for _, domainId := range domainIds {
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindNSDomain(this.UserContext(), &pb.FindNSDomainRequest{NsDomainId: domainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
domain := domainResp.NsDomain
|
||||
if domain != nil {
|
||||
domainMap[domain.Id] = maps.Map{
|
||||
"id": domain.Id,
|
||||
"name": domain.Name,
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["domains"] = domainMap
|
||||
|
||||
// 所有记录类型
|
||||
this.Data["recordTypes"] = dnsconfigs.FindAllRecordTypeDefinitions()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
16
EdgeUser/internal/web/actions/default/ns/accessLogs/init.go
Normal file
16
EdgeUser/internal/web/actions/default/ns/accessLogs/init.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Data("teaMenu", "ns").
|
||||
Data("teaSubMenu", "accessLog").
|
||||
Prefix("/ns/clusters/accessLogs").
|
||||
Get("", new(IndexAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package batch
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/dns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/nsutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CreateRecordsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateRecordsAction) Init() {
|
||||
this.Nav("", "", "batch")
|
||||
this.SecondMenu("createRecords")
|
||||
}
|
||||
|
||||
func (this *CreateRecordsAction) RunGet(params struct{}) {
|
||||
// 类型
|
||||
this.Data["types"] = dnsconfigs.FindAllUserRecordTypeDefinitions()
|
||||
|
||||
defaultTTL, err := nsutils.FindDefaultTTL(this.UserContext())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["defaultTTL"] = defaultTTL
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateRecordsAction) RunPost(params struct {
|
||||
Names string
|
||||
RecordsJSON []byte
|
||||
RemoveOld bool
|
||||
RemoveAll bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NS_LogCreateNSRecordsBatch)
|
||||
|
||||
// 检查域名是否已经创建
|
||||
var domainNames = []string{}
|
||||
for _, domainName := range strings.Split(params.Names, "\n") {
|
||||
domainName = strings.ToLower(strings.TrimSpace(domainName))
|
||||
if len(domainName) == 0 {
|
||||
continue
|
||||
}
|
||||
if !lists.ContainsString(domainNames, domainName) {
|
||||
domainNames = append(domainNames, domainName)
|
||||
}
|
||||
}
|
||||
|
||||
if len(domainNames) == 0 {
|
||||
this.FailField("names", "请输入域名")
|
||||
}
|
||||
|
||||
duplicateResp, err := this.RPC().NSDomainRPC().ExistNSDomains(this.UserContext(), &pb.ExistNSDomainsRequest{
|
||||
Names: domainNames,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var existingDomainNames = duplicateResp.ExistingNames
|
||||
var notExistingDomainNames = []string{}
|
||||
for _, domainName := range domainNames {
|
||||
if !lists.ContainsString(existingDomainNames, domainName) {
|
||||
notExistingDomainNames = append(notExistingDomainNames, domainName)
|
||||
}
|
||||
}
|
||||
if len(notExistingDomainNames) > 0 {
|
||||
this.FailField("names", "有以下域名不存在:"+strings.Join(notExistingDomainNames, ",")+"。请检查域名是否已删除或用户是否已选择正确。")
|
||||
}
|
||||
|
||||
// 检查记录
|
||||
type record struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value"`
|
||||
RouteCodes []string `json:"routeCodes"`
|
||||
TTL any `json:"ttl"`
|
||||
}
|
||||
|
||||
var records = []*record{}
|
||||
err = json.Unmarshal(params.RecordsJSON, &records)
|
||||
if err != nil {
|
||||
this.Fail("记录参数格式错误:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(records) == 0 {
|
||||
this.Fail("请添加至少一个记录")
|
||||
}
|
||||
|
||||
var recordCountsMap = map[string]int32{} // record name_type = count
|
||||
for _, record := range records {
|
||||
recordCountsMap[record.Name+"_____"+record.Type]++
|
||||
}
|
||||
|
||||
// 检查限额
|
||||
for _, domainName := range domainNames {
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindNSDomainWithName(this.UserContext(), &pb.FindNSDomainWithNameRequest{Name: domainName})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if domainResp.NsDomain == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
_, canCreate, err := nsutils.CheckRecordsQuota(this.UserContext(), domainResp.NsDomain.Id, int32(len(records)))
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !canCreate {
|
||||
this.Fail("域名 '" + domainName + "' 记录数已超出限额,请购买套餐后重试")
|
||||
}
|
||||
|
||||
// 检查负载均衡限额
|
||||
if !params.RemoveOld && !params.RemoveAll {
|
||||
for recordString, recordCount := range recordCountsMap {
|
||||
var recordPieces = strings.Split(recordString, "_____")
|
||||
var recordName = recordPieces[0]
|
||||
var recordType = recordPieces[1]
|
||||
|
||||
_, canCreate, err = nsutils.CheckLoadBalanceRecordsQuota(this.UserContext(), domainResp.NsDomain.Id, recordName, recordType, recordCount)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !canCreate {
|
||||
this.Fail("域名 '" + domainName + "' 记录 '" + recordName + "' 负载均衡数已超出限额,请购买套餐后重试")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 最小TTL
|
||||
minTTL, err := nsutils.FindMinTTL(this.UserContext())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, record := range records {
|
||||
message, ok := domainutils.ValidateRecordValue(record.Type, record.Value)
|
||||
if !ok {
|
||||
this.Fail("记录 '" + record.Name + "' 值校验失败:" + message)
|
||||
}
|
||||
|
||||
// ttl
|
||||
var recordInt = types.Int32(record.TTL)
|
||||
if recordInt <= 0 {
|
||||
recordInt = 600
|
||||
}
|
||||
record.TTL = recordInt
|
||||
|
||||
// 检查最小TTL
|
||||
if recordInt < minTTL {
|
||||
this.Fail("TTL不能小于" + types.String(minTTL) + "秒")
|
||||
}
|
||||
}
|
||||
recordsJSON, err := json.Marshal(records)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NSRecordRPC().CreateNSRecordsWithDomainNames(this.UserContext(), &pb.CreateNSRecordsWithDomainNamesRequest{
|
||||
NsDomainNames: domainNames,
|
||||
RecordsJSON: recordsJSON,
|
||||
RemoveOld: params.RemoveOld,
|
||||
RemoveAll: params.RemoveAll,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package batch
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DeleteDomainsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteDomainsAction) Init() {
|
||||
this.Nav("", "", "batch")
|
||||
this.SecondMenu("deleteDomains")
|
||||
}
|
||||
|
||||
func (this *DeleteDomainsAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *DeleteDomainsAction) RunPost(params struct {
|
||||
Names string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NS_LogDeleteNSDomainsBatch, this.UserId())
|
||||
|
||||
if len(params.Names) == 0 {
|
||||
this.FailField("names", "请输入要删除的域名")
|
||||
}
|
||||
|
||||
var domainNames = []string{}
|
||||
for _, name := range strings.Split(params.Names, "\n") {
|
||||
name = strings.TrimSpace(name)
|
||||
if len(name) == 0 {
|
||||
continue
|
||||
}
|
||||
name = strings.ToLower(name)
|
||||
domainNames = append(domainNames, name)
|
||||
}
|
||||
|
||||
if len(domainNames) == 0 {
|
||||
this.FailField("names", "请输入要删除的域名")
|
||||
}
|
||||
|
||||
// 检查域名是否存在
|
||||
duplicateResp, err := this.RPC().NSDomainRPC().ExistNSDomains(this.UserContext(), &pb.ExistNSDomainsRequest{
|
||||
Names: domainNames,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var existingDomainNames = duplicateResp.ExistingNames
|
||||
var notExistingDomainNames = []string{}
|
||||
for _, domainName := range domainNames {
|
||||
if !lists.ContainsString(existingDomainNames, domainName) {
|
||||
notExistingDomainNames = append(notExistingDomainNames, domainName)
|
||||
}
|
||||
}
|
||||
if len(notExistingDomainNames) > 0 {
|
||||
this.FailField("names", "有以下域名不存在:"+strings.Join(notExistingDomainNames, ",")+"。请检查域名是否已删除或用户是否已选择正确。")
|
||||
}
|
||||
|
||||
// 开始删除
|
||||
_, err = this.RPC().NSDomainRPC().DeleteNSDomains(this.UserContext(), &pb.DeleteNSDomainsRequest{
|
||||
Names: domainNames,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package batch
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DeleteRecordsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteRecordsAction) Init() {
|
||||
this.Nav("", "", "batch")
|
||||
this.SecondMenu("deleteRecords")
|
||||
}
|
||||
|
||||
func (this *DeleteRecordsAction) RunGet(params struct{}) {
|
||||
// 类型
|
||||
this.Data["types"] = dnsconfigs.FindAllUserRecordTypeDefinitions()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *DeleteRecordsAction) RunPost(params struct {
|
||||
Names string
|
||||
|
||||
SearchName string
|
||||
SearchValue string
|
||||
SearchType string
|
||||
SearchRouteCodes []string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NS_LogDeleteNSRecordsBatch)
|
||||
|
||||
// 检查域名是否已经创建
|
||||
var domainNames = []string{}
|
||||
for _, domainName := range strings.Split(params.Names, "\n") {
|
||||
domainName = strings.ToLower(strings.TrimSpace(domainName))
|
||||
if len(domainName) == 0 {
|
||||
continue
|
||||
}
|
||||
if !lists.ContainsString(domainNames, domainName) {
|
||||
domainNames = append(domainNames, domainName)
|
||||
}
|
||||
}
|
||||
|
||||
if len(domainNames) == 0 {
|
||||
this.FailField("names", "请输入域名")
|
||||
}
|
||||
|
||||
duplicateResp, err := this.RPC().NSDomainRPC().ExistNSDomains(this.UserContext(), &pb.ExistNSDomainsRequest{
|
||||
Names: domainNames,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var existingDomainNames = duplicateResp.ExistingNames
|
||||
var notExistingDomainNames = []string{}
|
||||
for _, domainName := range domainNames {
|
||||
if !lists.ContainsString(existingDomainNames, domainName) {
|
||||
notExistingDomainNames = append(notExistingDomainNames, domainName)
|
||||
}
|
||||
}
|
||||
if len(notExistingDomainNames) > 0 {
|
||||
this.FailField("names", "有以下域名不存在:"+strings.Join(notExistingDomainNames, ",")+"。请检查域名是否已删除或用户是否已选择正确。")
|
||||
}
|
||||
|
||||
_, err = this.RPC().NSRecordRPC().DeleteNSRecordsWithDomainNames(this.UserContext(), &pb.DeleteNSRecordsWithDomainNamesRequest{
|
||||
NsDomainNames: domainNames,
|
||||
SearchName: params.SearchName,
|
||||
SearchValue: params.SearchValue,
|
||||
SearchType: params.SearchType,
|
||||
SearchNSRouteCodes: params.SearchRouteCodes,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package batch
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type EnableRecordsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *EnableRecordsAction) Init() {
|
||||
this.Nav("", "", "batch")
|
||||
this.SecondMenu("enableRecords")
|
||||
}
|
||||
|
||||
func (this *EnableRecordsAction) RunGet(params struct{}) {
|
||||
// 类型
|
||||
this.Data["types"] = dnsconfigs.FindAllUserRecordTypeDefinitions()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *EnableRecordsAction) RunPost(params struct {
|
||||
Names string
|
||||
|
||||
SearchName string
|
||||
SearchValue string
|
||||
SearchType string
|
||||
SearchRouteCodes []string
|
||||
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
if params.IsOn {
|
||||
defer this.CreateLogInfo(codes.NS_LogEnableNSRecordsBatch)
|
||||
} else {
|
||||
defer this.CreateLogInfo(codes.NS_LogDisableNSRecordsBatch)
|
||||
}
|
||||
|
||||
// 检查域名是否已经创建
|
||||
var domainNames = []string{}
|
||||
for _, domainName := range strings.Split(params.Names, "\n") {
|
||||
domainName = strings.ToLower(strings.TrimSpace(domainName))
|
||||
if len(domainName) == 0 {
|
||||
continue
|
||||
}
|
||||
if !lists.ContainsString(domainNames, domainName) {
|
||||
domainNames = append(domainNames, domainName)
|
||||
}
|
||||
}
|
||||
|
||||
if len(domainNames) == 0 {
|
||||
this.FailField("names", "请输入域名")
|
||||
}
|
||||
|
||||
duplicateResp, err := this.RPC().NSDomainRPC().ExistNSDomains(this.UserContext(), &pb.ExistNSDomainsRequest{
|
||||
Names: domainNames,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var existingDomainNames = duplicateResp.ExistingNames
|
||||
var notExistingDomainNames = []string{}
|
||||
for _, domainName := range domainNames {
|
||||
if !lists.ContainsString(existingDomainNames, domainName) {
|
||||
notExistingDomainNames = append(notExistingDomainNames, domainName)
|
||||
}
|
||||
}
|
||||
if len(notExistingDomainNames) > 0 {
|
||||
this.FailField("names", "有以下域名不存在:"+strings.Join(notExistingDomainNames, ",")+"。请检查域名是否已删除或用户是否已选择正确。")
|
||||
}
|
||||
|
||||
_, err = this.RPC().NSRecordRPC().UpdateNSRecordsIsOnWithDomainNames(this.UserContext(), &pb.UpdateNSRecordsIsOnWithDomainNamesRequest{
|
||||
NsDomainNames: domainNames,
|
||||
SearchName: params.SearchName,
|
||||
SearchValue: params.SearchValue,
|
||||
SearchType: params.SearchType,
|
||||
SearchNSRouteCodes: params.SearchRouteCodes,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package batch
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/dns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/nsutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ImportRecordsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ImportRecordsAction) Init() {
|
||||
this.Nav("", "", "batch")
|
||||
this.SecondMenu("importRecords")
|
||||
}
|
||||
|
||||
func (this *ImportRecordsAction) RunGet(params struct{}) {
|
||||
// 类型
|
||||
this.Data["types"] = dnsconfigs.FindAllUserRecordTypeDefinitions()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *ImportRecordsAction) RunPost(params struct {
|
||||
Records string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NS_LogImportRecordsBatch)
|
||||
|
||||
var allRecordTypes = []string{}
|
||||
for _, t := range dnsconfigs.FindAllUserRecordTypeDefinitions() {
|
||||
allRecordTypes = append(allRecordTypes, t.Type)
|
||||
}
|
||||
|
||||
var pbRecords = []*pb.ImportNSRecordsRequest_Record{}
|
||||
var reg = regexp.MustCompile(`\s+`)
|
||||
var domainNames = []string{}
|
||||
|
||||
minTTL, err := nsutils.FindMinTTL(this.UserContext())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, line := range strings.Split(params.Records, "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 域名 记录名 记录类型 记录值 TTL
|
||||
var pieces = reg.Split(line, -1)
|
||||
if len(pieces) < 4 {
|
||||
this.Fail("'" + line + "' 格式错误,缺少必需项")
|
||||
}
|
||||
|
||||
var domainName = strings.ToLower(strings.TrimSpace(pieces[0]))
|
||||
var recordName = strings.ToLower(strings.TrimSpace(pieces[1]))
|
||||
var recordType = strings.ToUpper(pieces[2])
|
||||
var recordValue = strings.TrimSpace(pieces[3])
|
||||
|
||||
var recordTTLString = ""
|
||||
if len(pieces) > 4 {
|
||||
recordTTLString = pieces[4]
|
||||
}
|
||||
|
||||
// validate
|
||||
if len(domainName) == 0 {
|
||||
this.Fail("'" + line + "' 缺少域名")
|
||||
}
|
||||
if !domainutils.ValidateDomainFormat(domainName) {
|
||||
this.Fail("'" + line + "' 域名格式错误")
|
||||
}
|
||||
|
||||
if !lists.ContainsString(domainNames, domainName) {
|
||||
domainNames = append(domainNames, domainName)
|
||||
}
|
||||
|
||||
if len(recordName) > 0 && !domainutils.ValidateRecordName(recordName) {
|
||||
this.Fail("'" + line + "' 记录名格式错误")
|
||||
}
|
||||
|
||||
if len(recordType) == 0 {
|
||||
this.Fail("'" + line + "' 缺少记录类型")
|
||||
}
|
||||
if !lists.ContainsString(allRecordTypes, recordType) {
|
||||
this.Fail("'" + line + "' 不支持的记录类型 '" + recordType + "'")
|
||||
}
|
||||
|
||||
message, ok := domainutils.ValidateRecordValue(recordType, recordValue)
|
||||
if !ok {
|
||||
this.Fail("'" + line + "' 记录值 '" + recordValue + "' 校验失败:" + message)
|
||||
}
|
||||
|
||||
var recordTTL int32 = 600
|
||||
if len(recordTTLString) > 0 {
|
||||
if !regexp.MustCompile(`^\d+$`).MatchString(recordTTLString) {
|
||||
this.Fail("'" + line + "' 错误的TTL '" + recordTTLString + "'")
|
||||
}
|
||||
recordTTL = types.Int32(recordTTLString)
|
||||
if recordTTL > 10*365*86400 {
|
||||
recordTTL = 10 * 365 * 86400
|
||||
}
|
||||
|
||||
if recordTTL < minTTL {
|
||||
this.Fail("TTL不能小于" + types.String(minTTL) + "秒")
|
||||
}
|
||||
}
|
||||
pbRecords = append(pbRecords, &pb.ImportNSRecordsRequest_Record{
|
||||
NsDomainName: domainName,
|
||||
Name: recordName,
|
||||
Type: recordType,
|
||||
Value: recordValue,
|
||||
Ttl: recordTTL,
|
||||
})
|
||||
}
|
||||
|
||||
if len(pbRecords) == 0 {
|
||||
this.FailField("records", "请输入要导入的记录")
|
||||
}
|
||||
|
||||
// 检查域名是否存在
|
||||
|
||||
duplicateResp, err := this.RPC().NSDomainRPC().ExistNSDomains(this.UserContext(), &pb.ExistNSDomainsRequest{
|
||||
Names: domainNames,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var existingDomainNames = duplicateResp.ExistingNames
|
||||
var notExistingDomainNames = []string{}
|
||||
for _, domainName := range domainNames {
|
||||
if !lists.ContainsString(existingDomainNames, domainName) {
|
||||
notExistingDomainNames = append(notExistingDomainNames, domainName)
|
||||
}
|
||||
}
|
||||
if len(notExistingDomainNames) > 0 {
|
||||
this.FailField("names", "有以下域名不存在:"+strings.Join(notExistingDomainNames, ",")+"。请检查域名是否已删除或用户是否已选择正确。")
|
||||
}
|
||||
|
||||
// 检查限额
|
||||
for _, domainName := range domainNames {
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindNSDomainWithName(this.UserContext(), &pb.FindNSDomainWithNameRequest{Name: domainName})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if domainResp.NsDomain == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var countRecords int32 = 0
|
||||
for _, record := range pbRecords {
|
||||
if record.NsDomainName == domainName {
|
||||
countRecords++
|
||||
}
|
||||
}
|
||||
if countRecords == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
_, canCreate, err := nsutils.CheckRecordsQuota(this.UserContext(), domainResp.NsDomain.Id, countRecords)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !canCreate {
|
||||
this.Fail("域名 '" + domainName + "' 记录数已超出限额,请购买套餐后重试")
|
||||
}
|
||||
|
||||
// 检查负载均衡限额
|
||||
var recordCountsMap = map[string]int32{} // record name_type = count
|
||||
for _, record := range pbRecords {
|
||||
if record.NsDomainName == domainName {
|
||||
recordCountsMap[record.Name+"_____"+record.Type]++
|
||||
}
|
||||
}
|
||||
|
||||
for recordString, recordCount := range recordCountsMap {
|
||||
var recordPieces = strings.Split(recordString, "_____")
|
||||
var recordName = recordPieces[0]
|
||||
var recordType = recordPieces[1]
|
||||
|
||||
_, canCreate, err = nsutils.CheckLoadBalanceRecordsQuota(this.UserContext(), domainResp.NsDomain.Id, recordName, recordType, recordCount)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !canCreate {
|
||||
this.Fail("域名 '" + domainName + "' 记录 '" + recordName + "' 负载均衡数已超出限额,请购买套餐后重试")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = this.RPC().NSRecordRPC().ImportNSRecords(this.UserContext(), &pb.ImportNSRecordsRequest{
|
||||
NsRecords: pbRecords,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
102
EdgeUser/internal/web/actions/default/ns/domains/batch/index.go
Normal file
102
EdgeUser/internal/web/actions/default/ns/domains/batch/index.go
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package batch
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/dns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/nsutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "batch")
|
||||
this.SecondMenu("index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
Names string // 如果批量的话
|
||||
GroupId int64
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var groupIds = []int64{}
|
||||
if params.GroupId > 0 {
|
||||
groupIds = append(groupIds, params.GroupId)
|
||||
}
|
||||
|
||||
defer this.CreateLogInfo(codes.NS_LogCreateNSRecordsBatch)
|
||||
|
||||
params.Must.
|
||||
Field("names", params.Names).
|
||||
Require("请输入域名")
|
||||
|
||||
var names = []string{}
|
||||
for _, name := range strings.Split(params.Names, "\n") {
|
||||
name = strings.TrimSpace(name)
|
||||
if len(name) == 0 {
|
||||
continue
|
||||
}
|
||||
if !domainutils.ValidateDomainFormat(name) {
|
||||
this.Fail("域名 '" + name + "' 格式不正确")
|
||||
}
|
||||
if !lists.ContainsString(names, name) {
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
|
||||
if len(names) == 0 {
|
||||
this.FailField("names", "请输入域名")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查限额
|
||||
_, canCreate, err := nsutils.CheckDomainsQuote(this.UserContext(), int32(len(names)))
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !canCreate {
|
||||
this.Fail("域名数已超出限额,请购买套餐后重试")
|
||||
}
|
||||
|
||||
// 检查域名是否已经存在
|
||||
{
|
||||
existResp, err := this.RPC().NSDomainRPC().ExistNSDomains(this.UserContext(), &pb.ExistNSDomainsRequest{
|
||||
Names: names,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(existResp.ExistingNames) > 0 {
|
||||
this.Fail("域名 " + strings.Join(existResp.ExistingNames, ", ") + " 已经存在,无法重复添加")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_, err = this.RPC().NSDomainRPC().CreateNSDomains(this.UserContext(), &pb.CreateNSDomainsRequest{
|
||||
Names: names,
|
||||
NsDomainGroupIds: groupIds,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package batch
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/dns/domains/domainutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type UpdateRecordsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateRecordsAction) Init() {
|
||||
this.Nav("", "", "batch")
|
||||
this.SecondMenu("updateRecords")
|
||||
}
|
||||
|
||||
func (this *UpdateRecordsAction) RunGet(params struct{}) {
|
||||
// 类型
|
||||
this.Data["types"] = dnsconfigs.FindAllUserRecordTypeDefinitions()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateRecordsAction) RunPost(params struct {
|
||||
Names string
|
||||
|
||||
SearchName string
|
||||
SearchValue string
|
||||
SearchType string
|
||||
SearchRouteCodes []string
|
||||
|
||||
NewName string
|
||||
NewValue string
|
||||
NewType string
|
||||
NewRouteCodes []string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NS_LogUpdateNSRecordsBatch)
|
||||
|
||||
// 检查域名是否已经创建
|
||||
var domainNames = []string{}
|
||||
for _, domainName := range strings.Split(params.Names, "\n") {
|
||||
domainName = strings.ToLower(strings.TrimSpace(domainName))
|
||||
if len(domainName) == 0 {
|
||||
continue
|
||||
}
|
||||
if !lists.ContainsString(domainNames, domainName) {
|
||||
domainNames = append(domainNames, domainName)
|
||||
}
|
||||
}
|
||||
|
||||
if len(domainNames) == 0 {
|
||||
this.FailField("names", "请输入域名")
|
||||
}
|
||||
|
||||
duplicateResp, err := this.RPC().NSDomainRPC().ExistNSDomains(this.UserContext(), &pb.ExistNSDomainsRequest{
|
||||
Names: domainNames,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var existingDomainNames = duplicateResp.ExistingNames
|
||||
var notExistingDomainNames = []string{}
|
||||
for _, domainName := range domainNames {
|
||||
if !lists.ContainsString(existingDomainNames, domainName) {
|
||||
notExistingDomainNames = append(notExistingDomainNames, domainName)
|
||||
}
|
||||
}
|
||||
if len(notExistingDomainNames) > 0 {
|
||||
this.FailField("names", "有以下域名不存在:"+strings.Join(notExistingDomainNames, ",")+"。请检查域名是否已删除或用户是否已选择正确。")
|
||||
}
|
||||
|
||||
if len(params.NewValue) > 0 {
|
||||
message, ok := domainutils.ValidateRecordValue(params.NewType, params.NewValue)
|
||||
if !ok {
|
||||
this.Fail("新的记录值 '" + params.NewValue + "' 填写错误:" + message)
|
||||
}
|
||||
}
|
||||
|
||||
_, err = this.RPC().NSRecordRPC().UpdateNSRecordsWithDomainNames(this.UserContext(), &pb.UpdateNSRecordsWithDomainNamesRequest{
|
||||
NsDomainNames: domainNames,
|
||||
SearchName: params.SearchName,
|
||||
SearchValue: params.SearchValue,
|
||||
SearchType: params.SearchType,
|
||||
SearchNSRouteCodes: params.SearchRouteCodes,
|
||||
NewName: params.NewName,
|
||||
NewValue: params.NewValue,
|
||||
NewType: params.NewType,
|
||||
NewNSRouteCodes: params.NewRouteCodes,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
187
EdgeUser/internal/web/actions/default/ns/domains/create.go
Normal file
187
EdgeUser/internal/web/actions/default/ns/domains/create.go
Normal file
@@ -0,0 +1,187 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package domains
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/dns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/nsutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CreateAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateAction) Init() {
|
||||
this.Nav("", "", "create")
|
||||
}
|
||||
|
||||
func (this *CreateAction) RunGet(params struct{}) {
|
||||
userConfigResp, err := this.RPC().SysSettingRPC().ReadSysSetting(this.UserContext(), &pb.ReadSysSettingRequest{Code: systemconfigs.SettingCodeNSUserConfig})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["configIsValid"] = false
|
||||
if len(userConfigResp.ValueJSON) > 0 {
|
||||
var config = &dnsconfigs.NSUserConfig{}
|
||||
err = json.Unmarshal(userConfigResp.ValueJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if config.DefaultClusterId > 0 {
|
||||
this.Data["configIsValid"] = true
|
||||
}
|
||||
}
|
||||
|
||||
// 套餐限制
|
||||
maxDomains, canCreate, err := nsutils.CheckDomainsQuote(this.UserContext(), 1)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["quotaMaxDomains"] = maxDomains
|
||||
this.Data["quotaCanCreate"] = canCreate
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateAction) RunPost(params struct {
|
||||
AddingType string
|
||||
|
||||
Name string
|
||||
Names string // 如果批量的话
|
||||
UserId int64
|
||||
GroupId int64
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
// 检查套餐限制
|
||||
_, canCreate, err := nsutils.CheckDomainsQuote(this.UserContext(), 1)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !canCreate {
|
||||
this.Fail("域名个数已超出最大限额")
|
||||
}
|
||||
|
||||
var groupIds = []int64{}
|
||||
if params.GroupId > 0 {
|
||||
groupIds = append(groupIds, params.GroupId)
|
||||
}
|
||||
|
||||
if params.AddingType == "batch" { // 批量添加
|
||||
defer this.CreateLogInfo(codes.NS_LogCreateNSDomainsBatch)
|
||||
|
||||
params.Must.
|
||||
Field("names", params.Names).
|
||||
Require("请输入域名")
|
||||
|
||||
var names = []string{}
|
||||
for _, name := range strings.Split(params.Names, "\n") {
|
||||
name = strings.TrimSpace(name)
|
||||
if len(name) == 0 {
|
||||
continue
|
||||
}
|
||||
if !domainutils.ValidateDomainFormat(name) {
|
||||
this.Fail("域名 '" + name + "' 格式不正确")
|
||||
}
|
||||
if !lists.ContainsString(names, name) {
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
|
||||
if len(names) == 0 {
|
||||
this.FailField("names", "请输入域名")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查域名是否已经存在
|
||||
{
|
||||
existResp, err := this.RPC().NSDomainRPC().ExistNSDomains(this.UserContext(), &pb.ExistNSDomainsRequest{
|
||||
Names: names,
|
||||
UserId: params.UserId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(existResp.ExistingNames) > 0 {
|
||||
this.Fail("域名 " + strings.Join(existResp.ExistingNames, ", ") + " 已经存在,无法重复添加")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_, err := this.RPC().NSDomainRPC().CreateNSDomains(this.UserContext(), &pb.CreateNSDomainsRequest{
|
||||
UserId: params.UserId,
|
||||
Names: names,
|
||||
NsDomainGroupIds: groupIds,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
} else { // 单个添加
|
||||
var domainId int64
|
||||
defer func() {
|
||||
this.CreateLogInfo(codes.NSDomain_LogCreateNSDomain, domainId)
|
||||
}()
|
||||
|
||||
params.Name = strings.ToLower(params.Name)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入域名").
|
||||
Expect(func() (message string, success bool) {
|
||||
success = domainutils.ValidateDomainFormat(params.Name)
|
||||
if !success {
|
||||
message = "请输入正确的域名"
|
||||
}
|
||||
return
|
||||
})
|
||||
|
||||
// 检查域名是否已经存在
|
||||
{
|
||||
existResp, err := this.RPC().NSDomainRPC().ExistNSDomains(this.UserContext(), &pb.ExistNSDomainsRequest{
|
||||
Names: []string{params.Name},
|
||||
UserId: params.UserId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(existResp.ExistingNames) > 0 {
|
||||
this.Fail("域名 " + strings.Join(existResp.ExistingNames, ", ") + " 已经存在,无法重复添加")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().NSDomainRPC().CreateNSDomain(this.UserContext(), &pb.CreateNSDomainRequest{
|
||||
UserId: params.UserId,
|
||||
Name: params.Name,
|
||||
NsDomainGroupIds: groupIds,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
domainId = createResp.NsDomainId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
}
|
||||
27
EdgeUser/internal/web/actions/default/ns/domains/delete.go
Normal file
27
EdgeUser/internal/web/actions/default/ns/domains/delete.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package domains
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
DomainId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSDomain_LogDeleteNSDomain, params.DomainId)
|
||||
|
||||
_, err := this.RPC().NSDomainRPC().DeleteNSDomain(this.UserContext(), &pb.DeleteNSDomainRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package domains
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
)
|
||||
|
||||
type DeletePageAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeletePageAction) RunPost(params struct {
|
||||
DomainIds []int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NS_LogDeleteNSDomainsBatch, this.UserId())
|
||||
|
||||
if len(params.DomainIds) == 0 {
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
for _, domainId := range params.DomainIds {
|
||||
_, err := this.RPC().NSDomainRPC().DeleteNSDomain(this.UserContext(), &pb.DeleteNSDomainRequest{
|
||||
NsDomainId: domainId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package domain
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
DomainId int64
|
||||
}) {
|
||||
this.RedirectURL("/ns/domains/records?domainId=" + types.String(params.DomainId))
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package domain
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UpdateStatusPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateStatusPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdateStatusPopupAction) RunGet(params struct {
|
||||
DomainId int64
|
||||
}) {
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindNSDomain(this.UserContext(), &pb.FindNSDomainRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var domain = domainResp.NsDomain
|
||||
if domain == nil {
|
||||
this.NotFound("NSDomain", params.DomainId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["domain"] = maps.Map{
|
||||
"id": domain.Id,
|
||||
"name": domain.Name,
|
||||
"status": domain.Status,
|
||||
}
|
||||
|
||||
this.Data["statusList"] = dnsconfigs.FindAllNSDomainStatusList()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateStatusPopupAction) RunPost(params struct {
|
||||
DomainId int64
|
||||
Status string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSDomain_LogUpdateNSDomainStatus, params.DomainId, params.Status)
|
||||
|
||||
_, err := this.RPC().NSDomainRPC().UpdateNSDomainStatus(this.UserContext(), &pb.UpdateNSDomainStatusRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
Status: params.Status,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package domain
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains/domainutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type VerifyPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *VerifyPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *VerifyPopupAction) RunGet(params struct {
|
||||
DomainId int64
|
||||
}) {
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindNSDomain(this.UserContext(), &pb.FindNSDomainRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var domain = domainResp.NsDomain
|
||||
if domain == nil {
|
||||
this.NotFound("nsDomain", params.DomainId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["domain"] = maps.Map{
|
||||
"id": domain.Id,
|
||||
"name": domain.Name,
|
||||
"status": domain.Status,
|
||||
}
|
||||
|
||||
// 当前用户可以使用的DNS Hosts
|
||||
if domain.NsCluster == nil || domain.NsCluster.Id <= 0 {
|
||||
this.WriteString("当前域名(" + domain.Name + ")所在集群已被删除,请删除当前域名后重新添加")
|
||||
return
|
||||
}
|
||||
|
||||
var hosts []string
|
||||
hostsResp, err := this.RPC().NSClusterRPC().FindNSClusterHosts(this.UserContext(), &pb.FindNSClusterHostsRequest{
|
||||
NsClusterId: domain.NsCluster.Id,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
hosts = hostsResp.Hosts
|
||||
|
||||
if hosts == nil {
|
||||
hosts = []string{}
|
||||
}
|
||||
this.Data["hosts"] = hosts
|
||||
|
||||
// TXT记录
|
||||
txtResp, err := this.RPC().NSDomainRPC().FindNSDomainVerifyingInfo(this.UserContext(), &pb.FindNSDomainVerifyingInfoRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["requireTXT"] = txtResp.RequireTXT
|
||||
this.Data["txt"] = txtResp.Txt
|
||||
this.Data["txtExpiresTime"] = timeutil.FormatTime("Y-m-d H:i:s", txtResp.ExpiresAt)
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *VerifyPopupAction) RunPost(params struct {
|
||||
DomainId int64
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindNSDomain(this.UserContext(), &pb.FindNSDomainRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["isOk"] = false
|
||||
this.Data["message"] = ""
|
||||
this.Data["rawErrorMessage"] = ""
|
||||
|
||||
var domain = domainResp.NsDomain
|
||||
if domain == nil {
|
||||
this.NotFound("nsDomain", params.DomainId)
|
||||
return
|
||||
}
|
||||
|
||||
if domain.Status == dnsconfigs.NSDomainStatusVerified {
|
||||
this.Data["message"] = "已验证"
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
if domain.Status != dnsconfigs.NSDomainStatusNone {
|
||||
this.Data["message"] = "当前状态为:" + dnsconfigs.NSDomainStatusName(domain.Status) + ",不允许验证"
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
// 提交验证
|
||||
verifyResp, err := this.RPC().NSDomainRPC().VerifyNSDomain(this.UserContext(), &pb.VerifyNSDomainRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if !verifyResp.IsOk {
|
||||
var message = domainutils.VerifyMessageWithCode(verifyResp.ErrorCode)
|
||||
if len(verifyResp.CurrentTXTValues) > 0 {
|
||||
message += ",当前TXT解析结果为:" + strings.Join(verifyResp.CurrentTXTValues, ", ")
|
||||
} else if len(verifyResp.CurrentNSValues) > 0 {
|
||||
message += ",当前NS解析结果为:" + strings.Join(verifyResp.CurrentNSValues, ", ")
|
||||
}
|
||||
message += "。"
|
||||
|
||||
this.Data["message"] = message
|
||||
this.Data["rawErrorMessage"] = verifyResp.ErrorMessage
|
||||
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["isOk"] = true
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package domainutils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
// InitDomain 初始化域名信息
|
||||
func InitDomain(parent *actionutils.ParentAction, domainId int64) error {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domainResp, err := rpcClient.NSDomainRPC().FindNSDomain(parent.UserContext(), &pb.FindNSDomainRequest{NsDomainId: domainId})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var domain = domainResp.NsDomain
|
||||
if domain == nil {
|
||||
return errors.New("InitDomain: can not find domain with id '" + types.String(domainId) + "'")
|
||||
}
|
||||
|
||||
// 记录数量
|
||||
countRecordsResp, err := rpcClient.NSRecordRPC().CountAllNSRecords(parent.UserContext(), &pb.CountAllNSRecordsRequest{
|
||||
NsDomainId: domainId,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var countRecords = countRecordsResp.Count
|
||||
|
||||
// Key数量
|
||||
countKeysResp, err := rpcClient.NSKeyRPC().CountAllNSKeys(parent.UserContext(), &pb.CountAllNSKeysRequest{
|
||||
NsDomainId: domainId,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var countKeys = countKeysResp.Count
|
||||
|
||||
// 健康检查
|
||||
var healthCheckConfig = dnsconfigs.NewNSRecordsHealthCheckConfig()
|
||||
if len(domain.RecordsHealthCheckJSON) > 0 {
|
||||
err = json.Unmarshal(domain.RecordsHealthCheckJSON, healthCheckConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
parent.Data["domain"] = maps.Map{
|
||||
"id": domain.Id,
|
||||
"name": domain.Name,
|
||||
"countRecords": countRecords,
|
||||
"countKeys": countKeys,
|
||||
"enableHealthCheck": healthCheckConfig.IsOn,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyMessageWithCode 通过代号获取验证消息
|
||||
func VerifyMessageWithCode(code string) string {
|
||||
var message = ""
|
||||
switch code {
|
||||
case "DomainNotFound":
|
||||
message = "无法找到域名"
|
||||
case "InvalidStatus":
|
||||
message = "在当前域名状态下无法提交验证"
|
||||
case "InvalidDNSHosts":
|
||||
message = "没有设置正确的DNS主机地址或者NS记录尚未生效"
|
||||
case "TXTNotFound":
|
||||
message = "没有找到TXT记录或者TXT记录尚未生效"
|
||||
case "InvalidTXT":
|
||||
message = "没有设置正确的TXT记录或者TXT记录尚未生效"
|
||||
case "TXTExpired":
|
||||
message = "验证信息已失效,请刷新后重试"
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
// CheckHealthCheckPermission 检查是否能够修改健康检查
|
||||
func CheckHealthCheckPermission(rpcClient *rpc.RPCClient, ctx context.Context, domainId int64) (canUpdate bool, err error) {
|
||||
if domainId <= 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
domainResp, err := rpcClient.NSDomainRPC().FindNSDomain(ctx, &pb.FindNSDomainRequest{NsDomainId: domainId})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
var domain = domainResp.NsDomain
|
||||
if domain == nil {
|
||||
return false, errors.New("the domain is not found")
|
||||
}
|
||||
if domain.UserId > 0 {
|
||||
// 检查套餐
|
||||
userPlanResp, err := rpcClient.NSUserPlanRPC().FindNSUserPlan(ctx, &pb.FindNSUserPlanRequest{
|
||||
UserId: domain.UserId,
|
||||
NsUserPlanId: 0,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
var userPlan = userPlanResp.NsUserPlan
|
||||
if userPlan == nil || userPlan.NsPlanId == 0 || userPlan.DayTo < timeutil.Format("Ymd") {
|
||||
return checkHealthCheckInUserSetting(rpcClient, ctx)
|
||||
} else {
|
||||
planResp, err := rpcClient.NSPlanRPC().FindNSPlan(ctx, &pb.FindNSPlanRequest{NsPlanId: userPlan.NsPlanId})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if planResp.NsPlan == nil || len(planResp.NsPlan.ConfigJSON) == 0 {
|
||||
return checkHealthCheckInUserSetting(rpcClient, ctx)
|
||||
}
|
||||
var planConfig = dnsconfigs.DefaultNSPlanConfig()
|
||||
err = json.Unmarshal(planResp.NsPlan.ConfigJSON, planConfig)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return planConfig.SupportHealthCheck, nil
|
||||
}
|
||||
} else {
|
||||
return checkHealthCheckInUserSetting(rpcClient, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查用户基础设置
|
||||
func checkHealthCheckInUserSetting(rpcClient *rpc.RPCClient, ctx context.Context) (bool, error) {
|
||||
resp, err := rpcClient.SysSettingRPC().ReadSysSetting(ctx, &pb.ReadSysSettingRequest{
|
||||
Code: systemconfigs.SettingCodeNSUserConfig,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var config = dnsconfigs.NewNSUserConfig()
|
||||
if len(resp.ValueJSON) > 0 {
|
||||
err = json.Unmarshal(resp.ValueJSON, config)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if config.DefaultPlanConfig == nil {
|
||||
config.DefaultPlanConfig = dnsconfigs.DefaultNSUserPlanConfig()
|
||||
}
|
||||
return config.DefaultPlanConfig.SupportHealthCheck, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct {
|
||||
}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Name string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var groupId int64 = 0
|
||||
|
||||
defer func() {
|
||||
this.CreateLogInfo(codes.NSDomainGroup_LogCreateNSDomainGroup, groupId)
|
||||
}()
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入分组名称")
|
||||
|
||||
createResp, err := this.RPC().NSDomainGroupRPC().CreateNSDomainGroup(this.UserContext(), &pb.CreateNSDomainGroupRequest{
|
||||
Name: params.Name,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
groupId = createResp.NsDomainGroupId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package group
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
GroupId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSDomainGroup_LogDeleteNSDomainGroup, params.GroupId)
|
||||
|
||||
_, err := this.RPC().NSDomainGroupRPC().DeleteNSDomainGroup(this.UserContext(), &pb.DeleteNSDomainGroupRequest{NsDomainGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package group
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
GroupId int64
|
||||
}) {
|
||||
groupResp, err := this.RPC().NSDomainGroupRPC().FindNSDomainGroup(this.UserContext(), &pb.FindNSDomainGroupRequest{NsDomainGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var group = groupResp.NsDomainGroup
|
||||
if group == nil {
|
||||
this.NotFound("nsDomainGroup", params.GroupId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["group"] = maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
"isOn": group.IsOn,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package group
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
GroupId int64
|
||||
}) {
|
||||
groupResp, err := this.RPC().NSDomainGroupRPC().FindNSDomainGroup(this.UserContext(), &pb.FindNSDomainGroupRequest{NsDomainGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var group = groupResp.NsDomainGroup
|
||||
if group == nil {
|
||||
this.NotFound("nsDomainGroup", params.GroupId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["group"] = maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
"isOn": group.IsOn,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
GroupId int64
|
||||
Name string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSDomainGroup_LogUpdateNSDomainGroup, params.GroupId)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入分组名称")
|
||||
|
||||
_, err := this.RPC().NSDomainGroupRPC().UpdateNSDomainGroup(this.UserContext(), &pb.UpdateNSDomainGroupRequest{
|
||||
NsDomainGroupId: params.GroupId,
|
||||
Name: params.Name,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
groupsResp, err := this.RPC().NSDomainGroupRPC().FindAllNSDomainGroups(this.UserContext(), &pb.FindAllNSDomainGroupsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var groupMaps = []maps.Map{}
|
||||
for _, group := range groupsResp.NsDomainGroups {
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
"isOn": group.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type OptionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *OptionsAction) RunPost(params struct {
|
||||
UserId int64
|
||||
}) {
|
||||
groupsResp, err := this.RPC().NSDomainGroupRPC().FindAllAvailableNSDomainGroups(this.UserContext(), &pb.FindAllAvailableNSDomainGroupsRequest{
|
||||
UserId: params.UserId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var groupMaps = []maps.Map{}
|
||||
for _, group := range groupsResp.NsDomainGroups {
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
103
EdgeUser/internal/web/actions/default/ns/domains/healthCheck.go
Normal file
103
EdgeUser/internal/web/actions/default/ns/domains/healthCheck.go
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package domains
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains/domainutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type HealthCheckAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *HealthCheckAction) Init() {
|
||||
this.Nav("", "", "healthCheck")
|
||||
}
|
||||
|
||||
func (this *HealthCheckAction) RunGet(params struct {
|
||||
DomainId int64
|
||||
}) {
|
||||
err := domainutils.InitDomain(this.Parent(), params.DomainId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["domainId"] = params.DomainId
|
||||
|
||||
// 检查当前用户权限
|
||||
canUpdate, err := domainutils.CheckHealthCheckPermission(this.RPC(), this.UserContext(), params.DomainId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["canUpdate"] = canUpdate
|
||||
|
||||
// 健康检查配置
|
||||
healthCheckResp, err := this.RPC().NSDomainRPC().FindNSDomainRecordsHealthCheck(this.UserContext(), &pb.FindNSDomainRecordsHealthCheckRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var healthCheckConfig = dnsconfigs.NewNSRecordsHealthCheckConfig()
|
||||
if len(healthCheckResp.NsDomainRecordsHealthCheckJSON) > 0 {
|
||||
err = json.Unmarshal(healthCheckResp.NsDomainRecordsHealthCheckJSON, healthCheckConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Data["config"] = healthCheckConfig
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *HealthCheckAction) RunPost(params struct {
|
||||
DomainId int64
|
||||
RecordsHealthCheckJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSDomain_LogUpdateNSDomainHealthCheck, params.DomainId)
|
||||
|
||||
canUpdate, err := domainutils.CheckHealthCheckPermission(this.RPC(), this.UserContext(), params.DomainId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !canUpdate {
|
||||
this.Fail("当前用户没有权限修改健康检查设置")
|
||||
return
|
||||
}
|
||||
|
||||
var config = dnsconfigs.NewNSRecordsHealthCheckConfig()
|
||||
err = json.Unmarshal(params.RecordsHealthCheckJSON, config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = config.Init()
|
||||
if err != nil {
|
||||
this.Fail("校验配置失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NSDomainRPC().UpdateNSDomainRecordsHealthCheck(this.UserContext(), &pb.UpdateNSDomainRecordsHealthCheckRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
NsDomainRecordsHealthCheckJSON: params.RecordsHealthCheckJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
72
EdgeUser/internal/web/actions/default/ns/domains/index.go
Normal file
72
EdgeUser/internal/web/actions/default/ns/domains/index.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package domains
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
GroupId int64
|
||||
Keyword string
|
||||
}) {
|
||||
this.Data["groupId"] = params.GroupId
|
||||
this.Data["keyword"] = params.Keyword
|
||||
|
||||
// 分页
|
||||
countResp, err := this.RPC().NSDomainRPC().CountAllNSDomains(this.UserContext(), &pb.CountAllNSDomainsRequest{
|
||||
NsDomainGroupId: params.GroupId,
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var page = this.NewPage(countResp.Count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
// 列表
|
||||
domainsResp, err := this.RPC().NSDomainRPC().ListNSDomains(this.UserContext(), &pb.ListNSDomainsRequest{
|
||||
Keyword: params.Keyword,
|
||||
NsDomainGroupId: params.GroupId,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var domainMaps = []maps.Map{}
|
||||
for _, domain := range domainsResp.NsDomains {
|
||||
// 分组信息
|
||||
var groupMaps = []maps.Map{}
|
||||
for _, group := range domain.NsDomainGroups {
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
"userId": group.UserId,
|
||||
})
|
||||
}
|
||||
|
||||
domainMaps = append(domainMaps, maps.Map{
|
||||
"id": domain.Id,
|
||||
"name": domain.Name,
|
||||
"status": domain.Status,
|
||||
"statusName": dnsconfigs.NSDomainStatusName(domain.Status),
|
||||
"isOn": domain.IsOn,
|
||||
"groups": groupMaps,
|
||||
})
|
||||
}
|
||||
this.Data["domains"] = domainMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package keys
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct {
|
||||
DomainId int64
|
||||
}) {
|
||||
this.Data["domainId"] = params.DomainId
|
||||
|
||||
// 所有算法
|
||||
var algorithmMaps = []maps.Map{}
|
||||
for _, algo := range dnsconfigs.FindAllKeyAlgorithmTypes() {
|
||||
algorithmMaps = append(algorithmMaps, maps.Map{
|
||||
"name": algo.Name,
|
||||
"code": algo.Code,
|
||||
})
|
||||
}
|
||||
this.Data["algorithms"] = algorithmMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
DomainId int64
|
||||
Name string
|
||||
Algo string
|
||||
Secret string
|
||||
SecretType string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var keyId int64 = 0
|
||||
defer func() {
|
||||
this.CreateLogInfo(codes.NSKey_LogCreateNSKey, keyId)
|
||||
}()
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入密钥名称").
|
||||
Field("algo", params.Algo).
|
||||
Require("请选择算法").
|
||||
Field("secret", params.Secret).
|
||||
Require("请输入密码")
|
||||
|
||||
// 校验密码
|
||||
if params.SecretType == dnsconfigs.NSKeySecretTypeBase64 {
|
||||
_, err := base64.StdEncoding.DecodeString(params.Secret)
|
||||
if err != nil {
|
||||
this.FailField("secret", "请输入BASE64格式的密码或者选择明文")
|
||||
}
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().NSKeyRPC().CreateNSKey(this.UserContext(), &pb.CreateNSKeyRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
NsZoneId: 0,
|
||||
Name: params.Name,
|
||||
Algo: params.Algo,
|
||||
Secret: params.Secret,
|
||||
SecretType: params.SecretType,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
keyId = createResp.NsKeyId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package keys
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
KeyId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSKey_LogDeleteNSKey, params.KeyId)
|
||||
|
||||
_, err := this.RPC().NSKeyRPC().DeleteNSKey(this.UserContext(), &pb.DeleteNSKeyRequest{NsKeyId: params.KeyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package keys
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
)
|
||||
|
||||
type GenerateSecretAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *GenerateSecretAction) RunPost(params struct {
|
||||
SecretType string
|
||||
}) {
|
||||
switch params.SecretType {
|
||||
case dnsconfigs.NSKeySecretTypeClear:
|
||||
this.Data["secret"] = rands.HexString(128)
|
||||
case dnsconfigs.NSKeySecretTypeBase64:
|
||||
this.Data["secret"] = base64.StdEncoding.EncodeToString([]byte(rands.HexString(128)))
|
||||
default:
|
||||
this.Data["secret"] = rands.HexString(128)
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package keys
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains/domainutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "key")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
DomainId int64
|
||||
}) {
|
||||
// 初始化域名信息
|
||||
err := domainutils.InitDomain(this.Parent(), params.DomainId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 数量
|
||||
countResp, err := this.RPC().NSKeyRPC().CountAllNSKeys(this.UserContext(), &pb.CountAllNSKeysRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
NsZoneId: 0,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var page = this.NewPage(countResp.Count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
// 列表
|
||||
keysResp, err := this.RPC().NSKeyRPC().ListNSKeys(this.UserContext(), &pb.ListNSKeysRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
NsZoneId: 0,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var keyMaps = []maps.Map{}
|
||||
for _, key := range keysResp.NsKeys {
|
||||
keyMaps = append(keyMaps, maps.Map{
|
||||
"id": key.Id,
|
||||
"name": key.Name,
|
||||
"secret": key.Secret,
|
||||
"secretTypeName": dnsconfigs.FindKeySecretTypeName(key.SecretType),
|
||||
"algoName": dnsconfigs.FindKeyAlgorithmTypeName(key.Algo),
|
||||
"isOn": key.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["keys"] = keyMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package keys
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
KeyId int64
|
||||
}) {
|
||||
keyResp, err := this.RPC().NSKeyRPC().FindNSKey(this.UserContext(), &pb.FindNSKeyRequest{NsKeyId: params.KeyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var key = keyResp.NsKey
|
||||
if key == nil {
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["key"] = maps.Map{
|
||||
"id": key.Id,
|
||||
"name": key.Name,
|
||||
"algo": key.Algo,
|
||||
"secret": key.Secret,
|
||||
"secretType": key.SecretType,
|
||||
"isOn": key.IsOn,
|
||||
}
|
||||
|
||||
// 所有算法
|
||||
var algorithmMaps = []maps.Map{}
|
||||
for _, algo := range dnsconfigs.FindAllKeyAlgorithmTypes() {
|
||||
algorithmMaps = append(algorithmMaps, maps.Map{
|
||||
"name": algo.Name,
|
||||
"code": algo.Code,
|
||||
})
|
||||
}
|
||||
this.Data["algorithms"] = algorithmMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
KeyId int64
|
||||
Name string
|
||||
Algo string
|
||||
Secret string
|
||||
SecretType string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
this.CreateLogInfo(codes.NSKey_LogUpdateNSKey, params.KeyId)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入密钥名称").
|
||||
Field("algo", params.Algo).
|
||||
Require("请选择算法").
|
||||
Field("secret", params.Secret).
|
||||
Require("请输入密码")
|
||||
|
||||
// 校验密码
|
||||
if params.SecretType == dnsconfigs.NSKeySecretTypeBase64 {
|
||||
_, err := base64.StdEncoding.DecodeString(params.Secret)
|
||||
if err != nil {
|
||||
this.FailField("secret", "请输入BASE64格式的密码或者选择明文")
|
||||
}
|
||||
}
|
||||
|
||||
_, err := this.RPC().NSKeyRPC().UpdateNSKey(this.UserContext(), &pb.UpdateNSKeyRequest{
|
||||
NsKeyId: params.KeyId,
|
||||
Name: params.Name,
|
||||
Algo: params.Algo,
|
||||
Secret: params.Secret,
|
||||
SecretType: params.SecretType,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package records
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/dns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/nsutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct {
|
||||
DomainId int64
|
||||
}) {
|
||||
// 域名信息
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindNSDomain(this.UserContext(), &pb.FindNSDomainRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var domain = domainResp.NsDomain
|
||||
if domain == nil {
|
||||
this.NotFound("nsDomain", params.DomainId)
|
||||
return
|
||||
}
|
||||
this.Data["domain"] = maps.Map{
|
||||
"id": domain.Id,
|
||||
"name": domain.Name,
|
||||
}
|
||||
|
||||
// 类型
|
||||
this.Data["types"] = dnsconfigs.FindAllUserRecordTypeDefinitions()
|
||||
|
||||
// 检查限额
|
||||
maxRecords, canCreate, err := nsutils.CheckRecordsQuota(this.UserContext(), params.DomainId, 1)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["quotaMaxRecords"] = maxRecords
|
||||
this.Data["quotaCanCreate"] = canCreate
|
||||
|
||||
defaultTTL, err := nsutils.FindDefaultTTL(this.UserContext())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["defaultTTL"] = defaultTTL
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
AddingType string
|
||||
|
||||
DomainId int64
|
||||
|
||||
Name string
|
||||
Names string
|
||||
|
||||
Type string
|
||||
Value string
|
||||
|
||||
MxPriority int32
|
||||
|
||||
SrvPriority int32
|
||||
SrvWeight int32
|
||||
SrvPort int32
|
||||
|
||||
CaaFlag int32
|
||||
CaaTag string
|
||||
|
||||
Ttl int32
|
||||
Description string
|
||||
RouteCodes []string
|
||||
Weight int32
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
// 检查限额
|
||||
maxRecords, canCreate, err := nsutils.CheckRecordsQuota(this.UserContext(), params.DomainId, 1)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !canCreate {
|
||||
this.Fail("当前域名记录数已超出最大限额(" + types.String(maxRecords) + "个)")
|
||||
}
|
||||
|
||||
maxLoadBalanceRecords, canCreate, err := nsutils.CheckLoadBalanceRecordsQuota(this.UserContext(), params.DomainId, params.Name, params.Type, 1)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !canCreate {
|
||||
this.Fail("当前记录 '" + params.Name + "' 负载均衡数已超出最大限额(" + types.String(maxLoadBalanceRecords) + "个)")
|
||||
}
|
||||
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindNSDomain(this.UserContext(), &pb.FindNSDomainRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var domain = domainResp.NsDomain
|
||||
if domain == nil {
|
||||
this.Fail("找不到要修改的域名")
|
||||
}
|
||||
var domainName = domain.Name
|
||||
|
||||
if params.AddingType == "batch" { // 批量添加
|
||||
defer this.CreateLogInfo(codes.NSRecord_LogCreateNSRecordsBatch)
|
||||
|
||||
if len(params.Names) == 0 {
|
||||
this.FailField("names", "请输入记录名")
|
||||
}
|
||||
|
||||
var names = []string{}
|
||||
for _, name := range strings.Split(params.Names, "\n") {
|
||||
name = strings.TrimSpace(name)
|
||||
if len(name) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if !domainutils.ValidateRecordName(name) {
|
||||
this.FailField("names", "记录名 '"+name+"' 格式不正确,请修改后提交")
|
||||
}
|
||||
|
||||
// 去掉主域名
|
||||
name = strings.TrimSuffix(name, "."+domainName)
|
||||
|
||||
names = append(names, name)
|
||||
}
|
||||
|
||||
// 校验记录值
|
||||
message, ok := domainutils.ValidateRecordValue(params.Type, params.Value)
|
||||
if !ok {
|
||||
this.FailField("value", "记录值错误:"+message)
|
||||
}
|
||||
|
||||
// SRV
|
||||
if params.Type == dnsconfigs.RecordTypeSRV {
|
||||
if params.SrvPort < 0 || params.SrvPort > 65535 {
|
||||
this.FailField("srvPort", "请输入有效的端口号")
|
||||
}
|
||||
}
|
||||
|
||||
// 检查TTL
|
||||
minTTL, err := nsutils.FindMinTTL(this.UserContext())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if params.Ttl < minTTL {
|
||||
this.Fail("TTL不能小于" + types.String(minTTL) + "秒")
|
||||
}
|
||||
|
||||
_, err = this.RPC().NSRecordRPC().CreateNSRecords(this.UserContext(), &pb.CreateNSRecordsRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
Description: params.Description,
|
||||
Names: names,
|
||||
Type: params.Type,
|
||||
Value: params.Value,
|
||||
MxPriority: params.MxPriority,
|
||||
SrvPriority: params.SrvPriority,
|
||||
SrvWeight: params.SrvWeight,
|
||||
SrvPort: params.SrvPort,
|
||||
CaaFlag: params.CaaFlag,
|
||||
CaaTag: params.CaaTag,
|
||||
Ttl: params.Ttl,
|
||||
NsRouteCodes: params.RouteCodes,
|
||||
Weight: params.Weight,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
} else { // 单个添加
|
||||
var recordId int64
|
||||
defer func() {
|
||||
this.CreateLogInfo(codes.NSRecord_LogCreateNSRecord, recordId)
|
||||
}()
|
||||
|
||||
// 校验记录名
|
||||
if !domainutils.ValidateRecordName(params.Name) {
|
||||
this.FailField("name", "请输入正确的记录名")
|
||||
}
|
||||
|
||||
// 校验记录值
|
||||
message, ok := domainutils.ValidateRecordValue(params.Type, params.Value)
|
||||
if !ok {
|
||||
this.FailField("value", "记录值错误:"+message)
|
||||
}
|
||||
|
||||
// 检查TTL
|
||||
minTTL, err := nsutils.FindMinTTL(this.UserContext())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if params.Ttl < minTTL {
|
||||
this.Fail("TTL不能小于" + types.String(minTTL) + "秒")
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().NSRecordRPC().CreateNSRecord(this.UserContext(), &pb.CreateNSRecordRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
Description: params.Description,
|
||||
Name: params.Name,
|
||||
Type: params.Type,
|
||||
Value: params.Value,
|
||||
MxPriority: params.MxPriority,
|
||||
SrvPriority: params.SrvPriority,
|
||||
SrvWeight: params.SrvWeight,
|
||||
SrvPort: params.SrvPort,
|
||||
CaaFlag: params.CaaFlag,
|
||||
CaaTag: params.CaaTag,
|
||||
Ttl: params.Ttl,
|
||||
NsRouteCodes: params.RouteCodes,
|
||||
Weight: params.Weight,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
recordId = createResp.NsRecordId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package records
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
RecordId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSRecord_LogDeleteNSRecord, params.RecordId)
|
||||
|
||||
_, err := this.RPC().NSRecordRPC().DeleteNSRecord(this.UserContext(), &pb.DeleteNSRecordRequest{NsRecordId: params.RecordId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package records
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains/domainutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type HealthCheckPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *HealthCheckPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *HealthCheckPopupAction) RunGet(params struct {
|
||||
RecordId int64
|
||||
}) {
|
||||
// 记录信息
|
||||
recordResp, err := this.RPC().NSRecordRPC().FindNSRecord(this.UserContext(), &pb.FindNSRecordRequest{NsRecordId: params.RecordId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var record = recordResp.NsRecord
|
||||
if record == nil || record.NsDomain == nil {
|
||||
this.NotFound("nsRecord", params.RecordId)
|
||||
return
|
||||
}
|
||||
|
||||
// 记录健康检查
|
||||
var recordHealthCheckConfig = dnsconfigs.NewNSRecordHealthCheckConfig()
|
||||
if len(record.HealthCheckJSON) > 0 {
|
||||
err = json.Unmarshal(record.HealthCheckJSON, recordHealthCheckConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["record"] = maps.Map{
|
||||
"id": record.Id,
|
||||
"name": record.Name,
|
||||
"type": record.Type,
|
||||
"value": record.Value,
|
||||
"healthCheckConfig": recordHealthCheckConfig,
|
||||
}
|
||||
|
||||
// 域名信息
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindNSDomain(this.UserContext(), &pb.FindNSDomainRequest{NsDomainId: record.NsDomain.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var domain = domainResp.NsDomain
|
||||
if domain == nil {
|
||||
this.NotFound("nsDomain", record.NsDomain.Id)
|
||||
return
|
||||
}
|
||||
|
||||
// 域名健康检查
|
||||
var domainHealthCheckConfig = dnsconfigs.NewNSRecordsHealthCheckConfig()
|
||||
if len(domain.RecordsHealthCheckJSON) > 0 {
|
||||
err = json.Unmarshal(domain.RecordsHealthCheckJSON, domainHealthCheckConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["domain"] = maps.Map{
|
||||
"name": domain.Name,
|
||||
"healthCheckConfig": domainHealthCheckConfig,
|
||||
}
|
||||
|
||||
// 检查权限
|
||||
canUpdate, err := domainutils.CheckHealthCheckPermission(this.RPC(), this.UserContext(), record.NsDomain.Id)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if !canUpdate {
|
||||
this.Fail("permission denied")
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *HealthCheckPopupAction) RunPost(params struct {
|
||||
RecordId int64
|
||||
RecordHealthCheckJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSRecord_LogUpdateNSRecordHealthCheck, params.RecordId)
|
||||
|
||||
// 检查权限
|
||||
recordResp, err := this.RPC().NSRecordRPC().FindNSRecord(this.UserContext(), &pb.FindNSRecordRequest{NsRecordId: params.RecordId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var record = recordResp.NsRecord
|
||||
if record == nil || record.NsDomain == nil {
|
||||
this.Fail("找不到要修改的记录")
|
||||
return
|
||||
}
|
||||
|
||||
canUpdate, err := domainutils.CheckHealthCheckPermission(this.RPC(), this.UserContext(), record.NsDomain.Id)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if !canUpdate {
|
||||
this.Fail("permission denied")
|
||||
return
|
||||
}
|
||||
|
||||
var healthCheckConfig = dnsconfigs.NewNSRecordHealthCheckConfig()
|
||||
err = json.Unmarshal(params.RecordHealthCheckJSON, healthCheckConfig)
|
||||
if err != nil {
|
||||
this.Fail("解析配置失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = healthCheckConfig.Init()
|
||||
if err != nil {
|
||||
this.Fail("校验配置失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().NSRecordRPC().UpdateNSRecordHealthCheck(this.UserContext(), &pb.UpdateNSRecordHealthCheckRequest{
|
||||
NsRecordId: params.RecordId,
|
||||
NsRecordHealthCheckJSON: params.RecordHealthCheckJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package records
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains/domainutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "record")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
DomainId int64
|
||||
Type string
|
||||
Keyword string
|
||||
RouteCode string
|
||||
|
||||
NameOrder string
|
||||
TypeOrder string
|
||||
TtlOrder string
|
||||
UpOrder string
|
||||
}) {
|
||||
// 初始化域名信息
|
||||
err := domainutils.InitDomain(this.Parent(), params.DomainId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["type"] = params.Type
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["routeCode"] = params.RouteCode
|
||||
|
||||
// 域名的健康检查
|
||||
domainHealthCheckIsEnabled, err := domainutils.CheckHealthCheckPermission(this.RPC(), this.UserContext(), params.DomainId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var domainHealthCheckIsOn = false
|
||||
if domainHealthCheckIsEnabled {
|
||||
domainHealthCheckResp, err := this.RPC().NSDomainRPC().FindNSDomainRecordsHealthCheck(this.UserContext(), &pb.FindNSDomainRecordsHealthCheckRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(domainHealthCheckResp.NsDomainRecordsHealthCheckJSON) > 0 {
|
||||
var domainHealthCheckConfig = dnsconfigs.NewNSRecordsHealthCheckConfig()
|
||||
err = json.Unmarshal(domainHealthCheckResp.NsDomainRecordsHealthCheckJSON, domainHealthCheckConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
domainHealthCheckIsOn = domainHealthCheckConfig.IsOn
|
||||
}
|
||||
}
|
||||
this.Data["domainHealthCheckIsOn"] = domainHealthCheckIsOn
|
||||
|
||||
// 记录
|
||||
countResp, err := this.RPC().NSRecordRPC().CountAllNSRecords(this.UserContext(), &pb.CountAllNSRecordsRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
Type: params.Type,
|
||||
NsRouteCode: params.RouteCode,
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
var page = this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
recordsResp, err := this.RPC().NSRecordRPC().ListNSRecords(this.UserContext(), &pb.ListNSRecordsRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
Type: params.Type,
|
||||
NsRouteCode: params.RouteCode,
|
||||
Keyword: params.Keyword,
|
||||
NameAsc: params.NameOrder == "asc",
|
||||
NameDesc: params.NameOrder == "desc",
|
||||
TypeAsc: params.TypeOrder == "asc",
|
||||
TypeDesc: params.TypeOrder == "desc",
|
||||
TtlAsc: params.TtlOrder == "asc",
|
||||
TtlDesc: params.TtlOrder == "desc",
|
||||
UpAsc: params.UpOrder == "asc",
|
||||
UpDesc: params.UpOrder == "desc",
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var recordMaps = []maps.Map{}
|
||||
|
||||
var recordIds = []int64{}
|
||||
for _, record := range recordsResp.NsRecords {
|
||||
recordIds = append(recordIds, record.Id)
|
||||
}
|
||||
|
||||
// 统计
|
||||
var statMap = map[int64]maps.Map{} // recordId => Map
|
||||
if len(recordIds) > 0 {
|
||||
statsResp, err := this.RPC().NSRecordHourlyStatRPC().FindNSRecordHourlyStatWithRecordIds(this.UserContext(), &pb.FindNSRecordHourlyStatWithRecordIdsRequest{NsRecordIds: recordIds})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, stat := range statsResp.NsRecordHourlyStats {
|
||||
statMap[stat.NsRecordId] = maps.Map{
|
||||
"bytes": stat.Bytes,
|
||||
"countRequests": stat.CountRequests,
|
||||
"countRequestsFormat": numberutils.FormatCount(stat.CountRequests),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 列表
|
||||
for _, record := range recordsResp.NsRecords {
|
||||
var routeMaps = []maps.Map{}
|
||||
for _, route := range record.NsRoutes {
|
||||
routeMaps = append(routeMaps, maps.Map{
|
||||
"id": route.Id,
|
||||
"name": route.Name,
|
||||
})
|
||||
}
|
||||
|
||||
// 统计
|
||||
recordStatMap, ok := statMap[record.Id]
|
||||
if !ok {
|
||||
recordStatMap = maps.Map{
|
||||
"bytes": 0,
|
||||
"countRequests": 0,
|
||||
"countRequestsFormat": "0",
|
||||
}
|
||||
}
|
||||
|
||||
// 健康检查
|
||||
var recordHealthCheckConfig = dnsconfigs.NewNSRecordHealthCheckConfig()
|
||||
if domainHealthCheckIsOn && len(record.HealthCheckJSON) > 0 {
|
||||
err = json.Unmarshal(record.HealthCheckJSON, recordHealthCheckConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
recordMaps = append(recordMaps, maps.Map{
|
||||
"id": record.Id,
|
||||
"name": record.Name,
|
||||
"type": record.Type,
|
||||
"value": record.Value,
|
||||
"mxPriority": record.MxPriority,
|
||||
"ttl": record.Ttl,
|
||||
"weight": record.Weight,
|
||||
"description": record.Description,
|
||||
"isOn": record.IsOn,
|
||||
"routes": routeMaps,
|
||||
"stat": recordStatMap,
|
||||
|
||||
"healthCheck": recordHealthCheckConfig,
|
||||
"isUp": record.IsUp,
|
||||
})
|
||||
}
|
||||
this.Data["records"] = recordMaps
|
||||
|
||||
// 是否提示可以精准搜索
|
||||
this.Data["enableNameSearch"] = false
|
||||
this.Data["enableValueSearch"] = false
|
||||
this.Data["searchingKeyword"] = params.Keyword
|
||||
if countResp.Count > 0 && len(params.Keyword) > 0 {
|
||||
for _, record := range recordsResp.NsRecords {
|
||||
if record.Name == params.Keyword {
|
||||
this.Data["enableNameSearch"] = true
|
||||
break
|
||||
}
|
||||
if record.Value == params.Keyword {
|
||||
this.Data["enableValueSearch"] = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 所有记录类型
|
||||
this.Data["types"] = dnsconfigs.FindAllUserRecordTypeDefinitions()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package records
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type StatPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *StatPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *StatPopupAction) RunGet(params struct {
|
||||
RecordId int64
|
||||
}) {
|
||||
recordResp, err := this.RPC().NSRecordRPC().FindNSRecord(this.UserContext(), &pb.FindNSRecordRequest{NsRecordId: params.RecordId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var record = recordResp.NsRecord
|
||||
if record == nil {
|
||||
this.NotFound("nsRecord", params.RecordId)
|
||||
return
|
||||
}
|
||||
|
||||
var routeNames = []string{}
|
||||
for _, route := range record.NsRoutes {
|
||||
routeNames = append(routeNames, route.Name)
|
||||
}
|
||||
|
||||
this.Data["record"] = maps.Map{
|
||||
"id": record.Id,
|
||||
"name": record.Name,
|
||||
"routeNames": routeNames,
|
||||
}
|
||||
|
||||
statsResp, err := this.RPC().NSRecordHourlyStatRPC().FindLatestNSRecordsHourlyStats(this.UserContext(), &pb.FindLatestNSRecordsHourlyStatsRequest{NsRecordId: params.RecordId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range statsResp.NsRecordHourlyStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"bytes": stat.Bytes,
|
||||
"countRequests": stat.CountRequests,
|
||||
"hour": stat.Hour,
|
||||
})
|
||||
}
|
||||
this.Data["stats"] = statMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package records
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/dns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/nsutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
RecordId int64
|
||||
}) {
|
||||
recordResp, err := this.RPC().NSRecordRPC().FindNSRecord(this.UserContext(), &pb.FindNSRecordRequest{NsRecordId: params.RecordId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var record = recordResp.NsRecord
|
||||
if record == nil {
|
||||
this.NotFound("nsRecord", params.RecordId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["record"] = maps.Map{
|
||||
"id": record.Id,
|
||||
"name": record.Name,
|
||||
"type": record.Type,
|
||||
"value": record.Value,
|
||||
"mxPriority": record.MxPriority,
|
||||
"srvPriority": record.SrvPriority,
|
||||
"srvWeight": record.SrvWeight,
|
||||
"srvPort": record.SrvPort,
|
||||
"caaFlag": record.CaaFlag,
|
||||
"caaTag": record.CaaTag,
|
||||
"ttl": record.Ttl,
|
||||
"weight": record.Weight,
|
||||
"description": record.Description,
|
||||
"isOn": record.IsOn,
|
||||
"routes": record.NsRoutes,
|
||||
}
|
||||
|
||||
// 域名信息
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindNSDomain(this.UserContext(), &pb.FindNSDomainRequest{NsDomainId: record.NsDomain.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
domain := domainResp.NsDomain
|
||||
if domain == nil {
|
||||
this.NotFound("nsDomain", record.NsDomain.Id)
|
||||
return
|
||||
}
|
||||
this.Data["domain"] = maps.Map{
|
||||
"id": domain.Id,
|
||||
"name": domain.Name,
|
||||
}
|
||||
|
||||
// 类型
|
||||
this.Data["types"] = dnsconfigs.FindAllUserRecordTypeDefinitions()
|
||||
|
||||
// TTL
|
||||
defaultTTL, err := nsutils.FindDefaultTTL(this.UserContext())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["defaultTTL"] = defaultTTL
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
RecordId int64
|
||||
Name string
|
||||
Type string
|
||||
Value string
|
||||
|
||||
MxPriority int32
|
||||
|
||||
SrvPriority int32
|
||||
SrvWeight int32
|
||||
SrvPort int32
|
||||
|
||||
CaaFlag int32
|
||||
CaaTag string
|
||||
|
||||
Ttl int32
|
||||
Description string
|
||||
IsOn bool
|
||||
RouteCodes []string
|
||||
Weight int32
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
this.CreateLogInfo(codes.NSRecord_LogUpdateNSRecordHealthCheck, params.RecordId)
|
||||
|
||||
// 校验记录名
|
||||
if !domainutils.ValidateRecordName(params.Name) {
|
||||
this.FailField("name", "请输入正确的记录名")
|
||||
}
|
||||
|
||||
// 名称是否有改变
|
||||
recordResp, err := this.RPC().NSRecordRPC().FindNSRecord(this.UserContext(), &pb.FindNSRecordRequest{NsRecordId: params.RecordId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var record = recordResp.NsRecord
|
||||
if record == nil || record.NsDomain == nil {
|
||||
this.NotFound("nsRecord", params.RecordId)
|
||||
return
|
||||
}
|
||||
if record.Name != params.Name {
|
||||
// 检查限额
|
||||
maxLoadBalanceRecords, canCreate, err := nsutils.CheckLoadBalanceRecordsQuota(this.UserContext(), record.NsDomain.Id, params.Name, params.Type, 1)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !canCreate {
|
||||
this.Fail("当前记录 '" + params.Name + "' 负载均衡数已超出最大限额(" + types.String(maxLoadBalanceRecords) + "个)")
|
||||
}
|
||||
}
|
||||
|
||||
// 校验记录值
|
||||
message, ok := domainutils.ValidateRecordValue(params.Type, params.Value)
|
||||
if !ok {
|
||||
this.FailField("value", "记录值错误:"+message)
|
||||
}
|
||||
|
||||
// SRV
|
||||
if params.Type == dnsconfigs.RecordTypeSRV {
|
||||
if params.SrvPort < 0 || params.SrvPort > 65535 {
|
||||
this.FailField("srvPort", "请输入有效的端口号")
|
||||
}
|
||||
}
|
||||
|
||||
// 检查TTL
|
||||
minTTL, err := nsutils.FindMinTTL(this.UserContext())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if params.Ttl < minTTL {
|
||||
this.Fail("TTL不能小于" + types.String(minTTL) + "秒")
|
||||
}
|
||||
|
||||
_, err = this.RPC().NSRecordRPC().UpdateNSRecord(this.UserContext(), &pb.UpdateNSRecordRequest{
|
||||
NsRecordId: params.RecordId,
|
||||
Description: params.Description,
|
||||
Name: params.Name,
|
||||
Type: params.Type,
|
||||
Value: params.Value,
|
||||
MxPriority: params.MxPriority,
|
||||
SrvPriority: params.SrvPriority,
|
||||
SrvWeight: params.SrvWeight,
|
||||
SrvPort: params.SrvPort,
|
||||
CaaFlag: params.CaaFlag,
|
||||
CaaTag: params.CaaTag,
|
||||
Ttl: params.Ttl,
|
||||
IsOn: params.IsOn,
|
||||
NsRouteCodes: params.RouteCodes,
|
||||
Weight: params.Weight,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package records
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
)
|
||||
|
||||
type UpdateUpAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateUpAction) RunPost(params struct {
|
||||
RecordId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSRecord_LogUpNSRecord, params.RecordId)
|
||||
|
||||
_, err := this.RPC().NSRecordRPC().UpdateNSRecordIsUp(this.UserContext(), &pb.UpdateNSRecordIsUpRequest{
|
||||
NsRecordId: params.RecordId,
|
||||
IsUp: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
81
EdgeUser/internal/web/actions/default/ns/domains/tsig.go
Normal file
81
EdgeUser/internal/web/actions/default/ns/domains/tsig.go
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package domains
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains/domainutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
)
|
||||
|
||||
type TsigAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TsigAction) Init() {
|
||||
this.Nav("", "", "tsig")
|
||||
}
|
||||
|
||||
func (this *TsigAction) RunGet(params struct {
|
||||
DomainId int64
|
||||
}) {
|
||||
// 初始化域名信息
|
||||
err := domainutils.InitDomain(this.Parent(), params.DomainId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// TSIG信息
|
||||
tsigResp, err := this.RPC().NSDomainRPC().FindNSDomainTSIG(this.UserContext(), &pb.FindNSDomainTSIGRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var tsigJSON = tsigResp.TsigJSON
|
||||
|
||||
var tsigConfig = &dnsconfigs.NSTSIGConfig{}
|
||||
if len(tsigJSON) > 0 {
|
||||
err = json.Unmarshal(tsigJSON, tsigConfig)
|
||||
if err != nil {
|
||||
// 只是提示错误,仍然允许用户修改
|
||||
logs.Error(err)
|
||||
}
|
||||
}
|
||||
this.Data["tsig"] = tsigConfig
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *TsigAction) RunPost(params struct {
|
||||
DomainId int64
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSDomain_LogUpdateNSDomainTSIG, params.DomainId)
|
||||
|
||||
var tsigConfig = &dnsconfigs.NSTSIGConfig{
|
||||
IsOn: params.IsOn,
|
||||
}
|
||||
tsigJSON, err := json.Marshal(tsigConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, err = this.RPC().NSDomainRPC().UpdateNSDomainTSIG(this.UserContext(), &pb.UpdateNSDomainTSIGRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
TsigJSON: tsigJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
122
EdgeUser/internal/web/actions/default/ns/domains/update.go
Normal file
122
EdgeUser/internal/web/actions/default/ns/domains/update.go
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package domains
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains/domainutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UpdateAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateAction) Init() {
|
||||
this.Nav("", "", "update")
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunGet(params struct {
|
||||
DomainId int64
|
||||
}) {
|
||||
// 初始化域名信息
|
||||
err := domainutils.InitDomain(this.Parent(), params.DomainId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countRecords = this.Data.GetMap("domain").GetInt64("countRecords")
|
||||
var countKeys = this.Data.GetMap("domain").GetInt64("countKeys")
|
||||
|
||||
// 域名信息
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindNSDomain(this.UserContext(), &pb.FindNSDomainRequest{NsDomainId: params.DomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
domain := domainResp.NsDomain
|
||||
if domain == nil {
|
||||
this.NotFound("nsDomain", params.DomainId)
|
||||
return
|
||||
}
|
||||
|
||||
var clusterId = int64(0)
|
||||
if domain.NsCluster != nil {
|
||||
clusterId = domain.NsCluster.Id
|
||||
}
|
||||
|
||||
// 用户信息
|
||||
var userId = int64(0)
|
||||
if domain.User != nil {
|
||||
userId = domain.User.Id
|
||||
}
|
||||
|
||||
// 分组信息
|
||||
var groupId int64
|
||||
if len(domain.NsDomainGroups) > 0 {
|
||||
groupId = domain.NsDomainGroups[0].Id
|
||||
}
|
||||
|
||||
this.Data["domain"] = maps.Map{
|
||||
"id": domain.Id,
|
||||
"name": domain.Name,
|
||||
"isOn": domain.IsOn,
|
||||
"clusterId": clusterId,
|
||||
"userId": userId,
|
||||
"countRecords": countRecords,
|
||||
"countKeys": countKeys,
|
||||
"groupId": groupId,
|
||||
}
|
||||
|
||||
// DNS服务器
|
||||
if domain.NsCluster == nil || domain.NsCluster.Id <= 0 {
|
||||
this.WriteString("当前域名(" + domain.Name + ")所在集群已被删除,请删除当前域名后重新添加")
|
||||
return
|
||||
}
|
||||
|
||||
hostsResp, err := this.RPC().NSClusterRPC().FindNSClusterHosts(this.UserContext(), &pb.FindNSClusterHostsRequest{
|
||||
NsClusterId: domain.NsCluster.Id,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var hosts = hostsResp.Hosts
|
||||
if hosts == nil {
|
||||
hosts = []string{}
|
||||
}
|
||||
this.Data["dnsHosts"] = hosts
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
DomainId int64
|
||||
GroupId int64
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSDomain_LogUpdateNSDomain, params.DomainId)
|
||||
|
||||
var groupIds = []int64{}
|
||||
if params.GroupId > 0 {
|
||||
groupIds = append(groupIds, params.GroupId)
|
||||
}
|
||||
|
||||
_, err := this.RPC().NSDomainRPC().UpdateNSDomain(this.UserContext(), &pb.UpdateNSDomainRequest{
|
||||
NsDomainId: params.DomainId,
|
||||
NsDomainGroupIds: groupIds,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package domains
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains/domainutils"
|
||||
)
|
||||
|
||||
type VerifyPageAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *VerifyPageAction) RunPost(params struct {
|
||||
DomainIds []int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSDomain_LogValidateNSDomains)
|
||||
|
||||
if len(params.DomainIds) == 0 {
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
for _, domainId := range params.DomainIds {
|
||||
// 检查域名信息
|
||||
domainResp, err := this.RPC().NSDomainRPC().FindNSDomain(this.UserContext(), &pb.FindNSDomainRequest{NsDomainId: domainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var domain = domainResp.NsDomain
|
||||
if domain == nil || domain.Status != dnsconfigs.NSDomainStatusNone {
|
||||
continue
|
||||
}
|
||||
|
||||
verifyResp, err := this.RPC().NSDomainRPC().VerifyNSDomain(this.UserContext(), &pb.VerifyNSDomainRequest{NsDomainId: domainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !verifyResp.IsOk {
|
||||
var message = domainutils.VerifyMessageWithCode(verifyResp.ErrorCode)
|
||||
if len(message) > 0 {
|
||||
this.Fail("域名 '" + domain.Name + "' 验证失败:" + message)
|
||||
return
|
||||
}
|
||||
this.Fail("域名 '" + domain.Name + "' 验证失败")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
147
EdgeUser/internal/web/actions/default/ns/index.go
Normal file
147
EdgeUser/internal/web/actions/default/ns/index.go
Normal file
@@ -0,0 +1,147 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package ns
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "ns")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
// 跳转到域名
|
||||
this.RedirectURL("/ns/domains")
|
||||
|
||||
return
|
||||
resp, err := this.RPC().NSRPC().ComposeNSBoard(this.UserContext(), &pb.ComposeNSBoardRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["board"] = maps.Map{
|
||||
"countDomains": resp.CountNSDomains,
|
||||
"countRecords": resp.CountNSRecords,
|
||||
"countClusters": resp.CountNSClusters,
|
||||
"countNodes": resp.CountNSNodes,
|
||||
"countOfflineNodes": resp.CountOfflineNSNodes,
|
||||
}
|
||||
|
||||
// 流量排行
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.HourlyTrafficStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"day": stat.Hour[4:6] + "月" + stat.Hour[6:8] + "日",
|
||||
"hour": stat.Hour[8:],
|
||||
"countRequests": stat.CountRequests,
|
||||
"bytes": stat.Bytes,
|
||||
})
|
||||
}
|
||||
this.Data["hourlyStats"] = statMaps
|
||||
}
|
||||
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.DailyTrafficStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"day": stat.Day[4:6] + "月" + stat.Day[6:] + "日",
|
||||
"countRequests": stat.CountRequests,
|
||||
"bytes": stat.Bytes,
|
||||
})
|
||||
}
|
||||
this.Data["dailyStats"] = statMaps
|
||||
}
|
||||
|
||||
// 域名排行
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.TopNSDomainStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"domainId": stat.NsDomainId,
|
||||
"domainName": stat.NsDomainName,
|
||||
"countRequests": stat.CountRequests,
|
||||
"bytes": stat.Bytes,
|
||||
})
|
||||
}
|
||||
this.Data["topDomainStats"] = statMaps
|
||||
}
|
||||
|
||||
// 节点排行
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.TopNSNodeStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"clusterId": stat.NsClusterId,
|
||||
"nodeId": stat.NsNodeId,
|
||||
"nodeName": stat.NsNodeName,
|
||||
"countRequests": stat.CountRequests,
|
||||
"bytes": stat.Bytes,
|
||||
})
|
||||
}
|
||||
this.Data["topNodeStats"] = statMaps
|
||||
}
|
||||
|
||||
// CPU
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.CpuNodeValues {
|
||||
var valueMap = maps.Map{}
|
||||
err = json.Unmarshal(stat.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||
"value": valueMap.GetFloat32("usage"),
|
||||
})
|
||||
}
|
||||
this.Data["cpuValues"] = statMaps
|
||||
}
|
||||
|
||||
// Memory
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.MemoryNodeValues {
|
||||
var valueMap = maps.Map{}
|
||||
err = json.Unmarshal(stat.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||
"value": valueMap.GetFloat32("usage"),
|
||||
})
|
||||
}
|
||||
this.Data["memoryValues"] = statMaps
|
||||
}
|
||||
|
||||
// Load
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.LoadNodeValues {
|
||||
var valueMap = maps.Map{}
|
||||
err = json.Unmarshal(stat.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||
"value": valueMap.GetFloat32("load1m"),
|
||||
})
|
||||
}
|
||||
this.Data["loadValues"] = statMaps
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
98
EdgeUser/internal/web/actions/default/ns/init.go
Normal file
98
EdgeUser/internal/web/actions/default/ns/init.go
Normal file
@@ -0,0 +1,98 @@
|
||||
//go:build plus
|
||||
|
||||
package ns
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains/batch"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains/domain"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains/groups"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains/groups/group"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains/keys"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/domains/records"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/plans"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth("")).
|
||||
Data("teaMenu", "ns").
|
||||
Prefix("/ns").
|
||||
Get("", new(IndexAction)).
|
||||
|
||||
// 域名列表
|
||||
Prefix("/ns/domains").
|
||||
Data("teaSubMenu", "domain").
|
||||
Get("", new(domains.IndexAction)).
|
||||
GetPost("/create", new(domains.CreateAction)).
|
||||
Post("/delete", new(domains.DeleteAction)).
|
||||
Post("/deletePage", new(domains.DeletePageAction)).
|
||||
Post("/verifyPage", new(domains.VerifyPageAction)).
|
||||
GetPost("/update", new(domains.UpdateAction)).
|
||||
GetPost("/tsig", new(domains.TsigAction)).
|
||||
GetPost("/healthCheck", new(domains.HealthCheckAction)).
|
||||
|
||||
// 单个域名
|
||||
Prefix("/ns/domains/domain").
|
||||
Data("teaSubMenu", "domain").
|
||||
Get("", new(domain.IndexAction)).
|
||||
GetPost("/updateStatusPopup", new(domain.UpdateStatusPopupAction)).
|
||||
GetPost("/verifyPopup", new(domain.VerifyPopupAction)).
|
||||
|
||||
// 域名批量操作
|
||||
Prefix("/ns/domains/batch").
|
||||
Data("teaSubMenu", "domainBatch").
|
||||
GetPost("", new(batch.IndexAction)).
|
||||
GetPost("/createRecords", new(batch.CreateRecordsAction)).
|
||||
GetPost("/deleteDomains", new(batch.DeleteDomainsAction)).
|
||||
GetPost("/updateRecords", new(batch.UpdateRecordsAction)).
|
||||
GetPost("/enableRecords", new(batch.EnableRecordsAction)).
|
||||
GetPost("/importRecords", new(batch.ImportRecordsAction)).
|
||||
GetPost("/deleteRecords", new(batch.DeleteRecordsAction)).
|
||||
|
||||
// 域名密钥
|
||||
Prefix("/ns/domains/keys").
|
||||
Data("teaSubMenu", "domain").
|
||||
Get("", new(keys.IndexAction)).
|
||||
GetPost("/createPopup", new(keys.CreatePopupAction)).
|
||||
GetPost("/updatePopup", new(keys.UpdatePopupAction)).
|
||||
Post("/delete", new(keys.DeleteAction)).
|
||||
Post("/generateSecret", new(keys.GenerateSecretAction)).
|
||||
|
||||
// 记录相关
|
||||
Prefix("/ns/domains/records").
|
||||
Get("", new(records.IndexAction)).
|
||||
GetPost("/createPopup", new(records.CreatePopupAction)).
|
||||
GetPost("/updatePopup", new(records.UpdatePopupAction)).
|
||||
Post("/delete", new(records.DeleteAction)).
|
||||
GetPost("/statPopup", new(records.StatPopupAction)).
|
||||
GetPost("/healthCheckPopup", new(records.HealthCheckPopupAction)).
|
||||
Post("/updateUp", new(records.UpdateUpAction)).
|
||||
|
||||
// 域名分组列表
|
||||
Prefix("/ns/domains/groups").
|
||||
Data("teaSubMenu", "domainGroup").
|
||||
Get("", new(groups.IndexAction)).
|
||||
GetPost("/createPopup", new(groups.CreatePopupAction)).
|
||||
Post("/options", new(groups.OptionsAction)).
|
||||
|
||||
// 域名分组
|
||||
Prefix("/ns/domains/groups/group").
|
||||
Data("teaSubMenu", "domainGroup").
|
||||
Get("", new(group.IndexAction)).
|
||||
GetPost("/updatePopup", new(group.UpdatePopupAction)).
|
||||
Post("/delete", new(group.DeleteAction)).
|
||||
|
||||
// 套餐
|
||||
Prefix("/ns/plans").
|
||||
Data("teaSubMenu", "plan").
|
||||
Get("", new(plans.IndexAction)).
|
||||
GetPost("/buy", new(plans.BuyAction)).
|
||||
|
||||
//
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
7
EdgeUser/internal/web/actions/default/ns/init_empty.go
Normal file
7
EdgeUser/internal/web/actions/default/ns/init_empty.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package ns
|
||||
|
||||
// 此文件用于在非 Plus 版本中保持包的完整性
|
||||
// Plus 版本的功能在 init.go 中实现(需要 //go:build plus 标签)
|
||||
235
EdgeUser/internal/web/actions/default/ns/nsutils/utils.go
Normal file
235
EdgeUser/internal/web/actions/default/ns/nsutils/utils.go
Normal file
@@ -0,0 +1,235 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package nsutils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/rpc"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// FindUserPlanConfig 用户配置
|
||||
// 需要保证非 error 的情况下,一定会返回一个不为空的 NSPlanConfig
|
||||
func FindUserPlanConfig(ctx context.Context) (*dnsconfigs.NSPlanConfig, error) {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 从套餐中读取
|
||||
userPlanResp, err := rpcClient.NSUserPlanRPC().FindNSUserPlan(ctx, &pb.FindNSUserPlanRequest{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userPlanResp.NsUserPlan != nil &&
|
||||
len(userPlanResp.NsUserPlan.DayTo) > 0 &&
|
||||
userPlanResp.NsUserPlan.DayTo >= timeutil.Format("Ymd") /** 在有效期内 **/ {
|
||||
var planId = userPlanResp.NsUserPlan.NsPlanId
|
||||
if planId > 0 {
|
||||
planResp, err := rpcClient.NSPlanRPC().FindNSPlan(ctx, &pb.FindNSPlanRequest{NsPlanId: planId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if planResp.NsPlan != nil &&
|
||||
len(planResp.NsPlan.ConfigJSON) > 0 &&
|
||||
planResp.NsPlan.IsOn {
|
||||
var config = dnsconfigs.DefaultNSUserPlanConfig()
|
||||
err = json.Unmarshal(planResp.NsPlan.ConfigJSON, config)
|
||||
if err != nil {
|
||||
return nil, errors.New("decode plan config failed '" + err.Error() + "'")
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 从用户设置中读取
|
||||
userConfigResp, err := rpcClient.SysSettingRPC().ReadSysSetting(ctx, &pb.ReadSysSettingRequest{Code: systemconfigs.SettingCodeNSUserConfig})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(userConfigResp.ValueJSON) > 0 {
|
||||
var config = dnsconfigs.NewNSUserConfig()
|
||||
err = json.Unmarshal(userConfigResp.ValueJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.DefaultPlanConfig != nil {
|
||||
return config.DefaultPlanConfig, nil
|
||||
}
|
||||
}
|
||||
|
||||
return dnsconfigs.DefaultNSUserPlanConfig(), nil
|
||||
}
|
||||
|
||||
// FindBasicPlan 查找基础套餐
|
||||
func FindBasicPlan(ctx context.Context) (*dnsconfigs.NSPlanConfig, error) {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 从用户设置中读取
|
||||
userConfigResp, err := rpcClient.SysSettingRPC().ReadSysSetting(ctx, &pb.ReadSysSettingRequest{Code: systemconfigs.SettingCodeNSUserConfig})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(userConfigResp.ValueJSON) > 0 {
|
||||
var config = dnsconfigs.NewNSUserConfig()
|
||||
err = json.Unmarshal(userConfigResp.ValueJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.DefaultPlanConfig != nil {
|
||||
return config.DefaultPlanConfig, nil
|
||||
}
|
||||
}
|
||||
|
||||
return dnsconfigs.DefaultNSUserPlanConfig(), nil
|
||||
}
|
||||
|
||||
// CheckDomainsQuote 检查域名限额
|
||||
func CheckDomainsQuote(ctx context.Context, countNew int32) (maxDomains int32, ok bool, err error) {
|
||||
config, err := FindUserPlanConfig(ctx)
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
maxDomains = config.MaxDomains
|
||||
if maxDomains <= 0 {
|
||||
return 0, true, nil
|
||||
}
|
||||
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return maxDomains, false, err
|
||||
}
|
||||
|
||||
countDomainsResp, err := rpcClient.NSDomainRPC().CountAllNSDomains(ctx, &pb.CountAllNSDomainsRequest{})
|
||||
if err != nil {
|
||||
return maxDomains, false, err
|
||||
}
|
||||
|
||||
if countDomainsResp.Count+int64(countNew) > int64(maxDomains) {
|
||||
return maxDomains, false, nil
|
||||
}
|
||||
return maxDomains, true, nil
|
||||
}
|
||||
|
||||
// CheckRecordsQuota 检查记录限额
|
||||
func CheckRecordsQuota(ctx context.Context, domainId int64, countNew int32) (maxRecords int32, ok bool, err error) {
|
||||
config, err := FindUserPlanConfig(ctx)
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
maxRecords = config.MaxRecordsPerDomain
|
||||
if maxRecords <= 0 {
|
||||
return 0, true, nil
|
||||
}
|
||||
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return maxRecords, false, err
|
||||
}
|
||||
|
||||
countRecordsResp, err := rpcClient.NSRecordRPC().CountAllNSRecords(ctx, &pb.CountAllNSRecordsRequest{
|
||||
NsDomainId: domainId,
|
||||
})
|
||||
if err != nil {
|
||||
return maxRecords, false, err
|
||||
}
|
||||
|
||||
if countRecordsResp.Count+int64(countNew) > int64(maxRecords) {
|
||||
return maxRecords, false, nil
|
||||
}
|
||||
return maxRecords, true, nil
|
||||
}
|
||||
|
||||
// CheckLoadBalanceRecordsQuota 检查负载均衡限额
|
||||
func CheckLoadBalanceRecordsQuota(ctx context.Context, domainId int64, recordName string, recordType string, countNew int32) (maxRecords int32, ok bool, err error) {
|
||||
recordName = strings.ToLower(recordName)
|
||||
recordType = strings.ToUpper(recordType)
|
||||
|
||||
config, err := FindUserPlanConfig(ctx)
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
maxRecords = config.MaxLoadBalanceRecordsPerRecord
|
||||
if maxRecords <= 0 {
|
||||
return 0, true, nil
|
||||
}
|
||||
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return maxRecords, false, err
|
||||
}
|
||||
|
||||
countRecordsResp, err := rpcClient.NSRecordRPC().CountAllNSRecordsWithName(ctx, &pb.CountAllNSRecordsWithNameRequest{
|
||||
NsDomainId: domainId,
|
||||
Name: recordName,
|
||||
Type: recordType,
|
||||
})
|
||||
if err != nil {
|
||||
return maxRecords, false, err
|
||||
}
|
||||
|
||||
if countRecordsResp.Count+int64(countNew) > int64(maxRecords) {
|
||||
return maxRecords, false, nil
|
||||
}
|
||||
return maxRecords, true, nil
|
||||
}
|
||||
|
||||
// FindMinTTL 获取最小的TTL
|
||||
func FindMinTTL(ctx context.Context) (int32, error) {
|
||||
config, err := FindUserPlanConfig(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return config.MinTTL, nil
|
||||
}
|
||||
|
||||
func FindDefaultTTL(ctx context.Context) (int32, error) {
|
||||
config, err := FindUserPlanConfig(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var minTTL = config.MinTTL
|
||||
|
||||
if minTTL > 600 {
|
||||
return minTTL, nil
|
||||
}
|
||||
return 600, nil
|
||||
}
|
||||
|
||||
// CheckRoutesQuota 检查线路限额
|
||||
func CheckRoutesQuota(ctx context.Context, countNew int32) (maxCustomRoutes int32, ok bool, err error) {
|
||||
config, err := FindUserPlanConfig(ctx)
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
maxCustomRoutes = config.MaxCustomRoutes
|
||||
if maxCustomRoutes <= 0 {
|
||||
return 0, true, nil
|
||||
}
|
||||
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return maxCustomRoutes, false, err
|
||||
}
|
||||
|
||||
countRoutesResp, err := rpcClient.NSRouteRPC().CountAllNSRoutes(ctx, &pb.CountAllNSRoutesRequest{})
|
||||
if err != nil {
|
||||
return maxCustomRoutes, false, err
|
||||
}
|
||||
|
||||
if countRoutesResp.Count+int64(countNew) > int64(maxCustomRoutes) {
|
||||
return maxCustomRoutes, false, nil
|
||||
}
|
||||
return maxCustomRoutes, true, nil
|
||||
}
|
||||
158
EdgeUser/internal/web/actions/default/ns/plans/buy.go
Normal file
158
EdgeUser/internal/web/actions/default/ns/plans/buy.go
Normal file
@@ -0,0 +1,158 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package plans
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/finance/financeutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
type BuyAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *BuyAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *BuyAction) RunGet(params struct {
|
||||
PlanId int64
|
||||
}) {
|
||||
planResp, err := this.RPC().NSPlanRPC().FindNSPlan(this.UserContext(), &pb.FindNSPlanRequest{NsPlanId: params.PlanId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var plan = planResp.NsPlan
|
||||
if plan == nil || !plan.IsOn {
|
||||
this.NotFound("nsPlan", params.PlanId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["plan"] = maps.Map{
|
||||
"id": plan.Id,
|
||||
"name": plan.Name,
|
||||
"monthlyPrice": fmt.Sprintf("%.2f", plan.MonthlyPrice),
|
||||
"yearlyPrice": fmt.Sprintf("%.2f", plan.YearlyPrice),
|
||||
"monthFrom": timeutil.Format("Y-m-d"),
|
||||
"monthTo": timeutil.Format("Y-m-d", time.Now().AddDate(0, 1, 0)),
|
||||
"yearFrom": timeutil.Format("Y-m-d"),
|
||||
"yearTo": timeutil.Format("Y-m-d", time.Now().AddDate(1, 0, 0)),
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *BuyAction) RunPost(params struct {
|
||||
PlanId int64
|
||||
Period string
|
||||
MethodCode string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
planResp, err := this.RPC().NSPlanRPC().FindNSPlan(this.UserContext(), &pb.FindNSPlanRequest{NsPlanId: params.PlanId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var plan = planResp.NsPlan
|
||||
if plan == nil || !plan.IsOn {
|
||||
this.NotFound("nsPlan", params.PlanId)
|
||||
return
|
||||
}
|
||||
|
||||
var price float64
|
||||
var dayFrom = timeutil.Format("Ymd")
|
||||
var dayTo = dayFrom
|
||||
switch params.Period {
|
||||
case "yearly":
|
||||
price = float64(plan.YearlyPrice)
|
||||
dayTo = timeutil.Format("Ymd", time.Now().AddDate(1, 0, 0))
|
||||
case "monthly":
|
||||
price = float64(plan.MonthlyPrice)
|
||||
dayTo = timeutil.Format("Ymd", time.Now().AddDate(0, 1, 0))
|
||||
default:
|
||||
this.Fail("请输入正确的付费周期")
|
||||
return
|
||||
}
|
||||
|
||||
// 用户是否已经购买了套餐
|
||||
userPlanResp, err := this.RPC().NSUserPlanRPC().FindNSUserPlan(this.UserContext(), &pb.FindNSUserPlanRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if userPlanResp.NsUserPlan != nil && userPlanResp.NsUserPlan.DayTo >= timeutil.Format("Ymd") {
|
||||
this.Fail("当前已经有一个生效的套餐,无法重复购买")
|
||||
}
|
||||
|
||||
// 使用余额购买
|
||||
this.Data["success"] = false
|
||||
this.Data["orderCode"] = ""
|
||||
if params.MethodCode == "@balance" {
|
||||
balance, err := financeutils.FindUserBalance(this.UserContext())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if price > balance {
|
||||
this.Fail("当前余额不足,需要:" + fmt.Sprintf("%.2f元", price) + ",现有:" + fmt.Sprintf("%.2f元", balance) + " ,请充值后再试")
|
||||
return
|
||||
}
|
||||
|
||||
// 直接购买
|
||||
_, err = this.RPC().NSUserPlanRPC().BuyNSUserPlan(this.UserContext(), &pb.BuyNSUserPlanRequest{
|
||||
UserId: this.UserId(),
|
||||
PlanId: plan.Id,
|
||||
Period: params.Period,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["success"] = true
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
// 生成订单
|
||||
var orderParams = &userconfigs.OrderTypeBuyNSPlanParams{
|
||||
PlanId: plan.Id,
|
||||
DayFrom: dayFrom,
|
||||
DayTo: dayTo,
|
||||
Period: params.Period,
|
||||
}
|
||||
orderParamsJSON, err := json.Marshal(orderParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := this.RPC().UserOrderRPC().CreateUserOrder(this.UserContext(), &pb.CreateUserOrderRequest{
|
||||
Type: userconfigs.OrderTypeBuyNSPlan,
|
||||
OrderMethodCode: params.MethodCode,
|
||||
Amount: price,
|
||||
ParamsJSON: orderParamsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["orderCode"] = resp.Code
|
||||
|
||||
this.Success()
|
||||
}
|
||||
92
EdgeUser/internal/web/actions/default/ns/plans/index.go
Normal file
92
EdgeUser/internal/web/actions/default/ns/plans/index.go
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package plans
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/nsutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
// 当前我的套餐
|
||||
userPlanResp, err := this.RPC().NSUserPlanRPC().FindNSUserPlan(this.UserContext(), &pb.FindNSUserPlanRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var userPlan = userPlanResp.NsUserPlan
|
||||
this.Data["userPlan"] = nil
|
||||
if userPlan != nil && userPlan.NsPlan != nil {
|
||||
if len(userPlan.DayTo) < 8 {
|
||||
userPlan.DayTo = timeutil.Format("Ymd")
|
||||
}
|
||||
this.Data["userPlan"] = maps.Map{
|
||||
"dayTo": userPlan.DayTo[:4] + "-" + userPlan.DayTo[4:6] + "-" + userPlan.DayTo[6:],
|
||||
"isExpired": userPlan.DayTo < timeutil.Format("Ymd"),
|
||||
"plan": maps.Map{
|
||||
"id": userPlan.NsPlan.Id,
|
||||
"name": userPlan.NsPlan.Name,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var planMaps = []maps.Map{}
|
||||
|
||||
// 基础套餐
|
||||
basicPlanConfig, err := nsutils.FindBasicPlan(this.UserContext())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
planMaps = append(planMaps, maps.Map{
|
||||
"id": 0,
|
||||
"name": "注册用户",
|
||||
"monthlyPrice": 0,
|
||||
"yearlyPrice": 0,
|
||||
"config": basicPlanConfig,
|
||||
})
|
||||
|
||||
// 所有套餐
|
||||
plansResp, err := this.RPC().NSPlanRPC().FindAllEnabledNSPlans(this.UserContext(), &pb.FindAllEnabledNSPlansRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, plan := range plansResp.NsPlans {
|
||||
var config = &dnsconfigs.NSPlanConfig{}
|
||||
if len(plan.ConfigJSON) == 0 {
|
||||
continue
|
||||
}
|
||||
err = json.Unmarshal(plan.ConfigJSON, config)
|
||||
if err != nil {
|
||||
remotelogs.Error("NSPlan", "decode plan config failed: plan: "+types.String(plan.Id)+": "+err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
planMaps = append(planMaps, maps.Map{
|
||||
"id": plan.Id,
|
||||
"name": plan.Name,
|
||||
"monthlyPrice": plan.MonthlyPrice,
|
||||
"yearlyPrice": plan.YearlyPrice,
|
||||
"config": config,
|
||||
})
|
||||
}
|
||||
this.Data["plans"] = planMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/nsutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
DomainId int64
|
||||
UserId int64
|
||||
}) {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["domainId"] = params.DomainId
|
||||
this.Data["userId"] = params.UserId
|
||||
|
||||
this.Data["rangeTypes"] = dnsconfigs.AllNSRouteRangeTypes()
|
||||
|
||||
// 线路限额
|
||||
maxCustomRoutes, canCreate, err := nsutils.CheckRoutesQuota(this.UserContext(), 1)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["quotaMaxCustomRoutes"] = maxCustomRoutes
|
||||
this.Data["quotaCanCreate"] = canCreate
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
DomainId int64
|
||||
UserId int64
|
||||
|
||||
Name string
|
||||
RangesJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var routeId = int64(0)
|
||||
defer func() {
|
||||
this.CreateLogInfo(codes.NSRoute_LogCreateNSRoute, routeId)
|
||||
}()
|
||||
|
||||
// 线路限额
|
||||
maxCustomRoutes, canCreate, err := nsutils.CheckRoutesQuota(this.UserContext(), 1)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !canCreate {
|
||||
this.Fail("超出线路最大限额(" + types.String(maxCustomRoutes) + "个),请升级套餐后再试")
|
||||
return
|
||||
}
|
||||
|
||||
params.Must.Field("name", params.Name).
|
||||
Require("请输入线路名称")
|
||||
|
||||
ranges, err := dnsconfigs.InitNSRangesFromJSON(params.RangesJSON)
|
||||
if err != nil {
|
||||
this.Fail("配置校验失败:" + err.Error())
|
||||
}
|
||||
|
||||
if len(ranges) == 0 {
|
||||
this.Fail("请添加线路范围")
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().NSRouteRPC().CreateNSRoute(this.UserContext(), &pb.CreateNSRouteRequest{
|
||||
NsClusterId: params.ClusterId,
|
||||
NsDomainId: params.DomainId,
|
||||
UserId: params.UserId,
|
||||
Name: params.Name,
|
||||
RangesJSON: params.RangesJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
routeId = createResp.NsRouteId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
27
EdgeUser/internal/web/actions/default/ns/routes/delete.go
Normal file
27
EdgeUser/internal/web/actions/default/ns/routes/delete.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
RouteId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSRoute_LogDeleteNSRoute, params.RouteId)
|
||||
|
||||
_, err := this.RPC().NSRouteRPC().DeleteNSRoute(this.UserContext(), &pb.DeleteNSRouteRequest{NsRouteId: params.RouteId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
41
EdgeUser/internal/web/actions/default/ns/routes/index.go
Normal file
41
EdgeUser/internal/web/actions/default/ns/routes/index.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
routesResp, err := this.RPC().NSRouteRPC().FindAllNSRoutes(this.UserContext(), &pb.FindAllNSRoutesRequest{
|
||||
NsClusterId: 0,
|
||||
NsDomainId: 0,
|
||||
UserId: 0,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var routeMaps = []maps.Map{}
|
||||
for _, route := range routesResp.NsRoutes {
|
||||
routeMaps = append(routeMaps, maps.Map{
|
||||
"id": route.Id,
|
||||
"name": route.Name,
|
||||
"isOn": route.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["routes"] = routeMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
25
EdgeUser/internal/web/actions/default/ns/routes/init.go
Normal file
25
EdgeUser/internal/web/actions/default/ns/routes/init.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth("")).
|
||||
Data("teaMenu", "ns").
|
||||
Data("teaSubMenu", "route").
|
||||
Prefix("/ns/routes").
|
||||
Get("", new(IndexAction)).
|
||||
Get("/route", new(RouteAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
GetPost("/updatePopup", new(UpdatePopupAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
Post("/sort", new(SortAction)).
|
||||
Post("/options", new(OptionsAction)).
|
||||
Get("/internal", new(InternalAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
89
EdgeUser/internal/web/actions/default/ns/routes/internal.go
Normal file
89
EdgeUser/internal/web/actions/default/ns/routes/internal.go
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type InternalAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *InternalAction) Init() {
|
||||
this.Nav("", "", "internal")
|
||||
}
|
||||
|
||||
func (this *InternalAction) RunGet(params struct{}) {
|
||||
this.Data["ispRoutes"] = dnsconfigs.AllDefaultISPRoutes
|
||||
this.Data["chinaProvinceRoutes"] = dnsconfigs.AllDefaultChinaProvinceRoutes
|
||||
this.Data["worldRegionRoutes"] = dnsconfigs.AllDefaultWorldRegionRoutes
|
||||
|
||||
// Agent相关线路
|
||||
agentsResp, err := this.RPC().NSRouteRPC().FindAllAgentNSRoutes(this.UserContext(), &pb.FindAllAgentNSRoutesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var agentRouteMaps = []maps.Map{}
|
||||
for _, route := range agentsResp.NsRoutes {
|
||||
agentRouteMaps = append(agentRouteMaps, maps.Map{
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
})
|
||||
}
|
||||
this.Data["agentRoutes"] = agentRouteMaps
|
||||
|
||||
// 系统内置公用线路
|
||||
publicRoutesResp, err := this.RPC().NSRouteRPC().FindAllPublicNSRoutes(this.UserContext(), &pb.FindAllPublicRoutesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var publicCategoryMaps = []maps.Map{}
|
||||
var publicCategoryIds = []int64{}
|
||||
var publicRouteMaps = []maps.Map{}
|
||||
for _, route := range publicRoutesResp.NsRoutes {
|
||||
var categoryId int64 = 0
|
||||
if route.NsRouteCategory != nil {
|
||||
categoryId = route.NsRouteCategory.Id
|
||||
}
|
||||
|
||||
publicRouteMaps = append(publicRouteMaps, maps.Map{
|
||||
"id": route.Id,
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
"categoryId": categoryId,
|
||||
})
|
||||
|
||||
// 未分类
|
||||
if route.NsRouteCategory == nil {
|
||||
if !lists.ContainsInt64(publicCategoryIds, 0) {
|
||||
publicCategoryIds = append(publicCategoryIds, 0)
|
||||
publicCategoryMaps = append(publicCategoryMaps, maps.Map{
|
||||
"id": 0,
|
||||
"name": "官方线路",
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// 有分类
|
||||
if !lists.ContainsInt64(publicCategoryIds, route.NsRouteCategory.Id) {
|
||||
publicCategoryIds = append(publicCategoryIds, route.NsRouteCategory.Id)
|
||||
publicCategoryMaps = append(publicCategoryMaps, maps.Map{
|
||||
"id": route.NsRouteCategory.Id,
|
||||
"name": route.NsRouteCategory.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["publicCategories"] = publicCategoryMaps
|
||||
this.Data["publicRoutes"] = publicRouteMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
203
EdgeUser/internal/web/actions/default/ns/routes/options.go
Normal file
203
EdgeUser/internal/web/actions/default/ns/routes/options.go
Normal file
@@ -0,0 +1,203 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/ns/nsutils"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type OptionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *OptionsAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
DomainId int64
|
||||
UserId int64
|
||||
}) {
|
||||
var routeMaps = []maps.Map{}
|
||||
|
||||
planConfig, err := nsutils.FindUserPlanConfig(this.UserContext())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 默认线路
|
||||
for _, route := range dnsconfigs.AllDefaultRoutes {
|
||||
routeMaps = append(routeMaps, maps.Map{
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
"type": "default",
|
||||
})
|
||||
}
|
||||
|
||||
// 自定义
|
||||
routesResp, err := this.RPC().NSRouteRPC().FindAllNSRoutes(this.UserContext(), &pb.FindAllNSRoutesRequest{
|
||||
NsClusterId: params.ClusterId,
|
||||
NsDomainId: params.DomainId,
|
||||
UserId: params.UserId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, route := range routesResp.NsRoutes {
|
||||
if len(route.Code) == 0 {
|
||||
route.Code = "id:" + types.String(route.Id)
|
||||
}
|
||||
|
||||
if !route.IsOn {
|
||||
continue
|
||||
}
|
||||
|
||||
routeMaps = append(routeMaps, maps.Map{
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
"type": "user",
|
||||
})
|
||||
}
|
||||
|
||||
// 运营商
|
||||
this.Data["supportISPRoutes"] = false
|
||||
if planConfig == nil || planConfig.SupportISPRoutes {
|
||||
this.Data["supportISPRoutes"] = true
|
||||
for _, route := range dnsconfigs.AllDefaultISPRoutes {
|
||||
routeMaps = append(routeMaps, maps.Map{
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
"type": "isp",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 中国省份
|
||||
this.Data["supportChinaProvinceRoutes"] = false
|
||||
if planConfig == nil || planConfig.SupportChinaProvinceRoutes {
|
||||
this.Data["supportChinaProvinceRoutes"] = true
|
||||
for _, route := range dnsconfigs.AllDefaultChinaProvinceRoutes {
|
||||
routeMaps = append(routeMaps, maps.Map{
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
"type": "china",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 全球
|
||||
this.Data["supportWorldRegionRoutes"] = false
|
||||
if planConfig == nil || planConfig.SupportCountryRoutes {
|
||||
this.Data["supportWorldRegionRoutes"] = true
|
||||
for _, route := range dnsconfigs.AllDefaultWorldRegionRoutes {
|
||||
routeMaps = append(routeMaps, maps.Map{
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
"type": "world",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 省份
|
||||
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvinces(this.UserContext(), &pb.FindAllRegionProvincesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var provinceMaps = []maps.Map{}
|
||||
for _, province := range provincesResp.RegionProvinces {
|
||||
if province.RegionCountry == nil || len(province.RegionCountry.RouteCode) == 0 {
|
||||
continue
|
||||
}
|
||||
provinceMaps = append(provinceMaps, maps.Map{
|
||||
"id": province.Id,
|
||||
"name": province.Name,
|
||||
"code": "region:province:" + types.String(province.Id),
|
||||
"type": "province",
|
||||
"countryCode": province.RegionCountry.RouteCode,
|
||||
})
|
||||
}
|
||||
this.Data["provinces"] = provinceMaps
|
||||
|
||||
// 搜索引擎
|
||||
this.Data["supportAgentRoutes"] = false
|
||||
if planConfig == nil || planConfig.SupportAgentRoutes {
|
||||
this.Data["supportAgentRoutes"] = true
|
||||
agentsResp, err := this.RPC().NSRouteRPC().FindAllAgentNSRoutes(this.UserContext(), &pb.FindAllAgentNSRoutesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, route := range agentsResp.NsRoutes {
|
||||
routeMaps = append(routeMaps, maps.Map{
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
"type": "agent",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 公共线路
|
||||
this.Data["publicCategories"] = []maps.Map{}
|
||||
this.Data["supportPublicRoutes"] = false
|
||||
|
||||
publicRoutesResp, err := this.RPC().NSRouteRPC().FindAllPublicNSRoutes(this.UserContext(), &pb.FindAllPublicRoutesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(publicRoutesResp.NsRoutes) == 0 {
|
||||
this.Data["supportPublicRoutes"] = true
|
||||
} else if planConfig == nil || planConfig.SupportPublicRoutes {
|
||||
this.Data["supportPublicRoutes"] = true
|
||||
|
||||
var publicCategoryMaps = []maps.Map{}
|
||||
var publicCategoryIds = []int64{}
|
||||
for _, route := range publicRoutesResp.NsRoutes {
|
||||
var categoryId int64 = 0
|
||||
if route.NsRouteCategory != nil {
|
||||
categoryId = route.NsRouteCategory.Id
|
||||
}
|
||||
|
||||
routeMaps = append(routeMaps, maps.Map{
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
"type": "public:category:" + types.String(categoryId),
|
||||
})
|
||||
|
||||
// 未分类
|
||||
if route.NsRouteCategory == nil {
|
||||
if !lists.ContainsInt64(publicCategoryIds, 0) {
|
||||
publicCategoryIds = append(publicCategoryIds, 0)
|
||||
publicCategoryMaps = append(publicCategoryMaps, maps.Map{
|
||||
"id": 0,
|
||||
"name": "官方线路",
|
||||
"type": "public:category:" + types.String(0),
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// 有分类
|
||||
if !lists.ContainsInt64(publicCategoryIds, categoryId) {
|
||||
publicCategoryIds = append(publicCategoryIds, route.NsRouteCategory.Id)
|
||||
publicCategoryMaps = append(publicCategoryMaps, maps.Map{
|
||||
"id": route.NsRouteCategory.Id,
|
||||
"name": route.NsRouteCategory.Name,
|
||||
"type": "public:category:" + types.String(categoryId),
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["publicCategories"] = publicCategoryMaps
|
||||
}
|
||||
|
||||
this.Data["routes"] = routeMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
17
EdgeUser/internal/web/actions/default/ns/routes/route.go
Normal file
17
EdgeUser/internal/web/actions/default/ns/routes/route.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package clusters
|
||||
|
||||
import "github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
|
||||
type RouteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *RouteAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *RouteAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
27
EdgeUser/internal/web/actions/default/ns/routes/sort.go
Normal file
27
EdgeUser/internal/web/actions/default/ns/routes/sort.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
)
|
||||
|
||||
type SortAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SortAction) RunPost(params struct {
|
||||
RouteIds []int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSRoute_LogSortNSRoutes)
|
||||
|
||||
_, err := this.RPC().NSRouteRPC().UpdateNSRouteOrders(this.UserContext(), &pb.UpdateNSRouteOrdersRequest{NsRouteIds: params.RouteIds})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
RouteId int64
|
||||
}) {
|
||||
routeResp, err := this.RPC().NSRouteRPC().FindNSRoute(this.UserContext(), &pb.FindNSRouteRequest{NsRouteId: params.RouteId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var route = routeResp.NsRoute
|
||||
if route == nil {
|
||||
this.NotFound("nsRoute", params.RouteId)
|
||||
return
|
||||
}
|
||||
|
||||
var rangeMaps = []maps.Map{}
|
||||
if len(route.RangesJSON) > 0 {
|
||||
err = json.Unmarshal(route.RangesJSON, &rangeMaps)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["route"] = maps.Map{
|
||||
"id": route.Id,
|
||||
"name": route.Name,
|
||||
"isOn": route.IsOn,
|
||||
"ranges": rangeMaps,
|
||||
}
|
||||
|
||||
// 范围类型
|
||||
this.Data["rangeTypes"] = dnsconfigs.AllNSRouteRangeTypes()
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
RouteId int64
|
||||
Name string
|
||||
RangesJSON []byte
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NSRoute_LogUpdateNSRoute, params.RouteId)
|
||||
|
||||
params.Must.Field("name", params.Name).
|
||||
Require("请输入线路名称")
|
||||
|
||||
ranges, err := dnsconfigs.InitNSRangesFromJSON(params.RangesJSON)
|
||||
if err != nil {
|
||||
this.Fail("配置校验失败:" + err.Error())
|
||||
}
|
||||
|
||||
if len(ranges) == 0 {
|
||||
this.Fail("请添加线路范围")
|
||||
}
|
||||
|
||||
_, err = this.RPC().NSRouteRPC().UpdateNSRoute(this.UserContext(), &pb.UpdateNSRouteRequest{
|
||||
NsRouteId: params.RouteId,
|
||||
Name: params.Name,
|
||||
RangesJSON: params.RangesJSON,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
Reference in New Issue
Block a user