diff --git a/internal/configloaders/admin_module.go b/internal/configloaders/admin_module.go index 8e7abb4c..a84216f9 100644 --- a/internal/configloaders/admin_module.go +++ b/internal/configloaders/admin_module.go @@ -158,7 +158,7 @@ func AllModuleMaps() []maps.Map { } if teaconst.IsPlus { m = append(m, maps.Map{ - "name": "域名服务器", + "name": "域名服务", "code": AdminModuleCodeNS, "url": "/ns", }) diff --git a/internal/rpc/rpc_client.go b/internal/rpc/rpc_client.go index 5907f77e..2b1e2b52 100644 --- a/internal/rpc/rpc_client.go +++ b/internal/rpc/rpc_client.go @@ -360,6 +360,14 @@ func (this *RPCClient) NSNodeRPC() pb.NSNodeServiceClient { return pb.NewNSNodeServiceClient(this.pickConn()) } +func (this *RPCClient) NSDomainRPC() pb.NSDomainServiceClient { + return pb.NewNSDomainServiceClient(this.pickConn()) +} + +func (this *RPCClient) NSRecordRPC() pb.NSRecordServiceClient { + return pb.NewNSRecordServiceClient(this.pickConn()) +} + // Context 构造Admin上下文 func (this *RPCClient) Context(adminId int64) context.Context { ctx := context.Background() diff --git a/internal/web/actions/actionutils/utils.go b/internal/web/actions/actionutils/utils.go index 9f3edc7e..dbcf169e 100644 --- a/internal/web/actions/actionutils/utils.go +++ b/internal/web/actions/actionutils/utils.go @@ -37,6 +37,8 @@ func FailPage(action actions.ActionWrapper, err error) {
` + teaconst.ErrServer + `
可以通过查看 $安装目录/logs/run.log 日志文件查看具体的错误提示。
+
+
Error: ` + err.Error() + `
`) diff --git a/internal/web/actions/default/ns/clusters/init.go b/internal/web/actions/default/ns/clusters/init.go index 77f5445b..ffa27e46 100644 --- a/internal/web/actions/default/ns/clusters/init.go +++ b/internal/web/actions/default/ns/clusters/init.go @@ -15,6 +15,7 @@ func init() { Prefix("/ns/clusters"). Get("", new(IndexAction)). GetPost("/create", new(CreateAction)). + Post("/options", new(OptionsAction)). EndAll() }) } diff --git a/internal/web/actions/default/ns/clusters/logs/index.go b/internal/web/actions/default/ns/clusters/logs/index.go new file mode 100644 index 00000000..d21656e4 --- /dev/null +++ b/internal/web/actions/default/ns/clusters/logs/index.go @@ -0,0 +1,88 @@ +package logs + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" + timeutil "github.com/iwind/TeaGo/utils/time" +) + +type IndexAction struct { + actionutils.ParentAction +} + +func (this *IndexAction) Init() { +} + +func (this *IndexAction) RunGet(params struct { + DayFrom string + DayTo string + Keyword string + Level string +}) { + this.Data["dayFrom"] = params.DayFrom + this.Data["dayTo"] = params.DayTo + this.Data["keyword"] = params.Keyword + this.Data["level"] = params.Level + + countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{ + NodeId: 0, + Role: nodeconfigs.NodeRoleDNS, + DayFrom: params.DayFrom, + DayTo: params.DayTo, + Keyword: params.Keyword, + Level: params.Level, + }) + if err != nil { + this.ErrorPage(err) + return + } + count := countResp.Count + page := this.NewPage(count) + this.Data["page"] = page.AsHTML() + + logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{ + NodeId: 0, + Role: nodeconfigs.NodeRoleDNS, + DayFrom: params.DayFrom, + DayTo: params.DayTo, + Keyword: params.Keyword, + Level: params.Level, + Offset: page.Offset, + Size: page.Size, + }) + + logs := []maps.Map{} + for _, log := range logsResp.NodeLogs { + // 节点信息 + nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: log.NodeId}) + if err != nil { + continue + } + node := nodeResp.NsNode + if node == nil || node.NsCluster == nil { + continue + } + + logs = append(logs, maps.Map{ + "tag": log.Tag, + "description": log.Description, + "createdTime": timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt), + "level": log.Level, + "isToday": timeutil.FormatTime("Y-m-d", log.CreatedAt) == timeutil.Format("Y-m-d"), + "count": log.Count, + "node": maps.Map{ + "id": node.Id, + "cluster": maps.Map{ + "id": node.NsCluster.Id, + "name": node.NsCluster.Name, + }, + "name": node.Name, + }, + }) + } + this.Data["logs"] = logs + + this.Show() +} diff --git a/internal/web/actions/default/ns/clusters/logs/init.go b/internal/web/actions/default/ns/clusters/logs/init.go new file mode 100644 index 00000000..5dfec414 --- /dev/null +++ b/internal/web/actions/default/ns/clusters/logs/init.go @@ -0,0 +1,19 @@ +package logs + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/configloaders" + "github.com/TeaOSLab/EdgeAdmin/internal/web/helpers" + "github.com/iwind/TeaGo" +) + +func init() { + TeaGo.BeforeStart(func(server *TeaGo.Server) { + server. + Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNS)). + Data("teaMenu", "ns"). + Data("teaSubMenu", "log"). + Prefix("/ns/clusters/logs"). + Get("", new(IndexAction)). + EndAll() + }) +} diff --git a/internal/web/actions/default/ns/clusters/options.go b/internal/web/actions/default/ns/clusters/options.go new file mode 100644 index 00000000..0d11d014 --- /dev/null +++ b/internal/web/actions/default/ns/clusters/options.go @@ -0,0 +1,30 @@ +package clusters + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" +) + +type OptionsAction struct { + actionutils.ParentAction +} + +func (this *OptionsAction) RunPost(params struct{}) { + clustersResp, err := this.RPC().NSClusterRPC().FindAllEnabledNSClusters(this.AdminContext(), &pb.FindAllEnabledNSClustersRequest{}) + if err != nil { + this.ErrorPage(err) + return + } + + clusterMaps := []maps.Map{} + for _, cluster := range clustersResp.NsClusters { + clusterMaps = append(clusterMaps, maps.Map{ + "id": cluster.Id, + "name": cluster.Name, + }) + } + this.Data["clusters"] = clusterMaps + + this.Success() +} diff --git a/internal/web/actions/default/ns/domains/create.go b/internal/web/actions/default/ns/domains/create.go new file mode 100644 index 00000000..4564640b --- /dev/null +++ b/internal/web/actions/default/ns/domains/create.go @@ -0,0 +1,62 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package domains + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/actions" +) + +type CreateAction struct { + actionutils.ParentAction +} + +func (this *CreateAction) Init() { + this.Nav("", "", "create") +} + +func (this *CreateAction) RunGet(params struct{}) { + this.Show() +} + +func (this *CreateAction) RunPost(params struct { + Name string + ClusterId int64 + UserId int64 + + Must *actions.Must + CSRF *actionutils.CSRF +}) { + var domainId int64 + defer func() { + this.CreateLogInfo("创建域名 %d", domainId) + }() + + params.Must. + Field("name", params.Name). + Require("请输入域名"). + Expect(func() (message string, success bool) { + success = domainutils.ValidateDomainFormat(params.Name) + if !success { + message = "请输入正确的域名" + } + return + }). + Field("clusterId", params.ClusterId). + Gt(0, "请选择所属集群") + + createResp, err := this.RPC().NSDomainRPC().CreateNSDomain(this.AdminContext(), &pb.CreateNSDomainRequest{ + NsClusterId: params.ClusterId, + UserId: params.UserId, + Name: params.Name, + }) + if err != nil { + this.ErrorPage(err) + return + } + domainId = createResp.NsDomainId + + this.Success() +} diff --git a/internal/web/actions/default/ns/domains/delete.go b/internal/web/actions/default/ns/domains/delete.go new file mode 100644 index 00000000..0999d275 --- /dev/null +++ b/internal/web/actions/default/ns/domains/delete.go @@ -0,0 +1,26 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package domains + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" +) + +type DeleteAction struct { + actionutils.ParentAction +} + +func (this *DeleteAction) RunPost(params struct { + DomainId int64 +}) { + defer this.CreateLogInfo("删除域名 %d", params.DomainId) + + _, err := this.RPC().NSDomainRPC().DeleteNSDomain(this.AdminContext(), &pb.DeleteNSDomainRequest{NsDomainId: params.DomainId}) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/internal/web/actions/default/ns/domains/domain.go b/internal/web/actions/default/ns/domains/domain.go new file mode 100644 index 00000000..2704e4b3 --- /dev/null +++ b/internal/web/actions/default/ns/domains/domain.go @@ -0,0 +1,61 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package domains + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" +) + +type DomainAction struct { + actionutils.ParentAction +} + +func (this *DomainAction) Init() { + this.Nav("", "", "index") +} + +func (this *DomainAction) RunGet(params struct { + DomainId int64 +}) { + // 域名信息 + domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: params.DomainId}) + if err != nil { + this.ErrorPage(err) + return + } + domain := domainResp.NsDomain + if domain == nil { + this.NotFound("nsDomain", params.DomainId) + return + } + + var clusterMap maps.Map + if domain.NsCluster != nil { + clusterMap = maps.Map{ + "id": domain.NsCluster.Id, + "name": domain.NsCluster.Name, + } + } + + // 用户信息 + var userMap maps.Map + if domain.User != nil { + userMap = maps.Map{ + "id": domain.User.Id, + "username": domain.User.Username, + "fullname": domain.User.Fullname, + } + } + + this.Data["domain"] = maps.Map{ + "id": domain.Id, + "name": domain.Name, + "isOn": domain.IsOn, + "cluster": clusterMap, + "user": userMap, + } + + this.Show() +} diff --git a/internal/web/actions/default/ns/domains/records/createPopup.go b/internal/web/actions/default/ns/domains/records/createPopup.go new file mode 100644 index 00000000..d52707ca --- /dev/null +++ b/internal/web/actions/default/ns/domains/records/createPopup.go @@ -0,0 +1,81 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package records + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "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 +}) { + // 域名信息 + domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: params.DomainId}) + if err != nil { + this.ErrorPage(err) + return + } + 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.FindAllRecordTypeDefinitions() + + // TTL + this.Data["ttlValues"] = dnsconfigs.FindAllRecordTTL() + + this.Show() +} + +func (this *CreatePopupAction) RunPost(params struct { + DomainId int64 + Name string + Type string + Value string + Ttl int32 + Description string + + Must *actions.Must + CSRF *actionutils.CSRF +}) { + var recordId int64 + defer func() { + this.CreateLogInfo("创建域名记录 %d", recordId) + }() + + createResp, err := this.RPC().NSRecordRPC().CreateNSRecord(this.AdminContext(), &pb.CreateNSRecordRequest{ + NsDomainId: params.DomainId, + Description: params.Description, + Name: params.Name, + Type: params.Type, + Value: params.Value, + Ttl: params.Ttl, + NsRouteIds: nil, // TODO 等待实现 + }) + if err != nil { + this.ErrorPage(err) + return + } + recordId = createResp.NsRecordId + + this.Success() +} diff --git a/internal/web/actions/default/ns/domains/records/delete.go b/internal/web/actions/default/ns/domains/records/delete.go new file mode 100644 index 00000000..f640e556 --- /dev/null +++ b/internal/web/actions/default/ns/domains/records/delete.go @@ -0,0 +1,26 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package records + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" +) + +type DeleteAction struct { + actionutils.ParentAction +} + +func (this *DeleteAction) RunPost(params struct { + RecordId int64 +}) { + defer this.CreateLogInfo("删除域名记录 %d", params.RecordId) + + _, err := this.RPC().NSRecordRPC().DeleteNSRecord(this.AdminContext(), &pb.DeleteNSRecordRequest{NsRecordId: params.RecordId}) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/internal/web/actions/default/ns/domains/records/index.go b/internal/web/actions/default/ns/domains/records/index.go new file mode 100644 index 00000000..9cee4922 --- /dev/null +++ b/internal/web/actions/default/ns/domains/records/index.go @@ -0,0 +1,96 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package records + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "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 + RouteId int64 // TODO +}) { + this.Data["type"] = params.Type + this.Data["keyword"] = params.Keyword + this.Data["routeId"] = params.RouteId + + // 域名信息 + domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: params.DomainId}) + if err != nil { + this.ErrorPage(err) + return + } + domain := domainResp.NsDomain + if domain == nil { + this.NotFound("nsDomain", params.DomainId) + return + } + this.Data["domain"] = maps.Map{ + "id": domain.Id, + "name": domain.Name, + } + + // 记录 + countResp, err := this.RPC().NSRecordRPC().CountAllEnabledNSRecords(this.AdminContext(), &pb.CountAllEnabledNSRecordsRequest{ + NsDomainId: params.DomainId, + Type: params.Type, + NsRouteId: params.RouteId, + Keyword: params.Keyword, + }) + if err != nil { + this.ErrorPage(err) + return + } + count := countResp.Count + page := this.NewPage(count) + this.Data["page"] = page.AsHTML() + + recordsResp, err := this.RPC().NSRecordRPC().ListEnabledNSRecords(this.AdminContext(), &pb.ListEnabledNSRecordsRequest{ + NsDomainId: params.DomainId, + Type: params.Type, + NsRouteId: params.RouteId, + Keyword: params.Keyword, + Offset: page.Offset, + Size: page.Size, + }) + if err != nil { + this.ErrorPage(err) + return + } + var recordMaps = []maps.Map{} + for _, record := range recordsResp.NsRecords { + routeMaps := []maps.Map{} + for _, route := range record.NsRoutes { + routeMaps = append(routeMaps, maps.Map{ + "id": route.Id, + "name": route.Name, + }) + } + + recordMaps = append(recordMaps, maps.Map{ + "id": record.Id, + "name": record.Name, + "type": record.Type, + "value": record.Value, + "ttl": record.Ttl, + "weight": record.Weight, + "description": record.Description, + "routes": routeMaps, + }) + } + this.Data["records"] = recordMaps + + this.Show() +} diff --git a/internal/web/actions/default/ns/domains/records/updatePopup.go b/internal/web/actions/default/ns/domains/records/updatePopup.go new file mode 100644 index 00000000..ab09394b --- /dev/null +++ b/internal/web/actions/default/ns/domains/records/updatePopup.go @@ -0,0 +1,98 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package records + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "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 { + RecordId int64 +}) { + recordResp, err := this.RPC().NSRecordRPC().FindEnabledNSRecord(this.AdminContext(), &pb.FindEnabledNSRecordRequest{NsRecordId: params.RecordId}) + if err != nil { + this.ErrorPage(err) + return + } + 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, + "ttl": record.Ttl, + "weight": record.Weight, + "description": record.Description, + } + + // 域名信息 + domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{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.FindAllRecordTypeDefinitions() + + // TTL + this.Data["ttlValues"] = dnsconfigs.FindAllRecordTTL() + + this.Show() +} + +func (this *UpdatePopupAction) RunPost(params struct { + RecordId int64 + Name string + Type string + Value string + Ttl int32 + Description string + + Must *actions.Must + CSRF *actionutils.CSRF +}) { + this.CreateLogInfo("修改域名记录 %d", params.RecordId) + + _, err := this.RPC().NSRecordRPC().UpdateNSRecord(this.AdminContext(), &pb.UpdateNSRecordRequest{ + NsRecordId: params.RecordId, + Description: params.Description, + Name: params.Name, + Type: params.Type, + Value: params.Value, + Ttl: params.Ttl, + NsRouteIds: nil, // TODO 等待实现 + }) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/internal/web/actions/default/ns/domains/update.go b/internal/web/actions/default/ns/domains/update.go new file mode 100644 index 00000000..f0b0bcb4 --- /dev/null +++ b/internal/web/actions/default/ns/domains/update.go @@ -0,0 +1,96 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package domains + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "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 +}) { + // 域名信息 + domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{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 + } + + this.Data["domain"] = maps.Map{ + "id": domain.Id, + "name": domain.Name, + "isOn": domain.IsOn, + "clusterId": clusterId, + "userId": userId, + } + + this.Show() +} + +func (this *UpdateAction) RunPost(params struct { + DomainId int64 + Name string + ClusterId int64 + UserId int64 + IsOn bool + + Must *actions.Must + CSRF *actionutils.CSRF +}) { + this.CreateLogInfo("修改域名 %d", params.DomainId) + + params.Must. + Field("name", params.Name). + Require("请输入域名"). + Expect(func() (message string, success bool) { + success = domainutils.ValidateDomainFormat(params.Name) + if !success { + message = "请输入正确的域名" + } + return + }). + Field("clusterId", params.ClusterId). + Gt(0, "请选择所属集群") + + _, err := this.RPC().NSDomainRPC().UpdateNSDomain(this.AdminContext(), &pb.UpdateNSDomainRequest{ + NsDomainId: params.DomainId, + NsClusterId: params.ClusterId, + UserId: params.UserId, + Name: params.Name, + IsOn: params.IsOn, + }) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/internal/web/actions/default/ns/index.go b/internal/web/actions/default/ns/index.go index ee04d239..8ff05dff 100644 --- a/internal/web/actions/default/ns/index.go +++ b/internal/web/actions/default/ns/index.go @@ -2,6 +2,8 @@ package ns import ( "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" ) type IndexAction struct { @@ -9,9 +11,80 @@ type IndexAction struct { } func (this *IndexAction) Init() { + this.FirstMenu("index") } -func (this *IndexAction) RunGet(params struct{}) { +func (this *IndexAction) RunGet(params struct { + ClusterId int64 + UserId int64 + Keyword string +}) { + this.Data["clusterId"] = params.ClusterId + this.Data["userId"] = params.UserId + this.Data["keyword"] = params.Keyword + + // 集群数量 + countClustersResp, err := this.RPC().NSClusterRPC().CountAllEnabledNSClusters(this.AdminContext(), &pb.CountAllEnabledNSClustersRequest{}) + if err != nil { + this.ErrorPage(err) + return + } + this.Data["countClusters"] = countClustersResp.Count + + // 分页 + countResp, err := this.RPC().NSDomainRPC().CountAllEnabledNSDomains(this.AdminContext(), &pb.CountAllEnabledNSDomainsRequest{ + UserId: params.UserId, + NsClusterId: params.ClusterId, + Keyword: params.Keyword, + }) + if err != nil { + this.ErrorPage(err) + return + } + page := this.NewPage(countResp.Count) + + // 列表 + domainsResp, err := this.RPC().NSDomainRPC().ListEnabledNSDomains(this.AdminContext(), &pb.ListEnabledNSDomainsRequest{ + UserId: params.UserId, + NsClusterId: params.ClusterId, + Keyword: params.Keyword, + Offset: page.Offset, + Size: page.Size, + }) + if err != nil { + this.ErrorPage(err) + return + } + domainMaps := []maps.Map{} + for _, domain := range domainsResp.NsDomains { + // 集群信息 + var clusterMap maps.Map + if domain.NsCluster != nil { + clusterMap = maps.Map{ + "id": domain.NsCluster.Id, + "name": domain.NsCluster.Name, + } + } + + // 用户信息 + var userMap maps.Map + if domain.User != nil { + userMap = maps.Map{ + "id": domain.User.Id, + "username": domain.User.Username, + "fullname": domain.User.Fullname, + } + } + + domainMaps = append(domainMaps, maps.Map{ + "id": domain.Id, + "name": domain.Name, + "isOn": domain.IsOn, + "cluster": clusterMap, + "user": userMap, + }) + } + this.Data["domains"] = domainMaps this.Show() } diff --git a/internal/web/actions/default/ns/init.go b/internal/web/actions/default/ns/init.go index 0abc2e3f..73e42924 100644 --- a/internal/web/actions/default/ns/init.go +++ b/internal/web/actions/default/ns/init.go @@ -2,6 +2,8 @@ package ns import ( "github.com/TeaOSLab/EdgeAdmin/internal/configloaders" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains/records" "github.com/TeaOSLab/EdgeAdmin/internal/web/helpers" "github.com/iwind/TeaGo" ) @@ -14,6 +16,20 @@ func init() { Prefix("/ns"). Get("", new(IndexAction)). + // 域名相关 + Prefix("/ns/domains"). + GetPost("/create", new(domains.CreateAction)). + Post("/delete", new(domains.DeleteAction)). + Get("/domain", new(domains.DomainAction)). + GetPost("/update", new(domains.UpdateAction)). + + // 记录相关 + Prefix("/ns/domains/records"). + Get("", new(records.IndexAction)). + GetPost("/createPopup", new(records.CreatePopupAction)). + GetPost("/updatePopup", new(records.UpdatePopupAction)). + Post("/delete", new(records.DeleteAction)). + EndAll() }) } diff --git a/internal/web/actions/default/ns/users/init.go b/internal/web/actions/default/ns/users/init.go new file mode 100644 index 00000000..b822ab60 --- /dev/null +++ b/internal/web/actions/default/ns/users/init.go @@ -0,0 +1,19 @@ +package users + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/configloaders" + "github.com/TeaOSLab/EdgeAdmin/internal/web/helpers" + "github.com/iwind/TeaGo" +) + +func init() { + TeaGo.BeforeStart(func(server *TeaGo.Server) { + server. + Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNS)). + Data("teaMenu", "ns"). + Data("teaSubMenu", "domain"). + Prefix("/ns/users"). + Post("/options", new(OptionsAction)). + EndAll() + }) +} diff --git a/internal/web/actions/default/ns/users/options.go b/internal/web/actions/default/ns/users/options.go new file mode 100644 index 00000000..e31b8cf8 --- /dev/null +++ b/internal/web/actions/default/ns/users/options.go @@ -0,0 +1,34 @@ +package users + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" +) + +type OptionsAction struct { + actionutils.ParentAction +} + +func (this *OptionsAction) RunPost(params struct{}) { + usersResp, err := this.RPC().UserRPC().ListEnabledUsers(this.AdminContext(), &pb.ListEnabledUsersRequest{ + Offset: 0, + Size: 10000, // TODO 改进 组件 + }) + if err != nil { + this.ErrorPage(err) + return + } + + userMaps := []maps.Map{} + for _, user := range usersResp.Users { + userMaps = append(userMaps, maps.Map{ + "id": user.Id, + "fullname": user.Fullname, + "username": user.Username, + }) + } + this.Data["users"] = userMaps + + this.Success() +} diff --git a/internal/web/actions/default/users/index.go b/internal/web/actions/default/users/index.go index 4745b718..82877bca 100644 --- a/internal/web/actions/default/users/index.go +++ b/internal/web/actions/default/users/index.go @@ -27,7 +27,11 @@ func (this *IndexAction) RunGet(params struct { page := this.NewPage(count) this.Data["page"] = page.AsHTML() - usersResp, err := this.RPC().UserRPC().ListEnabledUsers(this.AdminContext(), &pb.ListEnabledUsersRequest{Keyword: params.Keyword}) + usersResp, err := this.RPC().UserRPC().ListEnabledUsers(this.AdminContext(), &pb.ListEnabledUsersRequest{ + Keyword: params.Keyword, + Offset: page.Offset, + Size: page.Size, + }) if err != nil { this.ErrorPage(err) return diff --git a/internal/web/helpers/user_must_auth.go b/internal/web/helpers/user_must_auth.go index 551c658b..c330833d 100644 --- a/internal/web/helpers/user_must_auth.go +++ b/internal/web/helpers/user_must_auth.go @@ -220,7 +220,7 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map { { "code": "ns", "module": configloaders.AdminModuleCodeNS, - "name": "域名服务器", + "name": "域名服务", "subtitle": "域名列表", "icon": "cubes", "isOn": teaconst.IsPlus, @@ -232,7 +232,7 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map { }, { "name": "节点日志", - "url": "/ns/logs", + "url": "/ns/clusters/logs", "code": "log", }, }, diff --git a/internal/web/import.go b/internal/web/import.go index 92d35a43..b0bd52fd 100644 --- a/internal/web/import.go +++ b/internal/web/import.go @@ -37,6 +37,8 @@ import ( _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters/cluster" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters/cluster/settings" + _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters/logs" + _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/users" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs" diff --git a/web/public/js/components/common/not-found-box.js b/web/public/js/components/common/not-found-box.js index 293cc353..22d7bacf 100644 --- a/web/public/js/components/common/not-found-box.js +++ b/web/public/js/components/common/not-found-box.js @@ -2,6 +2,6 @@ Vue.component("not-found-box", { props: ["message"], template: `
-

{{message}}

+

{{message}}

` }) \ No newline at end of file diff --git a/web/public/js/components/ns/ns-cluster-selector.js b/web/public/js/components/ns/ns-cluster-selector.js new file mode 100644 index 00000000..cbe65dfc --- /dev/null +++ b/web/public/js/components/ns/ns-cluster-selector.js @@ -0,0 +1,28 @@ +Vue.component("ns-cluster-selector", { + mounted: function () { + let that = this + + Tea.action("/ns/clusters/options") + .post() + .success(function (resp) { + that.clusters = resp.data.clusters + }) + }, + props: ["v-cluster-id"], + data: function () { + let clusterId = this.vClusterId + if (clusterId == null) { + clusterId = 0 + } + return { + clusters: [], + clusterId: clusterId + } + }, + template: `
+ +
` +}) \ No newline at end of file diff --git a/web/public/js/components/ns/ns-user-selector.js b/web/public/js/components/ns/ns-user-selector.js new file mode 100644 index 00000000..a1e4a60b --- /dev/null +++ b/web/public/js/components/ns/ns-user-selector.js @@ -0,0 +1,28 @@ +Vue.component("ns-user-selector", { + mounted: function () { + let that = this + + Tea.action("/ns/users/options") + .post() + .success(function (resp) { + that.users = resp.data.users + }) + }, + props: ["v-user-id"], + data: function () { + let userId = this.vUserId + if (userId == null) { + userId = 0 + } + return { + users: [], + userId: userId + } + }, + template: `
+ +
` +}) \ No newline at end of file diff --git a/web/views/@default/ns/@menu.html b/web/views/@default/ns/@menu.html new file mode 100644 index 00000000..675705ae --- /dev/null +++ b/web/views/@default/ns/@menu.html @@ -0,0 +1,5 @@ + + 域名列表 + 添加域名 + +
\ No newline at end of file diff --git a/web/views/@default/ns/clusters/logs/index.css b/web/views/@default/ns/clusters/logs/index.css new file mode 100644 index 00000000..e05cd134 --- /dev/null +++ b/web/views/@default/ns/clusters/logs/index.css @@ -0,0 +1,5 @@ +pre.log-box { + margin: 0; + padding: 0; +} +/*# sourceMappingURL=index.css.map */ \ No newline at end of file diff --git a/web/views/@default/ns/clusters/logs/index.css.map b/web/views/@default/ns/clusters/logs/index.css.map new file mode 100644 index 00000000..2c0cfd3e --- /dev/null +++ b/web/views/@default/ns/clusters/logs/index.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA,GAAG;EACF,SAAA;EACA,UAAA","file":"index.css"} \ No newline at end of file diff --git a/web/views/@default/ns/clusters/logs/index.html b/web/views/@default/ns/clusters/logs/index.html new file mode 100644 index 00000000..950b7712 --- /dev/null +++ b/web/views/@default/ns/clusters/logs/index.html @@ -0,0 +1,62 @@ +{$layout} + +{$var "header"} + + + + + + +{$end} + + +
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+ +

暂时还没有日志。

+ + + + + + + + + + + + + + +
集群节点信息
{{log.node.cluster.name}}{{log.node.name}} +
[{{log.createdTime}}][{{log.createdTime}}][{{log.tag}}]{{log.description}}   共{{log.count}}条
+
+ +
\ No newline at end of file diff --git a/web/views/@default/ns/clusters/logs/index.js b/web/views/@default/ns/clusters/logs/index.js new file mode 100644 index 00000000..29a90420 --- /dev/null +++ b/web/views/@default/ns/clusters/logs/index.js @@ -0,0 +1,6 @@ +Tea.context(function () { + this.$delay(function () { + teaweb.datepicker("day-from-picker") + teaweb.datepicker("day-to-picker") + }) +}) \ No newline at end of file diff --git a/web/views/@default/ns/clusters/logs/index.less b/web/views/@default/ns/clusters/logs/index.less new file mode 100644 index 00000000..9accd63d --- /dev/null +++ b/web/views/@default/ns/clusters/logs/index.less @@ -0,0 +1,4 @@ +pre.log-box { + margin: 0; + padding: 0; +} \ No newline at end of file diff --git a/web/views/@default/ns/domains/@domain_menu.html b/web/views/@default/ns/domains/@domain_menu.html new file mode 100644 index 00000000..ac7f25db --- /dev/null +++ b/web/views/@default/ns/domains/@domain_menu.html @@ -0,0 +1,7 @@ + + 所有域名 + | + 详情({{domain.name}}) + 记录 + 修改 + \ No newline at end of file diff --git a/web/views/@default/ns/domains/create.html b/web/views/@default/ns/domains/create.html new file mode 100644 index 00000000..de15abbd --- /dev/null +++ b/web/views/@default/ns/domains/create.html @@ -0,0 +1,27 @@ +{$layout} +{$template "../menu"} + +
+ + + + + + + + + + + + + + +
域名 * + +
所属集群 * + +
所属用户 + +
+ +
\ No newline at end of file diff --git a/web/views/@default/ns/domains/create.js b/web/views/@default/ns/domains/create.js new file mode 100644 index 00000000..c7b275cc --- /dev/null +++ b/web/views/@default/ns/domains/create.js @@ -0,0 +1,3 @@ +Tea.context(function () { + this.success = NotifySuccess("保存成功", "/ns") +}) \ No newline at end of file diff --git a/web/views/@default/ns/domains/domain.html b/web/views/@default/ns/domains/domain.html new file mode 100644 index 00000000..944334f1 --- /dev/null +++ b/web/views/@default/ns/domains/domain.html @@ -0,0 +1,30 @@ +{$layout} +{$template "domain_menu"} + + + + + + + + + + + + + + + + + + +
域名{{domain.name}}
状态 + +
所属集群 + {{domain.cluster.name}} +
所属用户 + + {{domain.user.fullname}} ({{domain.user.username}}) + + - +
\ No newline at end of file diff --git a/web/views/@default/ns/domains/records/createPopup.html b/web/views/@default/ns/domains/records/createPopup.html new file mode 100644 index 00000000..3bbc84ce --- /dev/null +++ b/web/views/@default/ns/domains/records/createPopup.html @@ -0,0 +1,48 @@ +{$layout "layout_popup"} + +

创建记录

+
+ + + + + + + + + + + + + + + + + + + + + + + +
记录名 +
+ + .{{domain.name}} +
+
记录类型 + +

{{typeDescription}}

+
记录值 + +
TTL + +
备注 + +
+ +
\ No newline at end of file diff --git a/web/views/@default/ns/domains/records/createPopup.js b/web/views/@default/ns/domains/records/createPopup.js new file mode 100644 index 00000000..d234485a --- /dev/null +++ b/web/views/@default/ns/domains/records/createPopup.js @@ -0,0 +1,15 @@ +Tea.context(function () { + this.type = "A" + this.typeDescription = "" + + this.changeType = function () { + let that = this + this.types.forEach(function (v) { + if (v.type == that.type) { + that.typeDescription = v.description + } + }) + } + + this.changeType() +}) \ No newline at end of file diff --git a/web/views/@default/ns/domains/records/index.html b/web/views/@default/ns/domains/records/index.html new file mode 100644 index 00000000..7822b34b --- /dev/null +++ b/web/views/@default/ns/domains/records/index.html @@ -0,0 +1,37 @@ +{$layout} +{$template "../domain_menu"} + + + [创建记录] + + +

暂时还没有记录。

+ + + + + + + + + + + + + + + + + + + + + +
记录名记录类型记录值TTL线路备注操作
{{record.name}}{{record.type}}{{record.value}}{{formatTTL(record.ttl)}} + {{route.name}} + {{record.description}} + 修改   + 删除 +
+ +
\ No newline at end of file diff --git a/web/views/@default/ns/domains/records/index.js b/web/views/@default/ns/domains/records/index.js new file mode 100644 index 00000000..a93f8b5d --- /dev/null +++ b/web/views/@default/ns/domains/records/index.js @@ -0,0 +1,50 @@ +Tea.context(function () { + this.createRecord = function () { + teaweb.popup("/ns/domains/records/createPopup?domainId=" + this.domain.id, { + callback: function () { + teaweb.success("保存成功", function () { + teaweb.reload() + }) + } + }) + } + + this.updateRecord = function (recordId) { + teaweb.popup("/ns/domains/records/updatePopup?recordId=" + recordId, { + callback: function () { + teaweb.success("保存成功", function () { + teaweb.reload() + }) + } + }) + } + + this.deleteRecord = function (recordId) { + let that = this + teaweb.confirm("确定要删除此记录吗?", function () { + that.$post(".delete") + .params({ + recordId: recordId + }) + .success(function () { + teaweb.reload() + }) + }) + } + + this.formatTTL = function (ttl) { + if (ttl % 86400 == 0) { + let days = ttl / 86400 + return days + "天" + } + if (ttl % 3600 == 0) { + let hours = ttl / 3600 + return hours + "小时" + } + if (ttl % 60 == 0) { + let minutes = ttl / 60 + return minutes + "分钟" + } + return ttl + "秒" + } +}) \ No newline at end of file diff --git a/web/views/@default/ns/domains/records/updatePopup.html b/web/views/@default/ns/domains/records/updatePopup.html new file mode 100644 index 00000000..c2dede0b --- /dev/null +++ b/web/views/@default/ns/domains/records/updatePopup.html @@ -0,0 +1,48 @@ +{$layout "layout_popup"} + +

创建记录

+
+ + + + + + + + + + + + + + + + + + + + + + + +
记录名 +
+ + .{{domain.name}} +
+
记录类型 + +

{{typeDescription}}

+
记录值 + +
TTL + +
备注 + +
+ +
\ No newline at end of file diff --git a/web/views/@default/ns/domains/records/updatePopup.js b/web/views/@default/ns/domains/records/updatePopup.js new file mode 100644 index 00000000..00df31a1 --- /dev/null +++ b/web/views/@default/ns/domains/records/updatePopup.js @@ -0,0 +1,15 @@ +Tea.context(function () { + this.type = this.record.type + this.typeDescription = "" + + this.changeType = function () { + let that = this + this.types.forEach(function (v) { + if (v.type == that.type) { + that.typeDescription = v.description + } + }) + } + + this.changeType() +}) \ No newline at end of file diff --git a/web/views/@default/ns/domains/update.html b/web/views/@default/ns/domains/update.html new file mode 100644 index 00000000..d17ea974 --- /dev/null +++ b/web/views/@default/ns/domains/update.html @@ -0,0 +1,39 @@ +{$layout} +{$template "domain_menu"} + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
域名 * + +
所属集群 * + +
所属用户 + +
是否启用 + +
+ +
\ No newline at end of file diff --git a/web/views/@default/ns/domains/update.js b/web/views/@default/ns/domains/update.js new file mode 100644 index 00000000..7ab915cd --- /dev/null +++ b/web/views/@default/ns/domains/update.js @@ -0,0 +1,3 @@ +Tea.context(function () { + this.success = NotifySuccess("保存成功", "/ns/domains/domain?domainId=" + this.domain.id) +}) \ No newline at end of file diff --git a/web/views/@default/ns/index.html b/web/views/@default/ns/index.html index 8deefc83..4f3bd6e7 100644 --- a/web/views/@default/ns/index.html +++ b/web/views/@default/ns/index.html @@ -1 +1,61 @@ {$layout} +{$template "menu"} + +
+ + 暂时还没有集群,请先 创建集群。 + +
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+

暂时还没有域名。

+
+ + + + + + + + + + + + + + + + + + + +
域名集群用户状态操作
{{domain.name}} + {{domain.cluster.name}} + + + {{domain.user.fullname}} ({{domain.user.username}}) + + - + + 详情   删除 +
+
\ No newline at end of file diff --git a/web/views/@default/ns/index.js b/web/views/@default/ns/index.js new file mode 100644 index 00000000..933074cb --- /dev/null +++ b/web/views/@default/ns/index.js @@ -0,0 +1,14 @@ +Tea.context(function () { + this.deleteDomain = function (domainId) { + let that = this + teaweb.confirm("确定要删除此域名吗?", function () { + that.$post("/ns/domains/delete") + .params({ + domainId: domainId + }) + .success(function () { + teaweb.reload() + }) + }) + } +}) \ No newline at end of file diff --git a/web/views/@default/servers/components/waf/ipadmin/provinces.html b/web/views/@default/servers/components/waf/ipadmin/provinces.html index ca240b3f..542d52da 100644 --- a/web/views/@default/servers/components/waf/ipadmin/provinces.html +++ b/web/views/@default/servers/components/waf/ipadmin/provinces.html @@ -22,7 +22,7 @@ 选择省份/自治区 -
+
diff --git a/web/views/@default/servers/server/settings/conds/addGroupPopup.html b/web/views/@default/servers/server/settings/conds/addGroupPopup.html index 92544af4..400243f8 100644 --- a/web/views/@default/servers/server/settings/conds/addGroupPopup.html +++ b/web/views/@default/servers/server/settings/conds/addGroupPopup.html @@ -25,7 +25,7 @@ - + 子条件之间关系 diff --git a/web/views/@default/servers/server/settings/waf/ipadmin/provinces.html b/web/views/@default/servers/server/settings/waf/ipadmin/provinces.html index 29ca9750..bee81680 100644 --- a/web/views/@default/servers/server/settings/waf/ipadmin/provinces.html +++ b/web/views/@default/servers/server/settings/waf/ipadmin/provinces.html @@ -28,7 +28,7 @@ 选择省份/自治区 -
+