Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
963be2bc63 | ||
|
|
bd34a9bd37 | ||
|
|
32b93b2bd9 | ||
|
|
e7c4507b0b | ||
|
|
17ae34c44f | ||
|
|
b466ea2fd1 | ||
|
|
8e4ee54f03 | ||
|
|
c99547d9e3 |
3
build/configs/.gitignore
vendored
3
build/configs/.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
api.yaml
|
||||
server.yaml
|
||||
api_db.yaml
|
||||
*.pem
|
||||
*.pem
|
||||
tip.json
|
||||
2
go.mod
2
go.mod
@@ -9,6 +9,7 @@ require (
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/go-cmp v0.5.6 // indirect
|
||||
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f
|
||||
github.com/miekg/dns v1.1.35
|
||||
@@ -20,5 +21,6 @@ require (
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
|
||||
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced // indirect
|
||||
google.golang.org/grpc v1.38.0
|
||||
google.golang.org/protobuf v1.26.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "0.2.3"
|
||||
Version = "0.2.4"
|
||||
|
||||
ProductName = "Edge Admin"
|
||||
ProcessName = "edge-admin"
|
||||
|
||||
@@ -388,6 +388,14 @@ func (this *RPCClient) NSAccessLogRPC() pb.NSAccessLogServiceClient {
|
||||
return pb.NewNSAccessLogServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) MetricItemRPC() pb.MetricItemServiceClient {
|
||||
return pb.NewMetricItemServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) NodeClusterMetricItemRPC() pb.NodeClusterMetricItemServiceClient {
|
||||
return pb.NewNodeClusterMetricItemServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
// Context 构造Admin上下文
|
||||
func (this *RPCClient) Context(adminId int64) context.Context {
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -32,6 +32,9 @@ func (this *RunPopupAction) RunPost(params struct {
|
||||
this.Fail(err.Error())
|
||||
}
|
||||
|
||||
if resp.Results == nil {
|
||||
resp.Results = []*pb.ExecuteNodeClusterHealthCheckResponse_Result{}
|
||||
}
|
||||
this.Data["results"] = resp.Results
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
firewallActions "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/firewall-actions"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/health"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/message"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/metrics"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/services"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/thresholds"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/toa"
|
||||
@@ -67,6 +68,12 @@ func init() {
|
||||
GetPost("/updatePopup", new(thresholds.UpdatePopupAction)).
|
||||
Post("/delete", new(thresholds.DeleteAction)).
|
||||
|
||||
// 指标
|
||||
Prefix("/clusters/cluster/settings/metrics").
|
||||
Get("", new(metrics.IndexAction)).
|
||||
GetPost("/createPopup", new(metrics.CreatePopupAction)).
|
||||
Post("/delete", new(metrics.DeleteAction)).
|
||||
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct {
|
||||
Category string
|
||||
}) {
|
||||
if len(params.Category) == 0 {
|
||||
params.Category = "http"
|
||||
}
|
||||
this.Data["category"] = params.Category
|
||||
|
||||
countResp, err := this.RPC().MetricItemRPC().CountAllEnabledMetricItems(this.AdminContext(), &pb.CountAllEnabledMetricItemsRequest{Category: params.Category})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
itemsResp, err := this.RPC().MetricItemRPC().ListEnabledMetricItems(this.AdminContext(), &pb.ListEnabledMetricItemsRequest{
|
||||
Category: params.Category,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var itemMaps = []maps.Map{}
|
||||
for _, item := range itemsResp.MetricItems {
|
||||
itemMaps = append(itemMaps, maps.Map{
|
||||
"id": item.Id,
|
||||
"name": item.Name,
|
||||
"isOn": item.IsOn,
|
||||
"period": item.Period,
|
||||
"periodUnit": item.PeriodUnit,
|
||||
"keys": item.Keys,
|
||||
"value": item.Value,
|
||||
"category": item.Category,
|
||||
})
|
||||
}
|
||||
this.Data["items"] = itemMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package metrics
|
||||
|
||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct{}) {
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package metrics
|
||||
|
||||
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("", "setting", "setting")
|
||||
this.SecondMenu("metric")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
Category string
|
||||
}) {
|
||||
if len(params.Category) == 0 {
|
||||
params.Category = "http"
|
||||
}
|
||||
this.Data["category"] = params.Category
|
||||
|
||||
itemsResp, err := this.RPC().NodeClusterMetricItemRPC().FindAllNodeClusterMetricItems(this.AdminContext(), &pb.FindAllNodeClusterMetricItemsRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var itemMaps = []maps.Map{}
|
||||
for _, item := range itemsResp.MetricItems {
|
||||
itemMaps = append(itemMaps, maps.Map{
|
||||
"id": item.Id,
|
||||
"name": item.Name,
|
||||
"isOn": item.IsOn,
|
||||
"period": item.Period,
|
||||
"periodUnit": item.PeriodUnit,
|
||||
"keys": item.Keys,
|
||||
"value": item.Value,
|
||||
"category": item.Category,
|
||||
})
|
||||
}
|
||||
this.Data["items"] = itemMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
package clusterutils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
@@ -38,7 +36,8 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext
|
||||
action.Data["clusterId"] = clusterId
|
||||
|
||||
if clusterId > 0 {
|
||||
cluster, err := dao.SharedNodeClusterDAO.FindEnabledNodeCluster(actionPtr.(rpc.ContextInterface).AdminContext(), clusterId)
|
||||
var ctx = actionPtr.(rpc.ContextInterface).AdminContext()
|
||||
cluster, err := dao.SharedNodeClusterDAO.FindEnabledNodeCluster(ctx, clusterId)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
return
|
||||
@@ -48,6 +47,16 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext
|
||||
return
|
||||
}
|
||||
|
||||
clusterInfo, err := dao.SharedNodeClusterDAO.FindEnabledNodeClusterConfigInfo(ctx, clusterId)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
return
|
||||
}
|
||||
if clusterInfo == nil {
|
||||
action.WriteString("can not find cluster info")
|
||||
return
|
||||
}
|
||||
|
||||
tabbar := actionutils.NewTabbar()
|
||||
tabbar.Add("集群列表", "", "/clusters", "", false)
|
||||
tabbar.Add("集群节点", "", "/clusters/cluster?clusterId="+clusterIdString, "server", selectedTabbar == "node")
|
||||
@@ -64,7 +73,7 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext
|
||||
secondMenuItem := action.Data.GetString("secondMenuItem")
|
||||
switch selectedTabbar {
|
||||
case "setting":
|
||||
action.Data["leftMenuItems"] = this.createSettingMenu(cluster, secondMenuItem)
|
||||
action.Data["leftMenuItems"] = this.createSettingMenu(cluster, clusterInfo, secondMenuItem)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +81,7 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext
|
||||
}
|
||||
|
||||
// 设置菜单
|
||||
func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedItem string) (items []maps.Map) {
|
||||
func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, info *pb.FindEnabledNodeClusterConfigInfoResponse, selectedItem string) (items []maps.Map) {
|
||||
clusterId := numberutils.FormatInt64(cluster.Id)
|
||||
items = append(items, maps.Map{
|
||||
"name": "基础设置",
|
||||
@@ -92,25 +101,19 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedIt
|
||||
"isOn": cluster.HttpFirewallPolicyId > 0,
|
||||
})
|
||||
|
||||
{
|
||||
hasActions, _ := this.checkFirewallActions(cluster.Id)
|
||||
items = append(items, maps.Map{
|
||||
"name": "WAF动作",
|
||||
"url": "/clusters/cluster/settings/firewall-actions?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "firewallAction",
|
||||
"isOn": hasActions,
|
||||
})
|
||||
}
|
||||
items = append(items, maps.Map{
|
||||
"name": "WAF动作",
|
||||
"url": "/clusters/cluster/settings/firewall-actions?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "firewallAction",
|
||||
"isOn": info != nil && info.HasFirewallActions,
|
||||
})
|
||||
|
||||
{
|
||||
healthCheckIsOn, _ := this.checkHealthCheckIsOn(cluster.Id)
|
||||
items = append(items, maps.Map{
|
||||
"name": "健康检查",
|
||||
"url": "/clusters/cluster/settings/health?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "health",
|
||||
"isOn": healthCheckIsOn,
|
||||
})
|
||||
}
|
||||
items = append(items, maps.Map{
|
||||
"name": "健康检查",
|
||||
"url": "/clusters/cluster/settings/health?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "health",
|
||||
"isOn": info != nil && info.HealthCheckIsOn,
|
||||
})
|
||||
|
||||
items = append(items, maps.Map{
|
||||
"name": "DNS设置",
|
||||
@@ -118,22 +121,26 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedIt
|
||||
"isActive": selectedItem == "dns",
|
||||
"isOn": cluster.DnsDomainId > 0 || len(cluster.DnsName) > 0,
|
||||
})
|
||||
/**items = append(items, maps.Map{
|
||||
"name": "统计指标",
|
||||
"url": "/clusters/cluster/settings/metrics?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "metric",
|
||||
"isOn": info != nil && info.HasMetricItems,
|
||||
})**/
|
||||
|
||||
if teaconst.IsPlus {
|
||||
hasThresholds, _ := this.checkThresholds(cluster.Id)
|
||||
items = append(items, maps.Map{
|
||||
"name": "阈值设置",
|
||||
"url": "/clusters/cluster/settings/thresholds?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "threshold",
|
||||
"isOn": hasThresholds,
|
||||
"isOn": info != nil && info.HasThresholds,
|
||||
})
|
||||
}
|
||||
if teaconst.IsPlus {
|
||||
hasMessageReceivers, _ := this.checkMessages(cluster.Id)
|
||||
|
||||
items = append(items, maps.Map{
|
||||
"name": "消息通知",
|
||||
"url": "/clusters/cluster/settings/message?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "message",
|
||||
"isOn": hasMessageReceivers,
|
||||
"isOn": info != nil && info.HasMessageReceivers,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -148,75 +155,13 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedIt
|
||||
"url": "/clusters/cluster/settings/services?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "service",
|
||||
})
|
||||
items = append(items, maps.Map{
|
||||
"name": "TOA设置",
|
||||
"url": "/clusters/cluster/settings/toa?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "toa",
|
||||
})
|
||||
{
|
||||
items = append(items, maps.Map{
|
||||
"name": "TOA设置",
|
||||
"url": "/clusters/cluster/settings/toa?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "toa",
|
||||
"isOn": info != nil && info.IsTOAEnabled,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 检查健康检查是否开启
|
||||
func (this *ClusterHelper) checkHealthCheckIsOn(clusterId int64) (bool, error) {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
resp, err := rpcClient.NodeClusterRPC().FindNodeClusterHealthCheckConfig(rpcClient.Context(0), &pb.FindNodeClusterHealthCheckConfigRequest{NodeClusterId: clusterId})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(resp.HealthCheckJSON) > 0 {
|
||||
healthCheckConfig := &serverconfigs.HealthCheckConfig{}
|
||||
err = json.Unmarshal(resp.HealthCheckJSON, healthCheckConfig)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return healthCheckConfig.IsOn, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// 检查是否有WAF动作
|
||||
func (this *ClusterHelper) checkFirewallActions(clusterId int64) (bool, error) {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
resp, err := rpcClient.NodeClusterFirewallActionRPC().CountAllEnabledNodeClusterFirewallActions(rpcClient.Context(0), &pb.CountAllEnabledNodeClusterFirewallActionsRequest{NodeClusterId: clusterId})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return resp.Count > 0, nil
|
||||
}
|
||||
|
||||
// 检查阈值是否已经设置
|
||||
func (this *ClusterHelper) checkThresholds(clusterId int64) (bool, error) {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
resp, err := rpcClient.NodeThresholdRPC().CountAllEnabledNodeThresholds(rpcClient.Context(0), &pb.CountAllEnabledNodeThresholdsRequest{
|
||||
Role: "node",
|
||||
NodeClusterId: clusterId,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return resp.Count > 0, nil
|
||||
}
|
||||
|
||||
// 检查消息通知是否已经设置
|
||||
func (this *ClusterHelper) checkMessages(clusterId int64) (bool, error) {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
resp, err := rpcClient.MessageReceiverRPC().CountAllEnabledMessageReceivers(rpcClient.Context(0), &pb.CountAllEnabledMessageReceiversRequest{
|
||||
NodeClusterId: clusterId,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return resp.Count > 0, nil
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ func (this *CreateAction) RunPost(params struct {
|
||||
DnsDomain string
|
||||
Domains []string
|
||||
AutoRenew bool
|
||||
AuthURL string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -123,6 +124,7 @@ func (this *CreateAction) RunPost(params struct {
|
||||
DnsDomain: dnsDomain,
|
||||
Domains: realDomains,
|
||||
AutoRenew: params.AutoRenew,
|
||||
AuthURL: params.AuthURL,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -138,6 +140,7 @@ func (this *CreateAction) RunPost(params struct {
|
||||
DnsDomain: dnsDomain,
|
||||
Domains: realDomains,
|
||||
AutoRenew: params.AutoRenew,
|
||||
AuthURL: params.AuthURL,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -61,6 +61,7 @@ func (this *UpdateTaskPopupAction) RunGet(params struct {
|
||||
"domains": task.Domains,
|
||||
"autoRenew": task.AutoRenew,
|
||||
"isOn": task.IsOn,
|
||||
"authURL": task.AuthURL,
|
||||
"dnsProvider": dnsProviderMap,
|
||||
}
|
||||
|
||||
@@ -94,6 +95,7 @@ func (this *UpdateTaskPopupAction) RunPost(params struct {
|
||||
DnsDomain string
|
||||
Domains []string
|
||||
AutoRenew bool
|
||||
AuthURL string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
@@ -146,6 +148,7 @@ func (this *UpdateTaskPopupAction) RunPost(params struct {
|
||||
DnsDomain: dnsDomain,
|
||||
Domains: realDomains,
|
||||
AutoRenew: params.AutoRenew,
|
||||
AuthURL: params.AuthURL,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -22,6 +22,7 @@ func (this *ListsAction) RunGet(params struct {
|
||||
Type string
|
||||
}) {
|
||||
this.Data["subMenuItem"] = params.Type
|
||||
this.Data["type"] = params.Type
|
||||
|
||||
listId, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledPolicyIPListIdWithType(this.AdminContext(), params.FirewallPolicyId, params.Type)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type BindHTTPFirewallPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *BindHTTPFirewallPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *BindHTTPFirewallPopupAction) RunGet(params struct {
|
||||
HttpFirewallPolicyId int64
|
||||
Type string
|
||||
}) {
|
||||
this.Data["httpFirewallPolicyId"] = params.HttpFirewallPolicyId
|
||||
|
||||
// 获取已经选中的名单IDs
|
||||
var selectedIds = []int64{}
|
||||
inboundConfig, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyInboundConfig(this.AdminContext(), params.HttpFirewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if inboundConfig != nil {
|
||||
for _, ref := range inboundConfig.PublicAllowListRefs {
|
||||
selectedIds = append(selectedIds, ref.ListId)
|
||||
}
|
||||
for _, ref := range inboundConfig.PublicDenyListRefs {
|
||||
selectedIds = append(selectedIds, ref.ListId)
|
||||
}
|
||||
}
|
||||
|
||||
// 公共的名单
|
||||
countResp, err := this.RPC().IPListRPC().CountAllEnabledIPLists(this.AdminContext(), &pb.CountAllEnabledIPListsRequest{
|
||||
Type: params.Type,
|
||||
IsPublic: true,
|
||||
Keyword: "",
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
listsResp, err := this.RPC().IPListRPC().ListEnabledIPLists(this.AdminContext(), &pb.ListEnabledIPListsRequest{
|
||||
Type: params.Type,
|
||||
IsPublic: true,
|
||||
Keyword: "",
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var listMaps = []maps.Map{}
|
||||
for _, list := range listsResp.IpLists {
|
||||
// 包含的IP数量
|
||||
countItemsResp, err := this.RPC().IPItemRPC().CountIPItemsWithListId(this.AdminContext(), &pb.CountIPItemsWithListIdRequest{IpListId: list.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countItems = countItemsResp.Count
|
||||
|
||||
listMaps = append(listMaps, maps.Map{
|
||||
"id": list.Id,
|
||||
"isOn": list.IsOn,
|
||||
"name": list.Name,
|
||||
"description": list.Description,
|
||||
"countItems": countItems,
|
||||
"type": list.Type,
|
||||
"isSelected": lists.ContainsInt64(selectedIds, list.Id),
|
||||
})
|
||||
}
|
||||
this.Data["lists"] = listMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *BindHTTPFirewallPopupAction) RunPost(params struct {
|
||||
HttpFirewallPolicyId int64
|
||||
ListId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
defer this.CreateLogInfo("绑定IP名单 %d 到WAF策略 %d", params.ListId, params.HttpFirewallPolicyId)
|
||||
|
||||
// List类型
|
||||
listResp, err := this.RPC().IPListRPC().FindEnabledIPList(this.AdminContext(), &pb.FindEnabledIPListRequest{IpListId: params.ListId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var list = listResp.IpList
|
||||
if list == nil {
|
||||
this.Fail("找不到要使用的IP名单")
|
||||
}
|
||||
|
||||
// 已经绑定的
|
||||
inboundConfig, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyInboundConfig(this.AdminContext(), params.HttpFirewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if inboundConfig == nil {
|
||||
inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||
}
|
||||
inboundConfig.AddPublicList(list.Id, list.Type)
|
||||
|
||||
inboundJSON, err := json.Marshal(inboundConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, err = this.RPC().HTTPFirewallPolicyRPC().UpdateHTTPFirewallInboundConfig(this.AdminContext(), &pb.UpdateHTTPFirewallInboundConfigRequest{
|
||||
HttpFirewallPolicyId: params.HttpFirewallPolicyId,
|
||||
InboundJSON: inboundJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
103
internal/web/actions/default/servers/iplists/createIPPopup.go
Normal file
103
internal/web/actions/default/servers/iplists/createIPPopup.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type CreateIPPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateIPPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreateIPPopupAction) RunGet(params struct {
|
||||
ListId int64
|
||||
}) {
|
||||
this.Data["listId"] = params.ListId
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateIPPopupAction) RunPost(params struct {
|
||||
ListId int64
|
||||
IpFrom string
|
||||
IpTo string
|
||||
ExpiredAt int64
|
||||
Reason string
|
||||
Type string
|
||||
EventLevel string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
// 校验IPList
|
||||
existsResp, err := this.RPC().IPListRPC().ExistsEnabledIPList(this.AdminContext(), &pb.ExistsEnabledIPListRequest{IpListId: params.ListId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !existsResp.Exists {
|
||||
this.Fail("IP名单不存在")
|
||||
}
|
||||
|
||||
switch params.Type {
|
||||
case "ipv4":
|
||||
params.Must.
|
||||
Field("ipFrom", params.IpFrom).
|
||||
Require("请输入开始IP")
|
||||
|
||||
// 校验IP格式(ipFrom/ipTo)
|
||||
var ipFromLong uint64
|
||||
if !utils.IsIPv4(params.IpFrom) {
|
||||
this.Fail("请输入正确的开始IP")
|
||||
}
|
||||
ipFromLong = utils.IP2Long(params.IpFrom)
|
||||
|
||||
var ipToLong uint64
|
||||
if len(params.IpTo) > 0 && !utils.IsIPv4(params.IpTo) {
|
||||
ipToLong = utils.IP2Long(params.IpTo)
|
||||
this.Fail("请输入正确的结束IP")
|
||||
}
|
||||
|
||||
if ipFromLong > 0 && ipToLong > 0 && ipFromLong > ipToLong {
|
||||
params.IpTo, params.IpFrom = params.IpFrom, params.IpTo
|
||||
}
|
||||
case "ipv6":
|
||||
params.Must.
|
||||
Field("ipFrom", params.IpFrom).
|
||||
Require("请输入IP")
|
||||
|
||||
// 校验IP格式(ipFrom)
|
||||
if !utils.IsIPv6(params.IpFrom) {
|
||||
this.Fail("请输入正确的IPv6地址")
|
||||
}
|
||||
case "all":
|
||||
params.IpFrom = "0.0.0.0"
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().IPItemRPC().CreateIPItem(this.AdminContext(), &pb.CreateIPItemRequest{
|
||||
IpListId: params.ListId,
|
||||
IpFrom: params.IpFrom,
|
||||
IpTo: params.IpTo,
|
||||
ExpiredAt: params.ExpiredAt,
|
||||
Reason: params.Reason,
|
||||
Type: params.Type,
|
||||
EventLevel: params.EventLevel,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
itemId := createResp.IpItemId
|
||||
|
||||
// 日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "在IP名单中添加IP %d", itemId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
64
internal/web/actions/default/servers/iplists/createPopup.go
Normal file
64
internal/web/actions/default/servers/iplists/createPopup.go
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"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 {
|
||||
Type string
|
||||
}) {
|
||||
this.Data["type"] = params.Type
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Name string
|
||||
Type string
|
||||
Description string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var listId int64 = 0
|
||||
defer func() {
|
||||
defer this.CreateLogInfo("创建IP名单 %d", listId)
|
||||
}()
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入名称")
|
||||
|
||||
createResp, err := this.RPC().IPListRPC().CreateIPList(this.AdminContext(), &pb.CreateIPListRequest{
|
||||
Type: params.Type,
|
||||
Name: params.Name,
|
||||
Code: "",
|
||||
TimeoutJSON: nil,
|
||||
IsPublic: true,
|
||||
Description: params.Description,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
listId = createResp.IpListId
|
||||
|
||||
this.Data["list"] = maps.Map{
|
||||
"type": params.Type,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
27
internal/web/actions/default/servers/iplists/delete.go
Normal file
27
internal/web/actions/default/servers/iplists/delete.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
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 {
|
||||
ListId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo("删除IP名单 %d", params.ListId)
|
||||
|
||||
// 删除
|
||||
_, err := this.RPC().IPListRPC().DeleteIPList(this.AdminContext(), &pb.DeleteIPListRequest{IpListId: params.ListId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
26
internal/web/actions/default/servers/iplists/deleteIP.go
Normal file
26
internal/web/actions/default/servers/iplists/deleteIP.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteIPAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteIPAction) RunPost(params struct {
|
||||
ItemId int64
|
||||
}) {
|
||||
// 日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "从IP名单中删除IP %d", params.ItemId)
|
||||
|
||||
_, err := this.RPC().IPItemRPC().DeleteIPItem(this.AdminContext(), &pb.DeleteIPItemRequest{IpItemId: params.ItemId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
25
internal/web/actions/default/servers/iplists/export.go
Normal file
25
internal/web/actions/default/servers/iplists/export.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
|
||||
type ExportAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ExportAction) Init() {
|
||||
this.Nav("", "", "export")
|
||||
}
|
||||
|
||||
func (this *ExportAction) RunGet(params struct {
|
||||
ListId int64
|
||||
}) {
|
||||
err := InitIPList(this.Parent(), params.ListId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
57
internal/web/actions/default/servers/iplists/exportData.go
Normal file
57
internal/web/actions/default/servers/iplists/exportData.go
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type ExportDataAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ExportDataAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *ExportDataAction) RunGet(params struct {
|
||||
ListId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo("导出IP名单 %d", params.ListId)
|
||||
|
||||
resp := &pb.ListIPItemsWithListIdResponse{}
|
||||
var offset int64 = 0
|
||||
var size int64 = 1000
|
||||
for {
|
||||
itemsResp, err := this.RPC().IPItemRPC().ListIPItemsWithListId(this.AdminContext(), &pb.ListIPItemsWithListIdRequest{
|
||||
IpListId: params.ListId,
|
||||
Offset: offset,
|
||||
Size: size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(itemsResp.IpItems) == 0 {
|
||||
break
|
||||
}
|
||||
for _, item := range itemsResp.IpItems {
|
||||
resp.IpItems = append(resp.IpItems, item)
|
||||
}
|
||||
offset += size
|
||||
}
|
||||
|
||||
data, err := proto.Marshal(resp)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\"ip-list-"+numberutils.FormatInt64(params.ListId)+".data\";")
|
||||
this.AddHeader("Content-Length", strconv.Itoa(len(data)))
|
||||
this.Write(data)
|
||||
}
|
||||
59
internal/web/actions/default/servers/iplists/httpFirewall.go
Normal file
59
internal/web/actions/default/servers/iplists/httpFirewall.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ipconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// HttpFirewallAction 显示已经绑定的IP名单
|
||||
type HttpFirewallAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *HttpFirewallAction) RunPost(params struct {
|
||||
HttpFirewallPolicyId int64
|
||||
Type string
|
||||
}) {
|
||||
inboundConfig, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyInboundConfig(this.AdminContext(), params.HttpFirewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if inboundConfig == nil {
|
||||
inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||
}
|
||||
var refs []*ipconfigs.IPListRef
|
||||
switch params.Type {
|
||||
case ipconfigs.IPListTypeBlack:
|
||||
refs = inboundConfig.PublicDenyListRefs
|
||||
case ipconfigs.IPListTypeWhite:
|
||||
refs = inboundConfig.PublicAllowListRefs
|
||||
}
|
||||
|
||||
listMaps := []maps.Map{}
|
||||
for _, ref := range refs {
|
||||
listResp, err := this.RPC().IPListRPC().FindEnabledIPList(this.AdminContext(), &pb.FindEnabledIPListRequest{IpListId: ref.ListId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var list = listResp.IpList
|
||||
if list == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
listMaps = append(listMaps, maps.Map{
|
||||
"id": list.Id,
|
||||
"name": list.Name,
|
||||
})
|
||||
}
|
||||
this.Data["lists"] = listMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
87
internal/web/actions/default/servers/iplists/import.go
Normal file
87
internal/web/actions/default/servers/iplists/import.go
Normal file
@@ -0,0 +1,87 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type ImportAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ImportAction) Init() {
|
||||
this.Nav("", "", "import")
|
||||
}
|
||||
|
||||
func (this *ImportAction) RunGet(params struct {
|
||||
ListId int64
|
||||
}) {
|
||||
err := InitIPList(this.Parent(), params.ListId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *ImportAction) RunPost(params struct {
|
||||
ListId int64
|
||||
File *actions.File
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("导入IP名单 %d", params.ListId)
|
||||
|
||||
existsResp, err := this.RPC().IPListRPC().ExistsEnabledIPList(this.AdminContext(), &pb.ExistsEnabledIPListRequest{IpListId: params.ListId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !existsResp.Exists {
|
||||
this.Fail("IP名单不存在")
|
||||
}
|
||||
|
||||
if params.File == nil {
|
||||
this.Fail("请选择要导入的IP文件")
|
||||
}
|
||||
|
||||
data, err := params.File.Read()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
resp := &pb.ListIPItemsWithListIdResponse{}
|
||||
err = proto.Unmarshal(data, resp)
|
||||
if err != nil {
|
||||
this.Fail("导入失败,文件格式错误:" + err.Error())
|
||||
}
|
||||
|
||||
var count = 0
|
||||
var countIgnore = 0
|
||||
for _, item := range resp.IpItems {
|
||||
_, err = this.RPC().IPItemRPC().CreateIPItem(this.AdminContext(), &pb.CreateIPItemRequest{
|
||||
IpListId: params.ListId,
|
||||
IpFrom: item.IpFrom,
|
||||
IpTo: item.IpTo,
|
||||
ExpiredAt: item.ExpiredAt,
|
||||
Reason: item.Reason,
|
||||
Type: item.Type,
|
||||
EventLevel: item.EventLevel,
|
||||
})
|
||||
if err != nil {
|
||||
this.Fail("导入过程中出错:" + err.Error())
|
||||
}
|
||||
count++
|
||||
}
|
||||
|
||||
this.Data["count"] = count
|
||||
this.Data["countIgnore"] = countIgnore
|
||||
|
||||
this.Success()
|
||||
}
|
||||
76
internal/web/actions/default/servers/iplists/index.go
Normal file
76
internal/web/actions/default/servers/iplists/index.go
Normal file
@@ -0,0 +1,76 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ipconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
Type string
|
||||
Keyword string
|
||||
}) {
|
||||
if len(params.Type) == 0 {
|
||||
params.Type = ipconfigs.IPListTypeBlack
|
||||
}
|
||||
this.Data["type"] = params.Type
|
||||
this.Data["keyword"] = params.Keyword
|
||||
|
||||
countResp, err := this.RPC().IPListRPC().CountAllEnabledIPLists(this.AdminContext(), &pb.CountAllEnabledIPListsRequest{
|
||||
Type: params.Type,
|
||||
IsPublic: true,
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
listsResp, err := this.RPC().IPListRPC().ListEnabledIPLists(this.AdminContext(), &pb.ListEnabledIPListsRequest{
|
||||
Type: params.Type,
|
||||
IsPublic: true,
|
||||
Keyword: params.Keyword,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var listMaps = []maps.Map{}
|
||||
for _, list := range listsResp.IpLists {
|
||||
// 包含的IP数量
|
||||
countItemsResp, err := this.RPC().IPItemRPC().CountIPItemsWithListId(this.AdminContext(), &pb.CountIPItemsWithListIdRequest{IpListId: list.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countItems = countItemsResp.Count
|
||||
|
||||
listMaps = append(listMaps, maps.Map{
|
||||
"id": list.Id,
|
||||
"isOn": list.IsOn,
|
||||
"name": list.Name,
|
||||
"description": list.Description,
|
||||
"countItems": countItems,
|
||||
"type": list.Type,
|
||||
})
|
||||
}
|
||||
this.Data["lists"] = listMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
39
internal/web/actions/default/servers/iplists/init.go
Normal file
39
internal/web/actions/default/servers/iplists/init.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package iplists
|
||||
|
||||
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.AdminModuleCodeServer)).
|
||||
Data("teaMenu", "servers").
|
||||
Data("teaSubMenu", "iplist").
|
||||
Prefix("/servers/iplists").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
Get("/list", new(ListAction)).
|
||||
GetPost("/import", new(ImportAction)).
|
||||
GetPost("/export", new(ExportAction)).
|
||||
Get("/exportData", new(ExportDataAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
GetPost("/test", new(TestAction)).
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
Get("/items", new(ItemsAction)).
|
||||
|
||||
// IP相关
|
||||
GetPost("/createIPPopup", new(CreateIPPopupAction)).
|
||||
GetPost("/updateIPPopup", new(UpdateIPPopupAction)).
|
||||
Post("/deleteIP", new(DeleteIPAction)).
|
||||
|
||||
// 防火墙
|
||||
GetPost("/bindHTTPFirewallPopup", new(BindHTTPFirewallPopupAction)).
|
||||
Post("/unbindHTTPFirewall", new(UnbindHTTPFirewallAction)).
|
||||
Post("/httpFirewall", new(HttpFirewallAction)).
|
||||
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
71
internal/web/actions/default/servers/iplists/items.go
Normal file
71
internal/web/actions/default/servers/iplists/items.go
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type ItemsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ItemsAction) Init() {
|
||||
this.Nav("", "", "item")
|
||||
}
|
||||
|
||||
func (this *ItemsAction) RunGet(params struct {
|
||||
ListId int64
|
||||
}) {
|
||||
err := InitIPList(this.Parent(), params.ListId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 数量
|
||||
var listId = params.ListId
|
||||
countResp, err := this.RPC().IPItemRPC().CountIPItemsWithListId(this.AdminContext(), &pb.CountIPItemsWithListIdRequest{IpListId: listId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
// 列表
|
||||
itemsResp, err := this.RPC().IPItemRPC().ListIPItemsWithListId(this.AdminContext(), &pb.ListIPItemsWithListIdRequest{
|
||||
IpListId: listId,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
itemMaps := []maps.Map{}
|
||||
for _, item := range itemsResp.IpItems {
|
||||
expiredTime := ""
|
||||
if item.ExpiredAt > 0 {
|
||||
expiredTime = timeutil.FormatTime("Y-m-d H:i:s", item.ExpiredAt)
|
||||
}
|
||||
|
||||
itemMaps = append(itemMaps, maps.Map{
|
||||
"id": item.Id,
|
||||
"ipFrom": item.IpFrom,
|
||||
"ipTo": item.IpTo,
|
||||
"expiredTime": expiredTime,
|
||||
"reason": item.Reason,
|
||||
"type": item.Type,
|
||||
"eventLevelName": firewallconfigs.FindFirewallEventLevelName(item.EventLevel),
|
||||
})
|
||||
}
|
||||
this.Data["items"] = itemMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
25
internal/web/actions/default/servers/iplists/list.go
Normal file
25
internal/web/actions/default/servers/iplists/list.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
|
||||
type ListAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ListAction) Init() {
|
||||
this.Nav("", "", "list")
|
||||
}
|
||||
|
||||
func (this *ListAction) RunGet(params struct{
|
||||
ListId int64
|
||||
}) {
|
||||
err := InitIPList(this.Parent(), params.ListId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
74
internal/web/actions/default/servers/iplists/test.go
Normal file
74
internal/web/actions/default/servers/iplists/test.go
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type TestAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TestAction) Init() {
|
||||
this.Nav("", "", "test")
|
||||
}
|
||||
|
||||
func (this *TestAction) RunGet(params struct {
|
||||
ListId int64
|
||||
}) {
|
||||
err := InitIPList(this.Parent(), params.ListId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *TestAction) RunPost(params struct {
|
||||
ListId int64
|
||||
Ip string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
resp, err := this.RPC().IPItemRPC().CheckIPItemStatus(this.AdminContext(), &pb.CheckIPItemStatusRequest{
|
||||
IpListId: params.ListId,
|
||||
Ip: params.Ip,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
resultMap := maps.Map{
|
||||
"isDone": true,
|
||||
"isFound": resp.IsFound,
|
||||
"isOk": resp.IsOk,
|
||||
"error": resp.Error,
|
||||
"isAllowed": resp.IsAllowed,
|
||||
}
|
||||
|
||||
if resp.IpItem != nil {
|
||||
resultMap["item"] = maps.Map{
|
||||
"id": resp.IpItem.Id,
|
||||
"ipFrom": resp.IpItem.IpFrom,
|
||||
"ipTo": resp.IpItem.IpTo,
|
||||
"reason": resp.IpItem.Reason,
|
||||
"expiredAt": resp.IpItem.ExpiredAt,
|
||||
"expiredTime": timeutil.FormatTime("Y-m-d H:i:s", resp.IpItem.ExpiredAt),
|
||||
"type": resp.IpItem.Type,
|
||||
"eventLevelName": firewallconfigs.FindFirewallEventLevelName(resp.IpItem.EventLevel),
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["result"] = resultMap
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
)
|
||||
|
||||
type UnbindHTTPFirewallAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UnbindHTTPFirewallAction) RunPost(params struct {
|
||||
HttpFirewallPolicyId int64
|
||||
ListId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo("接触绑定IP名单 %d WAF策略 %d", params.ListId, params.HttpFirewallPolicyId)
|
||||
|
||||
// List类型
|
||||
listResp, err := this.RPC().IPListRPC().FindEnabledIPList(this.AdminContext(), &pb.FindEnabledIPListRequest{IpListId: params.ListId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var list = listResp.IpList
|
||||
if list == nil {
|
||||
this.Fail("找不到要使用的IP名单")
|
||||
}
|
||||
|
||||
// 已经绑定的
|
||||
inboundConfig, err := dao.SharedHTTPFirewallPolicyDAO.FindEnabledHTTPFirewallPolicyInboundConfig(this.AdminContext(), params.HttpFirewallPolicyId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if inboundConfig == nil {
|
||||
inboundConfig = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true}
|
||||
}
|
||||
inboundConfig.RemovePublicList(list.Id, list.Type)
|
||||
|
||||
inboundJSON, err := json.Marshal(inboundConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, err = this.RPC().HTTPFirewallPolicyRPC().UpdateHTTPFirewallInboundConfig(this.AdminContext(), &pb.UpdateHTTPFirewallInboundConfigRequest{
|
||||
HttpFirewallPolicyId: params.HttpFirewallPolicyId,
|
||||
InboundJSON: inboundJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
58
internal/web/actions/default/servers/iplists/update.go
Normal file
58
internal/web/actions/default/servers/iplists/update.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type UpdateAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateAction) Init() {
|
||||
this.Nav("", "", "update")
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunGet(params struct {
|
||||
ListId int64
|
||||
}) {
|
||||
err := InitIPList(this.Parent(), params.ListId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
ListId int64
|
||||
Name string
|
||||
Type string
|
||||
Description string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改IP名单 %d", params.ListId)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入名称")
|
||||
|
||||
_, err := this.RPC().IPListRPC().UpdateIPList(this.AdminContext(), &pb.UpdateIPListRequest{
|
||||
IpListId: params.ListId,
|
||||
Name: params.Name,
|
||||
Code: "",
|
||||
TimeoutJSON: nil,
|
||||
Description: params.Description,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
117
internal/web/actions/default/servers/iplists/updateIPPopup.go
Normal file
117
internal/web/actions/default/servers/iplists/updateIPPopup.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UpdateIPPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateIPPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdateIPPopupAction) RunGet(params struct {
|
||||
ItemId int64
|
||||
}) {
|
||||
itemResp, err := this.RPC().IPItemRPC().FindEnabledIPItem(this.AdminContext(), &pb.FindEnabledIPItemRequest{IpItemId: params.ItemId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
item := itemResp.IpItem
|
||||
if item == nil {
|
||||
this.NotFound("ipItem", params.ItemId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["item"] = maps.Map{
|
||||
"id": item.Id,
|
||||
"ipFrom": item.IpFrom,
|
||||
"ipTo": item.IpTo,
|
||||
"expiredAt": item.ExpiredAt,
|
||||
"reason": item.Reason,
|
||||
"type": item.Type,
|
||||
"eventLevel": item.EventLevel,
|
||||
}
|
||||
|
||||
this.Data["type"] = item.Type
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateIPPopupAction) RunPost(params struct {
|
||||
ItemId int64
|
||||
|
||||
IpFrom string
|
||||
IpTo string
|
||||
ExpiredAt int64
|
||||
Reason string
|
||||
Type string
|
||||
EventLevel string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
// 日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "修改IP名单中IP %d", params.ItemId)
|
||||
|
||||
// TODO 校验ItemId所属用户
|
||||
|
||||
switch params.Type {
|
||||
case "ipv4":
|
||||
params.Must.
|
||||
Field("ipFrom", params.IpFrom).
|
||||
Require("请输入开始IP")
|
||||
|
||||
// 校验IP格式(ipFrom/ipTo)
|
||||
var ipFromLong uint64
|
||||
if !utils.IsIPv4(params.IpFrom) {
|
||||
this.Fail("请输入正确的开始IP")
|
||||
}
|
||||
ipFromLong = utils.IP2Long(params.IpFrom)
|
||||
|
||||
var ipToLong uint64
|
||||
if len(params.IpTo) > 0 && !utils.IsIPv4(params.IpTo) {
|
||||
ipToLong = utils.IP2Long(params.IpTo)
|
||||
this.Fail("请输入正确的结束IP")
|
||||
}
|
||||
|
||||
if ipFromLong > 0 && ipToLong > 0 && ipFromLong > ipToLong {
|
||||
params.IpTo, params.IpFrom = params.IpFrom, params.IpTo
|
||||
}
|
||||
case "ipv6":
|
||||
params.Must.
|
||||
Field("ipFrom", params.IpFrom).
|
||||
Require("请输入IP")
|
||||
|
||||
// 校验IP格式(ipFrom)
|
||||
if !utils.IsIPv6(params.IpFrom) {
|
||||
this.Fail("请输入正确的IPv6地址")
|
||||
}
|
||||
case "all":
|
||||
params.IpFrom = "0.0.0.0"
|
||||
}
|
||||
|
||||
_, err := this.RPC().IPItemRPC().UpdateIPItem(this.AdminContext(), &pb.UpdateIPItemRequest{
|
||||
IpItemId: params.ItemId,
|
||||
IpFrom: params.IpFrom,
|
||||
IpTo: params.IpTo,
|
||||
ExpiredAt: params.ExpiredAt,
|
||||
Reason: params.Reason,
|
||||
Type: params.Type,
|
||||
EventLevel: params.EventLevel,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
52
internal/web/actions/default/servers/iplists/utils.go
Normal file
52
internal/web/actions/default/servers/iplists/utils.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package iplists
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
func InitIPList(action *actionutils.ParentAction, listId int64) error {
|
||||
client, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listResp, err := client.IPListRPC().FindEnabledIPList(action.AdminContext(), &pb.FindEnabledIPListRequest{IpListId: listId})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
list := listResp.IpList
|
||||
if list == nil {
|
||||
return errors.New("not found")
|
||||
}
|
||||
|
||||
var typeName = ""
|
||||
switch list.Type {
|
||||
case "black":
|
||||
typeName = "黑名单"
|
||||
case "white":
|
||||
typeName = "白名单"
|
||||
}
|
||||
|
||||
// IP数量
|
||||
countItemsResp, err := client.IPItemRPC().CountIPItemsWithListId(action.AdminContext(), &pb.CountIPItemsWithListIdRequest{IpListId: listId})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
countItems := countItemsResp.Count
|
||||
|
||||
action.Data["list"] = maps.Map{
|
||||
"id": list.Id,
|
||||
"name": list.Name,
|
||||
"type": list.Type,
|
||||
"typeName": typeName,
|
||||
"description": list.Description,
|
||||
"isOn": list.IsOn,
|
||||
"countItems": countItems,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
25
internal/web/actions/default/servers/metrics/charts.go
Normal file
25
internal/web/actions/default/servers/metrics/charts.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package metrics
|
||||
|
||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
|
||||
type ChartsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ChartsAction) Init() {
|
||||
this.Nav("", "", "chart")
|
||||
}
|
||||
|
||||
func (this *ChartsAction) RunGet(params struct {
|
||||
ItemId int64
|
||||
}) {
|
||||
err := InitItem(this.Parent(), params.ItemId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
83
internal/web/actions/default/servers/metrics/createPopup.go
Normal file
83
internal/web/actions/default/servers/metrics/createPopup.go
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"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 {
|
||||
Category string
|
||||
}) {
|
||||
this.Data["category"] = params.Category
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Name string
|
||||
Category string
|
||||
KeysJSON []byte
|
||||
PeriodJSON []byte
|
||||
Value string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入指标名称")
|
||||
|
||||
if len(params.Category) == 0 {
|
||||
this.Fail("请选择指标类型")
|
||||
}
|
||||
|
||||
// 统计对象
|
||||
if len(params.KeysJSON) == 0 {
|
||||
this.FailField("keys", "请选择指标统计的对象")
|
||||
}
|
||||
var keys = []string{}
|
||||
err := json.Unmarshal(params.KeysJSON, &keys)
|
||||
if err != nil {
|
||||
this.FailField("keys", "解析指标对象失败")
|
||||
}
|
||||
if len(keys) == 0 {
|
||||
this.FailField("keys", "请选择指标统计的对象")
|
||||
}
|
||||
|
||||
var periodMap = maps.Map{}
|
||||
err = json.Unmarshal(params.PeriodJSON, &periodMap)
|
||||
if err != nil {
|
||||
this.FailField("period", "解析统计周期失败")
|
||||
}
|
||||
var period = periodMap.GetInt32("period")
|
||||
var periodUnit = periodMap.GetString("unit")
|
||||
|
||||
createResp, err := this.RPC().MetricItemRPC().CreateMetricItem(this.AdminContext(), &pb.CreateMetricItemRequest{
|
||||
Code: "", // TODO 未来实现
|
||||
Category: params.Category,
|
||||
Name: params.Name,
|
||||
Keys: keys,
|
||||
Period: period,
|
||||
PeriodUnit: periodUnit,
|
||||
Value: params.Value,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
defer this.CreateLogInfo("创建统计指标 %d", createResp.MetricItemId)
|
||||
this.Success()
|
||||
}
|
||||
26
internal/web/actions/default/servers/metrics/delete.go
Normal file
26
internal/web/actions/default/servers/metrics/delete.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package metrics
|
||||
|
||||
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 {
|
||||
ItemId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo("删除统计指标")
|
||||
|
||||
_, err := this.RPC().MetricItemRPC().DeleteMetricItem(this.AdminContext(), &pb.DeleteMetricItemRequest{MetricItemId: params.ItemId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
61
internal/web/actions/default/servers/metrics/index.go
Normal file
61
internal/web/actions/default/servers/metrics/index.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package metrics
|
||||
|
||||
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("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
Category string
|
||||
}) {
|
||||
if len(params.Category) == 0 {
|
||||
params.Category = "http"
|
||||
}
|
||||
this.Data["category"] = params.Category
|
||||
|
||||
countResp, err := this.RPC().MetricItemRPC().CountAllEnabledMetricItems(this.AdminContext(), &pb.CountAllEnabledMetricItemsRequest{Category: params.Category})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
itemsResp, err := this.RPC().MetricItemRPC().ListEnabledMetricItems(this.AdminContext(), &pb.ListEnabledMetricItemsRequest{
|
||||
Category: params.Category,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var itemMaps = []maps.Map{}
|
||||
for _, item := range itemsResp.MetricItems {
|
||||
itemMaps = append(itemMaps, maps.Map{
|
||||
"id": item.Id,
|
||||
"name": item.Name,
|
||||
"isOn": item.IsOn,
|
||||
"period": item.Period,
|
||||
"periodUnit": item.PeriodUnit,
|
||||
"keys": item.Keys,
|
||||
"value": item.Value,
|
||||
"category": item.Category,
|
||||
})
|
||||
}
|
||||
this.Data["items"] = itemMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
24
internal/web/actions/default/servers/metrics/init.go
Normal file
24
internal/web/actions/default/servers/metrics/init.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package metrics
|
||||
|
||||
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.AdminModuleCodeServer)).
|
||||
Data("teaMenu", "servers").
|
||||
Data("teaSubMenu", "metric").
|
||||
Prefix("/servers/metrics").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
Get("/item", new(ItemAction)).
|
||||
Get("/charts", new(ChartsAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
25
internal/web/actions/default/servers/metrics/item.go
Normal file
25
internal/web/actions/default/servers/metrics/item.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package metrics
|
||||
|
||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
|
||||
type ItemAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ItemAction) Init() {
|
||||
this.Nav("", "", "item")
|
||||
}
|
||||
|
||||
func (this *ItemAction) RunGet(params struct {
|
||||
ItemId int64
|
||||
}) {
|
||||
err := InitItem(this.Parent(), params.ItemId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
84
internal/web/actions/default/servers/metrics/update.go
Normal file
84
internal/web/actions/default/servers/metrics/update.go
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"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 {
|
||||
ItemId int64
|
||||
}) {
|
||||
err := InitItem(this.Parent(), params.ItemId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
ItemId int64
|
||||
Name string
|
||||
KeysJSON []byte
|
||||
PeriodJSON []byte
|
||||
Value string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入指标名称")
|
||||
|
||||
// 统计对象
|
||||
if len(params.KeysJSON) == 0 {
|
||||
this.FailField("keys", "请选择指标统计的对象")
|
||||
}
|
||||
var keys = []string{}
|
||||
err := json.Unmarshal(params.KeysJSON, &keys)
|
||||
if err != nil {
|
||||
this.FailField("keys", "解析指标对象失败")
|
||||
}
|
||||
if len(keys) == 0 {
|
||||
this.FailField("keys", "请选择指标统计的对象")
|
||||
}
|
||||
|
||||
var periodMap = maps.Map{}
|
||||
err = json.Unmarshal(params.PeriodJSON, &periodMap)
|
||||
if err != nil {
|
||||
this.FailField("period", "解析统计周期失败")
|
||||
}
|
||||
var period = periodMap.GetInt32("period")
|
||||
var periodUnit = periodMap.GetString("unit")
|
||||
|
||||
_, err = this.RPC().MetricItemRPC().UpdateMetricItem(this.AdminContext(), &pb.UpdateMetricItemRequest{
|
||||
MetricItemId: params.ItemId,
|
||||
Name: params.Name,
|
||||
Keys: keys,
|
||||
Period: period,
|
||||
PeriodUnit: periodUnit,
|
||||
Value: params.Value,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
defer this.CreateLogInfo("修改统计指标 %d", params.ItemId)
|
||||
this.Success()
|
||||
}
|
||||
37
internal/web/actions/default/servers/metrics/utils.go
Normal file
37
internal/web/actions/default/servers/metrics/utils.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
func InitItem(parent *actionutils.ParentAction, itemId int64) error {
|
||||
client, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := client.MetricItemRPC().FindEnabledMetricItem(parent.AdminContext(), &pb.FindEnabledMetricItemRequest{MetricItemId: itemId})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var item = resp.MetricItem
|
||||
if item == nil {
|
||||
return errors.New("not found")
|
||||
}
|
||||
parent.Data["item"] = maps.Map{
|
||||
"id": item.Id,
|
||||
"name": item.Name,
|
||||
"isOn": item.IsOn,
|
||||
"keys": item.Keys,
|
||||
"value": item.Value,
|
||||
"period": item.Period,
|
||||
"periodUnit": item.PeriodUnit,
|
||||
"category": item.Category,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
"github.com/go-yaml/yaml"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
@@ -200,6 +201,26 @@ func (this *InstallAction) RunPost(params struct {
|
||||
this.Fail("设置管理员账号出错:" + err.Error())
|
||||
}
|
||||
|
||||
// 设置访问日志保留天数
|
||||
var accessLogKeepDays = dbMap.GetInt("accessLogKeepDays")
|
||||
if accessLogKeepDays > 0 {
|
||||
var config = &systemconfigs.DatabaseConfig{}
|
||||
config.ServerAccessLog.Clean.Days = accessLogKeepDays
|
||||
configJSON, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
this.Fail("配置设置访问日志保留天数出错:" + err.Error())
|
||||
return
|
||||
}
|
||||
_, err = client.SysSettingRPC().UpdateSysSetting(ctx, &pb.UpdateSysSettingRequest{
|
||||
Code: systemconfigs.SettingCodeDatabaseConfigSetting,
|
||||
ValueJSON: configJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.Fail("配置设置访问日志保留天数出错:" + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = apiConfig.WriteFile(Tea.ConfigFile("api.yaml"))
|
||||
if err != nil {
|
||||
this.Fail("保存配置失败,原因:" + err.Error())
|
||||
@@ -232,6 +253,26 @@ func (this *InstallAction) RunPost(params struct {
|
||||
this.Fail("设置管理员账号出错:" + err.Error())
|
||||
}
|
||||
|
||||
// 设置访问日志保留天数
|
||||
var accessLogKeepDays = dbMap.GetInt("accessLogKeepDays")
|
||||
if accessLogKeepDays > 0 {
|
||||
var config = &systemconfigs.DatabaseConfig{}
|
||||
config.ServerAccessLog.Clean.Days = accessLogKeepDays
|
||||
configJSON, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
this.Fail("配置设置访问日志保留天数出错:" + err.Error())
|
||||
return
|
||||
}
|
||||
_, err = client.SysSettingRPC().UpdateSysSetting(ctx, &pb.UpdateSysSettingRequest{
|
||||
Code: systemconfigs.SettingCodeDatabaseConfigSetting,
|
||||
ValueJSON: configJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.Fail("配置设置访问日志保留天数出错:" + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 写入API节点配置,完成安装
|
||||
err = apiConfig.WriteFile(Tea.ConfigFile("api.yaml"))
|
||||
if err != nil {
|
||||
|
||||
@@ -15,11 +15,12 @@ type ValidateDbAction struct {
|
||||
}
|
||||
|
||||
func (this *ValidateDbAction) RunPost(params struct {
|
||||
Host string
|
||||
Port string
|
||||
Database string
|
||||
Username string
|
||||
Password string
|
||||
Host string
|
||||
Port string
|
||||
Database string
|
||||
Username string
|
||||
Password string
|
||||
AccessLogKeepDays int
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -98,12 +99,13 @@ func (this *ValidateDbAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
this.Data["db"] = maps.Map{
|
||||
"host": params.Host,
|
||||
"port": params.Port,
|
||||
"database": params.Database,
|
||||
"username": params.Username,
|
||||
"password": params.Password,
|
||||
"passwordMask": strings.Repeat("*", len(params.Password)),
|
||||
"host": params.Host,
|
||||
"port": params.Port,
|
||||
"database": params.Database,
|
||||
"username": params.Username,
|
||||
"password": params.Password,
|
||||
"passwordMask": strings.Repeat("*", len(params.Password)),
|
||||
"accessLogKeepDays": params.AccessLogKeepDays,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
|
||||
@@ -2,22 +2,33 @@ package ui
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/conds/condutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/files"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ComponentsAction actions.Action
|
||||
|
||||
var componentsData = []byte{}
|
||||
var componentsDataSum string
|
||||
|
||||
func (this *ComponentsAction) RunGet(params struct{}) {
|
||||
this.AddHeader("Content-Type", "text/javascript; charset=utf-8")
|
||||
|
||||
// etag
|
||||
var requestETag = this.Header("If-None-Match")
|
||||
if len(requestETag) > 0 && requestETag == "\""+componentsDataSum+"\"" {
|
||||
this.ResponseWriter.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
|
||||
if !Tea.IsTesting() && len(componentsData) > 0 {
|
||||
this.AddHeader("Last-Modified", "Fri, 06 Sep 2019 08:29:50 GMT")
|
||||
this.Write(componentsData)
|
||||
@@ -81,5 +92,12 @@ func (this *ComponentsAction) RunGet(params struct{}) {
|
||||
}
|
||||
|
||||
componentsData = buffer.Bytes()
|
||||
|
||||
// ETag
|
||||
var h = md5.New()
|
||||
h.Write(buffer.Bytes())
|
||||
componentsDataSum = fmt.Sprintf("%x", h.Sum(nil))
|
||||
this.AddHeader("ETag", "\""+componentsDataSum+"\"")
|
||||
|
||||
this.Write(componentsData)
|
||||
}
|
||||
|
||||
30
internal/web/actions/default/ui/hideTip.go
Normal file
30
internal/web/actions/default/ui/hideTip.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ui
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type HideTipAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *HideTipAction) RunPost(params struct {
|
||||
Code string
|
||||
}) {
|
||||
tipKeyLocker.Lock()
|
||||
tipKeyMap[params.Code] = true
|
||||
tipKeyLocker.Unlock()
|
||||
|
||||
// 保存到文件
|
||||
tipJSON, err := json.Marshal(tipKeyMap)
|
||||
if err == nil {
|
||||
_ = ioutil.WriteFile(Tea.ConfigFile(tipConfigFile), tipJSON, 0666)
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -27,6 +27,8 @@ func init() {
|
||||
GetPost("/selectProvincesPopup", new(SelectProvincesPopupAction)).
|
||||
GetPost("/selectCountriesPopup", new(SelectCountriesPopupAction)).
|
||||
Post("/eventLevelOptions", new(EventLevelOptionsAction)).
|
||||
Post("/showTip", new(ShowTipAction)).
|
||||
Post("/hideTip", new(HideTipAction)).
|
||||
|
||||
EndAll()
|
||||
})
|
||||
|
||||
48
internal/web/actions/default/ui/showTip.go
Normal file
48
internal/web/actions/default/ui/showTip.go
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package ui
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var tipKeyMap = map[string]bool{}
|
||||
var tipKeyLocker = sync.Mutex{}
|
||||
var tipConfigFile = "tip.json"
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
// 从配置文件中加载已关闭的tips
|
||||
data, err := ioutil.ReadFile(Tea.ConfigFile(tipConfigFile))
|
||||
if err == nil {
|
||||
var m = map[string]bool{}
|
||||
err = json.Unmarshal(data, &m)
|
||||
if err == nil {
|
||||
tipKeyLocker.Lock()
|
||||
tipKeyMap = m
|
||||
tipKeyLocker.Unlock()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type ShowTipAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ShowTipAction) RunPost(params struct {
|
||||
Code string
|
||||
}) {
|
||||
tipKeyLocker.Lock()
|
||||
_, ok := tipKeyMap[params.Code]
|
||||
tipKeyLocker.Unlock()
|
||||
|
||||
this.Data["visible"] = !ok
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -167,11 +167,21 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
|
||||
"url": "/servers/components/waf",
|
||||
"code": "waf",
|
||||
},
|
||||
{
|
||||
"name": "IP名单",
|
||||
"url": "/servers/iplists",
|
||||
"code": "iplist",
|
||||
},
|
||||
{
|
||||
"name": "证书管理",
|
||||
"url": "/servers/certs",
|
||||
"code": "cert",
|
||||
},
|
||||
/**{
|
||||
"name": "统计指标",
|
||||
"url": "/servers/metrics",
|
||||
"code": "metric",
|
||||
},**/
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -109,6 +109,9 @@ import (
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/websocket"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/stat"
|
||||
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/iplists"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/metrics"
|
||||
|
||||
// 设置相关
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/authority"
|
||||
|
||||
@@ -176,6 +176,7 @@ Vue.component("health-check-config-box", {
|
||||
<td>域名</td>
|
||||
<td>
|
||||
<input type="text" v-model="urlHost"/>
|
||||
<p class="comment">在此集群上可以访问到的一个域名。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -62,7 +62,7 @@ Vue.component("tip-icon", {
|
||||
teaweb.popupTip(this.content)
|
||||
}
|
||||
},
|
||||
template: `<a href="" title="查看帮助" @click.prevent="showTip"><i class="icon question circle"></i></a>`
|
||||
template: `<a href="" title="查看帮助" @click.prevent="showTip"><i class="icon question circle grey"></i></a>`
|
||||
})
|
||||
|
||||
// 提交点击事件
|
||||
|
||||
37
web/public/js/components/common/tip-message-box.js
Normal file
37
web/public/js/components/common/tip-message-box.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// 信息提示窗口
|
||||
Vue.component("tip-message-box", {
|
||||
props: ["code"],
|
||||
mounted: function () {
|
||||
let that = this
|
||||
Tea.action("/ui/showTip")
|
||||
.params({
|
||||
code: this.code
|
||||
})
|
||||
.success(function (resp) {
|
||||
that.visible = resp.data.visible
|
||||
})
|
||||
.post()
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
visible: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
close: function () {
|
||||
this.visible = false
|
||||
Tea.action("/ui/hideTip")
|
||||
.params({
|
||||
code: this.code
|
||||
})
|
||||
.post()
|
||||
}
|
||||
},
|
||||
template: `<div class="ui icon message" v-if="visible">
|
||||
<i class="icon info circle"></i>
|
||||
<i class="close icon" title="取消" @click.prevent="close"></i>
|
||||
<div class="content">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
62
web/public/js/components/iplist/ip-list-bind-box.js
Normal file
62
web/public/js/components/iplist/ip-list-bind-box.js
Normal file
@@ -0,0 +1,62 @@
|
||||
// 绑定IP列表
|
||||
Vue.component("ip-list-bind-box", {
|
||||
props: ["v-http-firewall-policy-id", "v-type"],
|
||||
mounted: function () {
|
||||
this.refresh()
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
policyId: this.vHttpFirewallPolicyId,
|
||||
type: this.vType,
|
||||
lists: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
bind: function () {
|
||||
let that = this
|
||||
teaweb.popup("/servers/iplists/bindHTTPFirewallPopup?httpFirewallPolicyId=" + this.policyId + "&type=" + this.type, {
|
||||
width: "50em",
|
||||
height: "34em",
|
||||
callback: function () {
|
||||
|
||||
},
|
||||
onClose: function () {
|
||||
that.refresh()
|
||||
}
|
||||
})
|
||||
},
|
||||
remove: function (index, listId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除这个绑定的IP名单吗?", function () {
|
||||
Tea.action("/servers/iplists/unbindHTTPFirewall")
|
||||
.params({
|
||||
httpFirewallPolicyId: that.policyId,
|
||||
listId: listId
|
||||
})
|
||||
.post()
|
||||
.success(function (resp) {
|
||||
that.lists.$remove(index)
|
||||
})
|
||||
})
|
||||
},
|
||||
refresh: function () {
|
||||
let that = this
|
||||
Tea.action("/servers/iplists/httpFirewall")
|
||||
.params({
|
||||
httpFirewallPolicyId: this.policyId,
|
||||
type: this.vType
|
||||
})
|
||||
.post()
|
||||
.success(function (resp) {
|
||||
that.lists = resp.data.lists
|
||||
})
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<a href="" @click.prevent="bind()">绑定+</a> <span v-if="lists.length > 0"><span class="disabled small">| </span> 已绑定:</span>
|
||||
<div class="ui label basic small" v-for="(list, index) in lists">
|
||||
{{list.name}}
|
||||
<a href="" title="删除" @click.prevent="remove(index, list.id)"><i class="icon remove small"></i></a>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
@@ -34,7 +34,7 @@ Vue.component("http-access-log-box", {
|
||||
this.select()
|
||||
teaweb.popup("/servers/server/log/viewPopup?requestId=" + requestId, {
|
||||
width: "50em",
|
||||
height: "24em",
|
||||
height: "28em",
|
||||
onClose: function () {
|
||||
that.deselect()
|
||||
}
|
||||
|
||||
59
web/public/js/components/server/metric-keys-config-box.js
Normal file
59
web/public/js/components/server/metric-keys-config-box.js
Normal file
@@ -0,0 +1,59 @@
|
||||
// 指标对象
|
||||
Vue.component("metric-keys-config-box", {
|
||||
props: ["v-keys"],
|
||||
data: function () {
|
||||
let keys = this.vKeys
|
||||
if (keys == null) {
|
||||
keys = []
|
||||
}
|
||||
return {
|
||||
keys: keys,
|
||||
isAdding: false,
|
||||
key: ""
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cancel: function () {
|
||||
this.key = ""
|
||||
this.isAdding = false
|
||||
},
|
||||
confirm: function () {
|
||||
if (this.key.length > 0) {
|
||||
this.keys.push(this.key)
|
||||
this.cancel()
|
||||
}
|
||||
},
|
||||
add: function () {
|
||||
this.isAdding = true
|
||||
let that = this
|
||||
setTimeout(function () {
|
||||
that.$refs.key.focus()
|
||||
}, 100)
|
||||
},
|
||||
remove: function (index) {
|
||||
this.keys.$remove(index)
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<input type="hidden" name="keysJSON" :value="JSON.stringify(keys)"/>
|
||||
<div>
|
||||
<div v-for="(key, index) in keys" class="ui label small basic">
|
||||
{{key}} <a href="" title="删除" @click.prevent="remove"><i class="icon remove small"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isAdding" style="margin-top: 1em">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" v-model="key" ref="key" @keyup.enter="confirm()" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button type="button" class="ui button tiny" @click.prevent="confirm">确定</button>
|
||||
<a href="" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 1em" v-if="!isAdding">
|
||||
<button type="button" class="ui button tiny" @click.prevent="add">+</button>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
47
web/public/js/components/server/metric-period-config-box.js
Normal file
47
web/public/js/components/server/metric-period-config-box.js
Normal file
@@ -0,0 +1,47 @@
|
||||
// 指标周期设置
|
||||
Vue.component("metric-period-config-box", {
|
||||
props: ["v-period", "v-period-unit"],
|
||||
data: function () {
|
||||
let period = this.vPeriod
|
||||
let periodUnit = this.vPeriodUnit
|
||||
if (period == null || period.toString().length == 0) {
|
||||
period = 1
|
||||
}
|
||||
if (periodUnit == null || periodUnit.length == 0) {
|
||||
periodUnit = "day"
|
||||
}
|
||||
return {
|
||||
periodConfig: {
|
||||
period: period,
|
||||
unit: periodUnit
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
"periodConfig.period": function (v) {
|
||||
v = parseInt(v)
|
||||
if (isNaN(v) || v <= 0) {
|
||||
v = 1
|
||||
}
|
||||
this.periodConfig.period = v
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<input type="hidden" name="periodJSON" :value="JSON.stringify(periodConfig)"/>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" v-model="periodConfig.period" maxlength="4" size="4"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" v-model="periodConfig.unit">
|
||||
<option value="minute">分钟</option>
|
||||
<option value="hour">小时</option>
|
||||
<option value="day">天</option>
|
||||
<option value="week">周</option>
|
||||
<option value="month">月</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<p class="comment">在此周期内同一对象累积为同一数据。</p>
|
||||
</div>`
|
||||
})
|
||||
@@ -219,9 +219,9 @@ window.teaweb = {
|
||||
},
|
||||
popupTip: function (html) {
|
||||
Swal.fire({
|
||||
html: '<i class="icon question circle"></i><span style="line-height: 1.7">' + html + "</span>",
|
||||
html: '<div style="line-height: 1.7;text-align: left "><i class="icon question circle"></i>' + html + "</div>",
|
||||
width: "30em",
|
||||
padding: "5em",
|
||||
padding: "4em",
|
||||
showConfirmButton: false,
|
||||
showCloseButton: true,
|
||||
focusConfirm: false
|
||||
|
||||
@@ -197,9 +197,6 @@ p.margin {
|
||||
padding-top: 2em;
|
||||
padding-bottom: 2.4em;
|
||||
}
|
||||
.main-menu .ui.menu .item span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.main-menu .ui.labeled.icon.menu .item {
|
||||
font-size: 0.9em;
|
||||
@@ -214,9 +211,24 @@ p.margin {
|
||||
margin-top: 0.5em;
|
||||
color: grey;
|
||||
}
|
||||
@media screen and (max-width: 512px) {
|
||||
.main-menu .ui.menu .item.expend .subtitle {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.main-menu .ui.menu .sub-items .item {
|
||||
padding-left: 2.8em !important;
|
||||
}
|
||||
.main-menu .ui.menu .sub-items .item .icon {
|
||||
position: absolute;
|
||||
left: 1.1em;
|
||||
top: 0.93em;
|
||||
}
|
||||
@media screen and (max-width: 512px) {
|
||||
.main-menu .ui.menu .sub-items .item {
|
||||
padding-left: 1em !important;
|
||||
}
|
||||
}
|
||||
.main-menu .ui.menu .sub-items .item.active {
|
||||
background-color: #2185d0 !important;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -80,12 +80,12 @@
|
||||
<span v-if="module.code.length > 0">
|
||||
<i class="window restore outline icon" v-if="module.icon == null"></i>
|
||||
<i class="ui icon" v-if="module.icon != null" :class="module.icon"></i>
|
||||
<span>{{module.name}}</span>
|
||||
<span class="module-name">{{module.name}}</span>
|
||||
</span>
|
||||
<div class="subtitle" v-if="module.subtitle != null && module.subtitle.length > 0">{{module.subtitle}}</div>
|
||||
</a>
|
||||
<div v-if="teaMenu == module.code" class="sub-items">
|
||||
<a class="item" v-for="subItem in module.subItems" v-if="subItem.isOn !== false" :href="subItem.url" :class="{active:subItem.code == teaSubMenu}">{{subItem.name}}</a>
|
||||
<a class="item" v-for="subItem in module.subItems" v-if="subItem.isOn !== false" :href="subItem.url"><i class="icon angle right" v-if="subItem.code == teaSubMenu"></i> {{subItem.name}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -139,7 +139,7 @@ div.margin, p.margin {
|
||||
}
|
||||
|
||||
.main-menu .ui.menu .item span {
|
||||
display: none;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,9 +163,27 @@ div.margin, p.margin {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 512px) {
|
||||
.item.expend .subtitle {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.sub-items {
|
||||
.item {
|
||||
padding-left: 2.8em !important;
|
||||
|
||||
.icon {
|
||||
position: absolute;
|
||||
left: 1.1em;
|
||||
top: 0.93em;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 512px) {
|
||||
.item {
|
||||
padding-left: 1em !important;
|
||||
}
|
||||
}
|
||||
|
||||
.item.active {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<form method="post" class="ui form" v-if="!isRequesting">
|
||||
<p>成功节点:<span class="green">{{countSuccess}}</span> 失败节点:<span class="red">{{countFail}}</span></p>
|
||||
<table class="ui table selectable celled">
|
||||
<table class="ui table selectable celled" v-if="results.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>节点</th>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>添加指标</h3>
|
||||
|
||||
<p class="comment" v-if="items.length == 0">暂时还没有指标。</p>
|
||||
<table class="ui table celled selectable" v-if="items.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>指标名称</th>
|
||||
<th>统计对象</th>
|
||||
<th>统计周期</th>
|
||||
<th class="three wide">统计数值</th>
|
||||
<th class="two wide">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="item in items">
|
||||
<td>{{item.name}}</td>
|
||||
<td>
|
||||
<span v-if="item.keys != null" v-for="key in item.keys" class="ui label basic small">{{key}}</span>
|
||||
</td>
|
||||
<td>
|
||||
{{item.period}} {{item.periodUnit}}
|
||||
</td>
|
||||
<td>
|
||||
<span class="ui label small basic">{{item.value}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<label-on :v-is-on="item.isOn"></label-on>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" v-if="!item.isChecked">添加</a>
|
||||
<a href="" v-if="item.isChecked"><span class="grey">已添加</span></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
@@ -0,0 +1,47 @@
|
||||
{$layout}
|
||||
{$template "/left_menu"}
|
||||
|
||||
<div class="right-box">
|
||||
<first-menu>
|
||||
<menu-item :href="'/clusters/cluster/settings/metrics?category=http&clusterId=' + clusterId" :active="category == 'http'">HTTP</menu-item>
|
||||
<menu-item :href="'/clusters/cluster/settings/metrics?category=tcp&clusterId=' + clusterId" :active="category == 'tcp'">TCP</menu-item>
|
||||
<menu-item :href="'/clusters/cluster/settings/metrics?category=udp&clusterId=' + clusterId" :active="category == 'udp'">UDP</menu-item>
|
||||
<span class="item disabled">|</span>
|
||||
<menu-item @click.prevent="createItem">[添加指标]</menu-item>
|
||||
<span class="item disabled">|</span>
|
||||
<span class="item"><tip-icon content="在这里设置的指标,会自动应用到部署在当前集群上的所有服务上。"></tip-icon></span>
|
||||
</first-menu>
|
||||
|
||||
<p class="comment" v-if="items.length == 0">暂时还没有设置指标。</p>
|
||||
|
||||
<table class="ui table celled selectable" v-if="items.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>指标名称</th>
|
||||
<th>统计对象</th>
|
||||
<th>统计周期</th>
|
||||
<th class="three wide">统计数值</th>
|
||||
<th class="two wide">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="item in items">
|
||||
<td>{{item.name}}</td>
|
||||
<td>
|
||||
<span v-if="item.keys != null" v-for="key in item.keys" class="ui label basic small">{{key}}</span>
|
||||
</td>
|
||||
<td>
|
||||
{{item.period}} {{item.periodUnit}}
|
||||
</td>
|
||||
<td>
|
||||
<span class="ui label small basic">{{item.value}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<label-on :v-is-on="item.isOn"></label-on>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="deleteItem(item.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@@ -0,0 +1,30 @@
|
||||
Tea.context(function () {
|
||||
this.createItem = function () {
|
||||
teaweb.popup(Tea.url(".createPopup", {
|
||||
clusterId: this.clusterId
|
||||
}), {
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
},
|
||||
width: "50em",
|
||||
height: "25em"
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteItem = function (itemId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除这个指标吗?", function () {
|
||||
that.$post(".delete")
|
||||
.params({
|
||||
itemId: itemId
|
||||
})
|
||||
.success(function () {
|
||||
teaweb.success("删除成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -12,7 +12,7 @@
|
||||
<td class="title">是否启用TOA</td>
|
||||
<td>
|
||||
<checkbox name="isOn" v-model="toa.isOn"></checkbox>
|
||||
<p class="comment">在启用之前,请确保当前集群下所有节点服务器已经安装TOA模块和libnetfilter_queue,并启用了IPTables。</p>
|
||||
<p class="comment">在启用之前,请确保当前集群下所有节点服务器已经安装libnetfilter_queue,并启用了IPTables。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tbody v-show="toa.isOn">
|
||||
|
||||
@@ -24,16 +24,37 @@
|
||||
|
||||
<!-- 准备工作 -->
|
||||
<div v-show="step == 'prepare'">
|
||||
<div style="margin-bottom: 1em">
|
||||
<radio name="authType" :v-value="'http'" v-model="authType">使用HTTP认证</radio>
|
||||
<radio name="authType" :v-value="'dns'" v-model="authType">使用DNS认证</radio>
|
||||
</div>
|
||||
<div v-if="authType == 'http'">
|
||||
使用HTTP的方式请求网址<code-label>/.well-known/acme-challenge/令牌</code-label>校验,该方式要求需要实现将域名解析到集群上,之后系统会自动生成网址信息。
|
||||
</div>
|
||||
<div v-if="authType == 'dns'">
|
||||
我们在申请免费证书的过程中需要自动增加或修改相关域名的TXT记录,请先确保你已经在"域名解析" -- <a href="/dns/providers" target="_blank">"DNS服务商"</a> 中已经添加了对应的DNS服务商账号。
|
||||
</div>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">认证方式</td>
|
||||
<td>
|
||||
<div style="margin-bottom: 1em">
|
||||
<radio name="authType" :v-value="'http'" v-model="authType">使用HTTP认证</radio>
|
||||
<radio name="authType" :v-value="'dns'" v-model="authType">使用DNS认证</radio>
|
||||
</div>
|
||||
<div v-if="authType == 'http'">
|
||||
<p class="comment">使用HTTP的方式请求网址<code-label>/.well-known/acme-challenge/令牌</code-label>校验,该方式要求需要实现将域名解析到集群上,之后系统会自动生成网址信息。</p>
|
||||
</div>
|
||||
<div v-if="authType == 'dns'">
|
||||
<p class="comment">我们在申请免费证书的过程中需要自动增加或修改相关域名的TXT记录,请先确保你已经在"域名解析" -- <a href="/dns/providers" target="_blank">"DNS服务商"</a> 中已经添加了对应的DNS服务商账号。</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<a href="" @click.prevent="showPrepareMoreOptionsVisible">更多选项<i class="icon angle" :class="{up: prepareMoreOptionsVisible, down: !prepareMoreOptionsVisible}"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tbody v-show="prepareMoreOptionsVisible">
|
||||
<tr>
|
||||
<td>回调URL</td>
|
||||
<td>
|
||||
<input type="text" name="authURL" v-model="authURL" maxlength="200"/>
|
||||
<p class="comment">将认证数据以JSON的方式POST到此URL上,可以依此生成认证文件或者设置DNS域名解析。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="button-group">
|
||||
<button type="button" class="ui button primary" @click.prevent="doPrepare">下一步</button>
|
||||
|
||||
@@ -10,6 +10,12 @@ Tea.context(function () {
|
||||
this.step = "user"
|
||||
}
|
||||
|
||||
this.prepareMoreOptionsVisible = false
|
||||
this.authURL = ""
|
||||
this.showPrepareMoreOptionsVisible = function () {
|
||||
this.prepareMoreOptionsVisible = !this.prepareMoreOptionsVisible
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择用户
|
||||
*/
|
||||
@@ -78,7 +84,8 @@ Tea.context(function () {
|
||||
dnsDomain: this.dnsDomain,
|
||||
domains: this.domains,
|
||||
autoRenew: this.autoRenew ? 1 : 0,
|
||||
taskId: this.taskId
|
||||
taskId: this.taskId,
|
||||
authURL: this.authURL
|
||||
})
|
||||
.success(function (resp) {
|
||||
this.taskId = resp.data.taskId
|
||||
|
||||
@@ -41,6 +41,18 @@
|
||||
<p class="comment">在免费证书临近到期之前,是否尝试自动续期。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>回调URL</td>
|
||||
<td>
|
||||
<input type="text" name="authURL" v-model="task.authURL" maxlength="200"/>
|
||||
<p class="comment">将认证数据以JSON的方式POST到此URL上,可以依此生成认证文件或者设置DNS域名解析。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
|
||||
@@ -56,10 +56,13 @@ Tea.context(function () {
|
||||
* 添加IP名单菜单
|
||||
*/
|
||||
this.createIP = function (type) {
|
||||
let that = this
|
||||
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
||||
height: "23em",
|
||||
callback: function () {
|
||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + that.firewallPolicyId + "&type=" + type
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
<second-menu style="margin-top: -1em">
|
||||
<span class="item">ID: {{listId}} <tip-icon content="ID可以用于使用API操作此IP名单"></tip-icon></span>
|
||||
<span class="item disabled">|</span>
|
||||
<div class="item"><ip-list-bind-box :v-http-firewall-policy-id="firewallPolicyId" :v-type="type"></ip-list-bind-box></div>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="items.length == 0">暂时还没有IP。</p>
|
||||
|
||||
@@ -26,10 +26,13 @@ Tea.context(function () {
|
||||
* 添加IP名单菜单
|
||||
*/
|
||||
this.createIP = function (type) {
|
||||
let that = this
|
||||
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
||||
height: "26em",
|
||||
callback: function () {
|
||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + that.firewallPolicyId + "&type=" + type
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -42,10 +42,13 @@ Tea.context(function () {
|
||||
* 添加IP名单菜单
|
||||
*/
|
||||
this.createIP = function (type) {
|
||||
let that = this
|
||||
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
||||
height: "23em",
|
||||
callback: function () {
|
||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + that.firewallPolicyId + "&type=" + type
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,47 +1,50 @@
|
||||
Tea.context(function () {
|
||||
this.ip = ""
|
||||
this.result = {
|
||||
isDone: false,
|
||||
isOk: false,
|
||||
isFound: false,
|
||||
isAllowed: false,
|
||||
error: "",
|
||||
province: null,
|
||||
country: null,
|
||||
ipItem: null,
|
||||
ipList: null
|
||||
}
|
||||
this.ip = ""
|
||||
this.result = {
|
||||
isDone: false,
|
||||
isOk: false,
|
||||
isFound: false,
|
||||
isAllowed: false,
|
||||
error: "",
|
||||
province: null,
|
||||
country: null,
|
||||
ipItem: null,
|
||||
ipList: null
|
||||
}
|
||||
|
||||
this.$delay(function () {
|
||||
this.$watch("ip", function () {
|
||||
this.result.isDone = false
|
||||
})
|
||||
})
|
||||
this.$delay(function () {
|
||||
this.$watch("ip", function () {
|
||||
this.result.isDone = false
|
||||
})
|
||||
})
|
||||
|
||||
this.success = function (resp) {
|
||||
this.result = resp.data.result
|
||||
}
|
||||
this.success = function (resp) {
|
||||
this.result = resp.data.result
|
||||
}
|
||||
|
||||
this.updateItem = function (itemId) {
|
||||
teaweb.popup(Tea.url(".updateIPPopup?firewallPolicyId=" + this.firewallPolicyId, {itemId: itemId}), {
|
||||
height: "26em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
this.updateItem = function (itemId) {
|
||||
teaweb.popup(Tea.url(".updateIPPopup?firewallPolicyId=" + this.firewallPolicyId, {itemId: itemId}), {
|
||||
height: "26em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加IP名单菜单
|
||||
*/
|
||||
this.createIP = function (type) {
|
||||
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
||||
height: "26em",
|
||||
callback: function () {
|
||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type
|
||||
}
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 添加IP名单菜单
|
||||
*/
|
||||
this.createIP = function (type) {
|
||||
let that = this
|
||||
teaweb.popup("/servers/components/waf/ipadmin/createIPPopup?firewallPolicyId=" + this.firewallPolicyId + '&type=' + type, {
|
||||
height: "26em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + that.firewallPolicyId + "&type=" + type
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -41,6 +41,7 @@
|
||||
<td>绑定域名</td>
|
||||
<td>
|
||||
<server-name-box></server-name-box>
|
||||
<p class="comment">绑定后,才能通过域名可以访问不同的服务。</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
<td>
|
||||
<span v-if="server.ports.length == 0">-</span>
|
||||
<div v-for="port in server.ports">
|
||||
<tiny-basic-label>{{port.portRange}}<span class="small">({{port.protocol}})</span></tiny-basic-label>
|
||||
<tiny-basic-label><keyword :v-word="keyword">{{port.portRange}}</keyword><span class="small">({{port.protocol}})</span></tiny-basic-label>
|
||||
</div>
|
||||
</td>
|
||||
<td class="center">
|
||||
|
||||
10
web/views/@default/servers/iplists/@list_menu.html
Normal file
10
web/views/@default/servers/iplists/@list_menu.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<first-menu>
|
||||
<menu-item :href="'/servers/iplists?type=' + list.type">{{list.typeName}}</menu-item>
|
||||
<span class="disabled item">|</span>
|
||||
<menu-item :href="'/servers/iplists/list?listId=' + list.id" code="list">"{{list.name}}"详情</menu-item>
|
||||
<menu-item :href="'/servers/iplists/items?listId=' + list.id" code="item">IP({{list.countItems}})</menu-item>
|
||||
<menu-item :href="'/servers/iplists/update?listId=' + list.id" code="update">修改</menu-item>
|
||||
<menu-item :href="'/servers/iplists/test?listId=' + list.id" code="test">IP检查</menu-item>
|
||||
<menu-item :href="'/servers/iplists/export?listId=' + list.id" code="export">导出</menu-item>
|
||||
<menu-item :href="'/servers/iplists/import?listId=' + list.id" code="import">导入</menu-item>
|
||||
</first-menu>
|
||||
8
web/views/@default/servers/iplists/@menu.html
Normal file
8
web/views/@default/servers/iplists/@menu.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<first-menu>
|
||||
<menu-item href="/servers/iplists" :active="type == 'black'">黑名单</menu-item>
|
||||
<menu-item href="/servers/iplists?type=white" :active="type == 'white'">白名单</menu-item>
|
||||
<span class="item disabled">|</span>
|
||||
<menu-item @click.prevent="createList">[创建]</menu-item>
|
||||
<span class="item disabled">|</span>
|
||||
<span class="item"><tip-icon content="可以在WAF策略里直接引用这些公用名单。"></tip-icon></span>
|
||||
</first-menu>
|
||||
@@ -0,0 +1,38 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>绑定公用IP名单</h3>
|
||||
|
||||
|
||||
<p class="comment" v-if="lists.length == 0">暂时还没有可用的公用IP名单。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="lists.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="two wide">ID</th>
|
||||
<th>名称</th>
|
||||
<th class="two wide">类型</th>
|
||||
<th>备注</th>
|
||||
<th class="two wide">IP数量</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="list in lists">
|
||||
<td>{{list.id}}</td>
|
||||
<td>{{list.name}}</td>
|
||||
<td>
|
||||
<span v-if="list.type == 'black'">黑名单</span>
|
||||
<span v-if="list.type == 'white'">白名单</span>
|
||||
</td>
|
||||
<td>{{list.description}}</td>
|
||||
<td>
|
||||
<span v-if="list.countItems > 0">{{list.countItems}}</span>
|
||||
<span v-else class="disabled">0</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="bind(list)" v-if="!list.isSelected">绑定</a>
|
||||
<a href="" style="color: grey" @click.prevent="unbind(list)" v-if="list.isSelected">已绑定</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
23
web/views/@default/servers/iplists/bindHTTPFirewallPopup.js
Normal file
23
web/views/@default/servers/iplists/bindHTTPFirewallPopup.js
Normal file
@@ -0,0 +1,23 @@
|
||||
Tea.context(function () {
|
||||
this.bind = function (list) {
|
||||
this.$post("$")
|
||||
.params({
|
||||
httpFirewallPolicyId: this.httpFirewallPolicyId,
|
||||
listId: list.id
|
||||
})
|
||||
.success(function () {
|
||||
list.isSelected = true
|
||||
})
|
||||
}
|
||||
|
||||
this.unbind = function (list) {
|
||||
this.$post(".unbindHTTPFirewall")
|
||||
.params({
|
||||
httpFirewallPolicyId: this.httpFirewallPolicyId,
|
||||
listId: list.id
|
||||
})
|
||||
.success(function () {
|
||||
list.isSelected = false
|
||||
})
|
||||
}
|
||||
})
|
||||
76
web/views/@default/servers/iplists/createIPPopup.html
Normal file
76
web/views/@default/servers/iplists/createIPPopup.html
Normal file
@@ -0,0 +1,76 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>添加IP</h3>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="listId" :value="listId"/>
|
||||
<csrf-token></csrf-token>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">类型 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="type" v-model="type">
|
||||
<option value="ipv4">IPv4</option>
|
||||
<option value="ipv6">IPv6</option>
|
||||
<option value="all">所有IP</option>
|
||||
</select>
|
||||
<p class="comment" v-if="type == 'ipv4'">单个IPv4或一个IPv4范围。</p>
|
||||
<p class="comment" v-if="type == 'ipv6'">单个IPv6。</p>
|
||||
<p class="comment" v-if="type == 'all'">允许或禁用所有的IP。</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- IPv4 -->
|
||||
<tbody v-if="type == 'ipv4'">
|
||||
<tr>
|
||||
<td>开始IP *</td>
|
||||
<td>
|
||||
<input type="text" name="ipFrom" maxlength="64" placeholder="x.x.x.x" ref="focus"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>结束IP</td>
|
||||
<td>
|
||||
<input type="text" name="ipTo" maxlength="64" placeholder="x.x.x.x"/>
|
||||
<p class="comment">表示IP段的时候需要填写此项。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- IPv6 -->
|
||||
<tbody v-if="type == 'ipv6'">
|
||||
<tr>
|
||||
<td>IP *</td>
|
||||
<td>
|
||||
<input type="text" name="ipFrom" maxlength="64" placeholder="x:x:x:x:x:x:x:x" ref="focus"/>
|
||||
<p class="comment">IPv6地址,比如 1406:3c00:0:2409:13:58:103:15</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tr>
|
||||
<td>级别</td>
|
||||
<td>
|
||||
<firewall-event-level-options :v-value="eventLevel"></firewall-event-level-options>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>过期时间</td>
|
||||
<td>
|
||||
<datetime-input :v-name="'expiredAt'"></datetime-input>
|
||||
<p class="comment">在加入名单某一段时间后会失效,留空表示永久有效。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td><input type="text" name="reason" maxlength="100"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
4
web/views/@default/servers/iplists/createIPPopup.js
Normal file
4
web/views/@default/servers/iplists/createIPPopup.js
Normal file
@@ -0,0 +1,4 @@
|
||||
Tea.context(function () {
|
||||
this.type = "ipv4"
|
||||
this.eventLevel = (this.listType == "white") ? "debug" : "critical"
|
||||
})
|
||||
4
web/views/@default/servers/iplists/createPopup.css
Normal file
4
web/views/@default/servers/iplists/createPopup.css
Normal file
@@ -0,0 +1,4 @@
|
||||
h3 var {
|
||||
font-style: normal;
|
||||
}
|
||||
/*# sourceMappingURL=createPopup.css.map */
|
||||
1
web/views/@default/servers/iplists/createPopup.css.map
Normal file
1
web/views/@default/servers/iplists/createPopup.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["createPopup.less"],"names":[],"mappings":"AAAA,EACC;EACC,kBAAA","file":"createPopup.css"}
|
||||
31
web/views/@default/servers/iplists/createPopup.html
Normal file
31
web/views/@default/servers/iplists/createPopup.html
Normal file
@@ -0,0 +1,31 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>创建<var v-if="type == 'black'">黑名单</var><var v-if="type == 'white'">白名单</var></h3>
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="100" ref="focus"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>类型</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="type" v-model="type">
|
||||
<option value="black">黑名单</option>
|
||||
<option value="white">白名单</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<textarea name="description" rows="2" maxlength="200"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
5
web/views/@default/servers/iplists/createPopup.less
Normal file
5
web/views/@default/servers/iplists/createPopup.less
Normal file
@@ -0,0 +1,5 @@
|
||||
h3 {
|
||||
var {
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
13
web/views/@default/servers/iplists/export.html
Normal file
13
web/views/@default/servers/iplists/export.html
Normal file
@@ -0,0 +1,13 @@
|
||||
{$layout}
|
||||
{$template "list_menu"}
|
||||
|
||||
<div class="margin"></div>
|
||||
<form class="ui form">
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">说明</td>
|
||||
<td>导出所有的IP</td>
|
||||
</tr>
|
||||
</table>
|
||||
<a :href="'/servers/iplists/exportData?listId=' + list.id" class="ui button primary">导出</a>
|
||||
</form>
|
||||
19
web/views/@default/servers/iplists/import.html
Normal file
19
web/views/@default/servers/iplists/import.html
Normal file
@@ -0,0 +1,19 @@
|
||||
{$layout}
|
||||
{$template "list_menu"}
|
||||
|
||||
<div class="margin"></div>
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="listId" :value="list.id"/>
|
||||
<csrf-token></csrf-token>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">选择IP文件 *</td>
|
||||
<td>
|
||||
<input type="file" name="file" accept=".data"/>
|
||||
<p class="comment">文件名类似于<code-label>ip-list-123.data</code-label>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
7
web/views/@default/servers/iplists/import.js
Normal file
7
web/views/@default/servers/iplists/import.js
Normal file
@@ -0,0 +1,7 @@
|
||||
Tea.context(function () {
|
||||
this.success = function (resp) {
|
||||
teaweb.success("成功导入" + resp.data.count + "个IP", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
38
web/views/@default/servers/iplists/index.html
Normal file
38
web/views/@default/servers/iplists/index.html
Normal file
@@ -0,0 +1,38 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<tip-message-box code="iplist-public-tip">这里是公用的IP名单,可以在WAF策略里直接引用。</tip-message-box>
|
||||
|
||||
<p class="comment" v-if="lists.length == 0">暂时还没有公用IP名单。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="lists.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="one wide">ID</th>
|
||||
<th>名称</th>
|
||||
<th class="one wide">类型</th>
|
||||
<th>备注</th>
|
||||
<th class="one wide">IP数量</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="list in lists">
|
||||
<td>{{list.id}}</td>
|
||||
<td>{{list.name}}</td>
|
||||
<td>
|
||||
<span v-if="list.type == 'black'">黑名单</span>
|
||||
<span v-if="list.type == 'white'">白名单</span>
|
||||
</td>
|
||||
<td>{{list.description}}</td>
|
||||
<td>
|
||||
<span v-if="list.countItems > 0">{{list.countItems}}</span>
|
||||
<span v-else class="disabled">0</span>
|
||||
</td>
|
||||
<td>
|
||||
<a :href="'/servers/iplists/list?listId=' + list.id">详情</a>
|
||||
<a href="" @click.prevent="deleteList(list.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
26
web/views/@default/servers/iplists/index.js
Normal file
26
web/views/@default/servers/iplists/index.js
Normal file
@@ -0,0 +1,26 @@
|
||||
Tea.context(function () {
|
||||
this.createList = function () {
|
||||
teaweb.popup(Tea.url(".createPopup", {type: this.type}), {
|
||||
callback: function (resp) {
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location = "/servers/iplists?type=" + resp.data.list.type
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteList = function (listId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除此IP名单吗?", function () {
|
||||
that.$post(".delete")
|
||||
.params({
|
||||
listId: listId
|
||||
})
|
||||
.success(function () {
|
||||
teaweb.success("删除成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
12
web/views/@default/servers/iplists/items.html
Normal file
12
web/views/@default/servers/iplists/items.html
Normal file
@@ -0,0 +1,12 @@
|
||||
{$layout}
|
||||
{$template "list_menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item @click.prevent="createIP">[创建IP]</menu-item>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="items.length == 0">暂时还没有IP。</p>
|
||||
|
||||
<ip-list-table v-if="items.length > 0" :v-items="items" @update-item="updateItem" @delete-item="deleteItem"></ip-list-table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
37
web/views/@default/servers/iplists/items.js
Normal file
37
web/views/@default/servers/iplists/items.js
Normal file
@@ -0,0 +1,37 @@
|
||||
Tea.context(function () {
|
||||
this.updateItem = function (itemId) {
|
||||
teaweb.popup(Tea.url(".updateIPPopup", {itemId: itemId}), {
|
||||
height: "26em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteItem = function (itemId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除这个IP吗?", function () {
|
||||
that.$post(".deleteIP")
|
||||
.params({
|
||||
"itemId": itemId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加IP名单菜单
|
||||
*/
|
||||
this.createIP = function () {
|
||||
teaweb.popup(Tea.url(".createIPPopup", {listId: this.list.id}), {
|
||||
height: "23em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
24
web/views/@default/servers/iplists/list.html
Normal file
24
web/views/@default/servers/iplists/list.html
Normal file
@@ -0,0 +1,24 @@
|
||||
{$layout}
|
||||
{$template "list_menu"}
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">名称</td>
|
||||
<td>
|
||||
{{list.name}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>类型</td>
|
||||
<td>
|
||||
{{list.typeName}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<span v-if="list.description.length > 0">{{list.description}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
39
web/views/@default/servers/iplists/test.html
Normal file
39
web/views/@default/servers/iplists/test.html
Normal file
@@ -0,0 +1,39 @@
|
||||
{$layout}
|
||||
{$template "list_menu"}
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="listId" :value="list.id"/>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">IP *</td>
|
||||
<td>
|
||||
<input type="text" name="ip" class="text" maxlength="100" ref="focus" placeholder="x.x.x.x" v-model="ip"/>
|
||||
<p class="comment">要检查的IP</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>检查结果</td>
|
||||
<td>
|
||||
<div v-if="result.isDone">
|
||||
<div v-if="!result.isOk">
|
||||
<span class="red">{{result.error}}</span>
|
||||
</div>
|
||||
<div v-if="result.isFound">
|
||||
<div v-if="result.item != null">
|
||||
<div v-if="result.isAllowed">
|
||||
<span class="green">在白名单中 <ip-item-text :v-item="result.item"></ip-item-text> <a href="" @click.prevent="updateItem(result.list.id, result.item.id)" title="查看和修改"><i class="icon pencil small"></i></a></span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span class="red">在黑名单中 <ip-item-text :v-item="result.item"></ip-item-text> <a href="" @click.prevent="updateItem(result.item.id)" title="查看和修改"><i class="icon pencil small"></i></a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!result.isFound">
|
||||
没有找到和{{ip}}匹配的配置。
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn>检查IP状态</submit-btn>
|
||||
</form>
|
||||
33
web/views/@default/servers/iplists/test.js
Normal file
33
web/views/@default/servers/iplists/test.js
Normal file
@@ -0,0 +1,33 @@
|
||||
Tea.context(function () {
|
||||
this.ip = ""
|
||||
this.result = {
|
||||
isDone: false,
|
||||
isOk: false,
|
||||
isFound: false,
|
||||
isAllowed: false,
|
||||
error: "",
|
||||
ipItem: null,
|
||||
ipList: null
|
||||
}
|
||||
|
||||
this.$delay(function () {
|
||||
this.$watch("ip", function () {
|
||||
this.result.isDone = false
|
||||
})
|
||||
})
|
||||
|
||||
this.success = function (resp) {
|
||||
this.result = resp.data.result
|
||||
}
|
||||
|
||||
this.updateItem = function (itemId) {
|
||||
teaweb.popup(Tea.url(".updateIPPopup", {itemId: itemId}), {
|
||||
height: "26em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
28
web/views/@default/servers/iplists/update.html
Normal file
28
web/views/@default/servers/iplists/update.html
Normal file
@@ -0,0 +1,28 @@
|
||||
{$layout}
|
||||
{$template "list_menu"}
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="listId" :value="list.id"/>
|
||||
<csrf-token></csrf-token>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="100" ref="focus" v-model="list.name"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>类型</td>
|
||||
<td>
|
||||
{{list.typeName}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<textarea name="description" rows="2" maxlength="200" v-model="list.description"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
3
web/views/@default/servers/iplists/update.js
Normal file
3
web/views/@default/servers/iplists/update.js
Normal file
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyReloadSuccess("保存成功")
|
||||
})
|
||||
76
web/views/@default/servers/iplists/updateIPPopup.html
Normal file
76
web/views/@default/servers/iplists/updateIPPopup.html
Normal file
@@ -0,0 +1,76 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>修改IP</h3>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="itemId" :value="item.id"/>
|
||||
<input type="hidden" name="type" :value="item.type"/>
|
||||
<csrf-token></csrf-token>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">类型 *</td>
|
||||
<td>
|
||||
<!-- 类型不允许修改 -->
|
||||
<span v-if="item.type == 'ipv4'">IPv4</span>
|
||||
<span v-if="item.type == 'ipv6'">IPv6</span>
|
||||
<span v-if="item.type == 'all'">所有IP</span>
|
||||
|
||||
<p class="comment" v-if="type == 'ipv4'">单个IPv4或一个IPv4范围。</p>
|
||||
<p class="comment" v-if="type == 'ipv6'">单个IPv6。</p>
|
||||
<p class="comment" v-if="type == 'all'">允许或禁用所有的IP。</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- IPv4 -->
|
||||
<tbody v-if="type == 'ipv4'">
|
||||
<tr>
|
||||
<td>开始IP *</td>
|
||||
<td>
|
||||
<input type="text" name="ipFrom" maxlength="64" placeholder="x.x.x.x" ref="focus" v-model="item.ipFrom"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>结束IP</td>
|
||||
<td>
|
||||
<input type="text" name="ipTo" maxlength="64" placeholder="x.x.x.x" v-model="item.ipTo"/>
|
||||
<p class="comment">表示IP段的时候需要填写此项。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tr>
|
||||
<td>级别</td>
|
||||
<td>
|
||||
<firewall-event-level-options :v-value="item.eventLevel"></firewall-event-level-options>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- IPv6 -->
|
||||
<tbody v-if="type == 'ipv6'">
|
||||
<tr>
|
||||
<td>IP *</td>
|
||||
<td>
|
||||
<input type="text" name="ipFrom" maxlength="64" placeholder="x:x:x:x:x:x:x:x" ref="focus" v-model="item.ipFrom"/>
|
||||
<p class="comment">IPv6地址,比如 1406:3c00:0:2409:13:58:103:15</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>过期时间</td>
|
||||
<td>
|
||||
<datetime-input :v-name="'expiredAt'" :v-timestamp="item.expiredAt"></datetime-input>
|
||||
<p class="comment">在加入名单某一段时间后会失效,留空表示永久有效。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td><input type="text" name="reason" maxlength="100" v-model="item.reason"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
7
web/views/@default/servers/metrics/@item_menu.html
Normal file
7
web/views/@default/servers/metrics/@item_menu.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<first-menu>
|
||||
<menu-item :href="'/servers/metrics'">指标列表</menu-item>
|
||||
<span class="item disabled">|</span>
|
||||
<menu-item :href="'/servers/metrics/item?itemId=' + item.id" code="item">"{{item.name}}"详情</menu-item>
|
||||
<menu-item :href="'/servers/metrics/update?itemId=' + item.id" code="update">修改</menu-item>
|
||||
<menu-item :href="'/servers/metrics/charts?itemId=' + item.id" code="chart">图表</menu-item>
|
||||
</first-menu>
|
||||
4
web/views/@default/servers/metrics/charts.html
Normal file
4
web/views/@default/servers/metrics/charts.html
Normal file
@@ -0,0 +1,4 @@
|
||||
{$layout}
|
||||
{$template "item_menu"}
|
||||
|
||||
<p class="ui message warning">此功能暂未开通,敬等期待。</p>
|
||||
54
web/views/@default/servers/metrics/createPopup.html
Normal file
54
web/views/@default/servers/metrics/createPopup.html
Normal file
@@ -0,0 +1,54 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>创建{{category.toUpperCase()}}统计指标</h3>
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="category" :value="category"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">指标名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="100" ref="focus"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>统计对象 *</td>
|
||||
<td>
|
||||
<metric-keys-config-box :v-category="category"></metric-keys-config-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>统计周期 *</td>
|
||||
<td>
|
||||
<metric-period-config-box></metric-period-config-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>统计数值 *</td>
|
||||
<td>
|
||||
<!-- HTTP -->
|
||||
<select class="ui dropdown auto-width" name="value" v-if="category == 'http'">
|
||||
<option value="${countRequest}">请求数</option>
|
||||
<option value="${countConnection}">连接数</option>
|
||||
<option value="${countTrafficIn}">下行流量</option>
|
||||
<option value="${countTrafficOut}">上行流量</option>
|
||||
</select>
|
||||
|
||||
<!-- TCP -->
|
||||
<select class="ui dropdown auto-width" name="value" v-if="category == 'tcp'">
|
||||
<option value="${countConnection}">连接数</option>
|
||||
<option value="${countTrafficIn}">下行流量</option>
|
||||
<option value="${countTrafficOut}">上行流量</option>
|
||||
</select>
|
||||
|
||||
<!-- UDP -->
|
||||
<select class="ui dropdown auto-width" name="value" v-if="category == 'udp'">
|
||||
<option value="${countConnection}">连接数</option>
|
||||
<option value="${countTrafficIn}">下行流量</option>
|
||||
<option value="${countTrafficOut}">上行流量</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user