Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9f7cd723a | ||
|
|
4a813f08cd | ||
|
|
e75757f2bc | ||
|
|
91010325eb | ||
|
|
441c0bd628 | ||
|
|
a91b97ff2b | ||
|
|
fb775a0ee9 | ||
|
|
8ed02c8103 | ||
|
|
42a306ff22 | ||
|
|
a637783249 | ||
|
|
7ffff890a8 | ||
|
|
dbfbdddb3a | ||
|
|
f85b3a40ea | ||
|
|
27421bbd46 | ||
|
|
129d2ccef0 | ||
|
|
a553bad1ef | ||
|
|
ae7020437b | ||
|
|
74e6c7a87c | ||
|
|
658c5ae6dd | ||
|
|
7a24a69223 | ||
|
|
de90acaae4 | ||
|
|
51080f2669 | ||
|
|
fa5d97b74c | ||
|
|
42ba081cd1 | ||
|
|
404d733ba1 | ||
|
|
2f3398e251 | ||
|
|
5c09e272f3 | ||
|
|
d045f0526f | ||
|
|
0766ec9d5a | ||
|
|
4511b48382 | ||
|
|
151e58fbb9 | ||
|
|
c833ac2e96 | ||
|
|
99983330a3 | ||
|
|
a14e81a28f | ||
|
|
fc714a15a3 | ||
|
|
8a8f9d2912 | ||
|
|
58a0521605 | ||
|
|
e129b52f1c | ||
|
|
5cefd900a4 | ||
|
|
857dc70b4d | ||
|
|
e3036025bc | ||
|
|
76035dc3c2 | ||
|
|
22c55d0b83 | ||
|
|
9780937a1f | ||
|
|
b4eb6e92e0 |
@@ -9,7 +9,7 @@
|
||||
* `高扩展性` - 可以自由扩展新的节点,支持亿级数据
|
||||
|
||||
## 文档
|
||||
[点这里查看文档](https://github.com/TeaOSLab/EdgeDocs)
|
||||
[点这里查看文档](http://edge.teaos.cn/docs)
|
||||
|
||||
## 架构
|
||||

|
||||
|
||||
8
build/build-all.sh
Executable file
8
build/build-all.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
./build.sh linux amd64
|
||||
./build.sh linux 386
|
||||
./build.sh linux arm64
|
||||
./build.sh linux mips64
|
||||
./build.sh linux mips64le
|
||||
./build.sh darwin amd64
|
||||
@@ -52,6 +52,10 @@ func UpdateSecurityConfig(securityConfig *systemconfigs.SecurityConfig) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = securityConfig.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sharedSecurityConfig = securityConfig
|
||||
|
||||
// 通知更新
|
||||
@@ -86,6 +90,10 @@ func loadSecurityConfig() (*systemconfigs.SecurityConfig, error) {
|
||||
sharedSecurityConfig = defaultSecurityConfig()
|
||||
return sharedSecurityConfig, nil
|
||||
}
|
||||
err = config.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sharedSecurityConfig = config
|
||||
return sharedSecurityConfig, nil
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// API配置
|
||||
// APIConfig API配置
|
||||
type APIConfig struct {
|
||||
RPC struct {
|
||||
Endpoints []string `yaml:"endpoints"`
|
||||
@@ -18,7 +18,7 @@ type APIConfig struct {
|
||||
Secret string `yaml:"secret"`
|
||||
}
|
||||
|
||||
// 加载API配置
|
||||
// LoadAPIConfig 加载API配置
|
||||
func LoadAPIConfig() (*APIConfig, error) {
|
||||
// 候选文件
|
||||
localFile := Tea.ConfigFile("api.yaml")
|
||||
@@ -59,7 +59,7 @@ func LoadAPIConfig() (*APIConfig, error) {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// 写入API配置
|
||||
// WriteFile 写入API配置
|
||||
func (this *APIConfig) WriteFile(path string) error {
|
||||
data, err := yaml.Marshal(this)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "0.0.10"
|
||||
Version = "0.0.13"
|
||||
|
||||
ProductName = "Edge Admin"
|
||||
ProcessName = "edge-admin"
|
||||
|
||||
6
internal/const/plus.go
Normal file
6
internal/const/plus.go
Normal file
@@ -0,0 +1,6 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package teaconst
|
||||
|
||||
// IsPlus 是否为企业版
|
||||
var IsPlus = false
|
||||
@@ -87,7 +87,7 @@ func (this *AdminNode) Run() {
|
||||
Start()
|
||||
}
|
||||
|
||||
// 实现守护进程
|
||||
// Daemon 实现守护进程
|
||||
func (this *AdminNode) Daemon() {
|
||||
path := os.TempDir() + "/edge-admin.sock"
|
||||
isDebug := lists.ContainsString(os.Args, "debug")
|
||||
@@ -132,7 +132,7 @@ func (this *AdminNode) Daemon() {
|
||||
}
|
||||
}
|
||||
|
||||
// 安装系统服务
|
||||
// InstallSystemService 安装系统服务
|
||||
func (this *AdminNode) InstallSystemService() error {
|
||||
shortName := teaconst.SystemdServiceName
|
||||
|
||||
@@ -149,7 +149,7 @@ func (this *AdminNode) InstallSystemService() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 添加子PID
|
||||
// AddSubPID 添加子PID
|
||||
func (this *AdminNode) AddSubPID(pid int) {
|
||||
this.subPIDs = append(this.subPIDs, pid)
|
||||
}
|
||||
|
||||
@@ -139,6 +139,10 @@ func (this *RPCClient) DBNodeRPC() pb.DBNodeServiceClient {
|
||||
return pb.NewDBNodeServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) MonitorNodeRPC() pb.MonitorNodeServiceClient {
|
||||
return pb.NewMonitorNodeServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) DBRPC() pb.DBServiceClient {
|
||||
return pb.NewDBServiceClient(this.pickConn())
|
||||
}
|
||||
@@ -203,7 +207,7 @@ func (this *RPCClient) HTTPRewriteRuleRPC() pb.HTTPRewriteRuleServiceClient {
|
||||
return pb.NewHTTPRewriteRuleServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
// 访问日志
|
||||
// HTTPAccessLogRPC 访问日志
|
||||
func (this *RPCClient) HTTPAccessLogRPC() pb.HTTPAccessLogServiceClient {
|
||||
return pb.NewHTTPAccessLogServiceClient(this.pickConn())
|
||||
}
|
||||
@@ -224,6 +228,34 @@ func (this *RPCClient) MessageRPC() pb.MessageServiceClient {
|
||||
return pb.NewMessageServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) MessageRecipientGroupRPC() pb.MessageRecipientGroupServiceClient {
|
||||
return pb.NewMessageRecipientGroupServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) MessageRecipientRPC() pb.MessageRecipientServiceClient {
|
||||
return pb.NewMessageRecipientServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) MessageMediaRPC() pb.MessageMediaServiceClient {
|
||||
return pb.NewMessageMediaServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) MessageMediaInstanceRPC() pb.MessageMediaInstanceServiceClient {
|
||||
return pb.NewMessageMediaInstanceServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) MessageTaskRPC() pb.MessageTaskServiceClient {
|
||||
return pb.NewMessageTaskServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) MessageTaskLogRPC() pb.MessageTaskLogServiceClient {
|
||||
return pb.NewMessageTaskLogServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) MessageReceiverRPC() pb.MessageReceiverServiceClient {
|
||||
return pb.NewMessageReceiverServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) IPLibraryRPC() pb.IPLibraryServiceClient {
|
||||
return pb.NewIPLibraryServiceClient(this.pickConn())
|
||||
}
|
||||
@@ -296,7 +328,15 @@ func (this *RPCClient) NodeTaskRPC() pb.NodeTaskServiceClient {
|
||||
return pb.NewNodeTaskServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
// 构造Admin上下文
|
||||
func (this *RPCClient) AuthorityKeyRPC() pb.AuthorityKeyServiceClient {
|
||||
return pb.NewAuthorityKeyServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) AuthorityNodeRPC() pb.AuthorityNodeServiceClient {
|
||||
return pb.NewAuthorityNodeServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
// Context 构造Admin上下文
|
||||
func (this *RPCClient) Context(adminId int64) context.Context {
|
||||
ctx := context.Background()
|
||||
m := maps.Map{
|
||||
@@ -319,7 +359,7 @@ func (this *RPCClient) Context(adminId int64) context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
// 构造API上下文
|
||||
// APIContext 构造API上下文
|
||||
func (this *RPCClient) APIContext(apiNodeId int64) context.Context {
|
||||
ctx := context.Background()
|
||||
m := maps.Map{
|
||||
@@ -342,6 +382,12 @@ func (this *RPCClient) APIContext(apiNodeId int64) context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
// UpdateConfig 修改配置
|
||||
func (this *RPCClient) UpdateConfig(config *configs.APIConfig) error {
|
||||
this.apiConfig = config
|
||||
return this.init()
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (this *RPCClient) init() error {
|
||||
// 重新连接
|
||||
@@ -369,6 +415,8 @@ func (this *RPCClient) init() error {
|
||||
if len(conns) == 0 {
|
||||
return errors.New("[RPC]no available endpoints")
|
||||
}
|
||||
|
||||
// 这里不需要加锁,因为会和pickConn冲突
|
||||
this.conns = conns
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
var isConfigured bool
|
||||
|
||||
// 判断系统是否已经配置过
|
||||
// IsConfigured 判断系统是否已经配置过
|
||||
func IsConfigured() bool {
|
||||
if isConfigured {
|
||||
return true
|
||||
|
||||
68
internal/tasks/task_authority.go
Normal file
68
internal/tasks/task_authority.go
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
events.On(events.EventStart, func() {
|
||||
task := NewAuthorityTask()
|
||||
go task.Start()
|
||||
})
|
||||
}
|
||||
|
||||
type AuthorityTask struct {
|
||||
}
|
||||
|
||||
func NewAuthorityTask() *AuthorityTask {
|
||||
return &AuthorityTask{}
|
||||
}
|
||||
|
||||
func (this *AuthorityTask) Start() {
|
||||
ticker := time.NewTicker(10 * time.Minute)
|
||||
if Tea.IsTesting() {
|
||||
// 快速测试
|
||||
ticker = time.NewTicker(1 * time.Minute)
|
||||
}
|
||||
|
||||
// 初始化的时候先获取一次
|
||||
timeout := time.NewTimer(5 * time.Second)
|
||||
<-timeout.C
|
||||
err := this.Loop()
|
||||
if err != nil {
|
||||
logs.Println("[TASK][AuthorityTask]" + err.Error())
|
||||
}
|
||||
|
||||
// 定时获取
|
||||
for range ticker.C {
|
||||
err := this.Loop()
|
||||
if err != nil {
|
||||
logs.Println("[TASK][AuthorityTask]" + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *AuthorityTask) Loop() error {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := rpcClient.AuthorityKeyRPC().ReadAuthorityKey(rpcClient.Context(0), &pb.ReadAuthorityKeyRequest{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.AuthorityKey != nil {
|
||||
teaconst.IsPlus = true
|
||||
} else {
|
||||
teaconst.IsPlus = false
|
||||
}
|
||||
return nil
|
||||
}
|
||||
92
internal/tasks/task_sync_api_nodes.go
Normal file
92
internal/tasks/task_sync_api_nodes.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
events.On(events.EventStart, func() {
|
||||
task := NewSyncAPINodesTask()
|
||||
go task.Start()
|
||||
})
|
||||
}
|
||||
|
||||
// API节点同步任务
|
||||
type SyncAPINodesTask struct {
|
||||
}
|
||||
|
||||
func NewSyncAPINodesTask() *SyncAPINodesTask {
|
||||
return &SyncAPINodesTask{}
|
||||
}
|
||||
|
||||
func (this *SyncAPINodesTask) Start() {
|
||||
ticker := time.NewTicker(5 * time.Minute)
|
||||
if Tea.IsTesting() {
|
||||
// 快速测试
|
||||
ticker = time.NewTicker(1 * time.Minute)
|
||||
}
|
||||
for range ticker.C {
|
||||
err := this.Loop()
|
||||
if err != nil {
|
||||
logs.Println("[TASK][SYNC_API_NODES]" + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *SyncAPINodesTask) Loop() error {
|
||||
// 获取所有可用的节点
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := rpcClient.APINodeRPC().FindAllEnabledAPINodes(rpcClient.Context(0), &pb.FindAllEnabledAPINodesRequest{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newEndpoints := []string{}
|
||||
for _, node := range resp.Nodes {
|
||||
if !node.IsOn {
|
||||
continue
|
||||
}
|
||||
newEndpoints = append(newEndpoints, node.AccessAddrs...)
|
||||
}
|
||||
|
||||
// 和现有的对比
|
||||
config, err := configs.LoadAPIConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if this.isSame(newEndpoints, config.RPC.Endpoints) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 修改RPC对象配置
|
||||
config.RPC.Endpoints = newEndpoints
|
||||
err = rpcClient.UpdateConfig(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 保存到文件
|
||||
err = config.WriteFile(Tea.ConfigFile("api.yaml"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *SyncAPINodesTask) isSame(endpoints1 []string, endpoints2 []string) bool {
|
||||
sort.Strings(endpoints1)
|
||||
sort.Strings(endpoints2)
|
||||
return strings.Join(endpoints1, "&") == strings.Join(endpoints2, "&")
|
||||
}
|
||||
15
internal/tasks/task_sync_api_nodes_test.go
Normal file
15
internal/tasks/task_sync_api_nodes_test.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSyncAPINodesTask_Loop(t *testing.T) {
|
||||
task := NewSyncAPINodesTask()
|
||||
err := task.Loop()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
@@ -35,7 +35,7 @@ func FormatBits(bits int64) string {
|
||||
} else if bits < 1000*1000*1000 {
|
||||
return fmt.Sprintf("%.2fMB", float64(bits)/1000/1000)
|
||||
} else if bits < 1000*1000*1000*1000 {
|
||||
return fmt.Sprintf("%.2fGB", float64(bits)/1000/10001000)
|
||||
return fmt.Sprintf("%.2fGB", float64(bits)/1000/1000/1000)
|
||||
} else {
|
||||
return fmt.Sprintf("%.2fPB", float64(bits)/1000/1000/1000/1000)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
@@ -25,7 +26,21 @@ func FailPage(action actions.ActionWrapper, err error) {
|
||||
if err != nil {
|
||||
logs.Println("[" + reflect.TypeOf(action).String() + "]" + findStack(err.Error()))
|
||||
}
|
||||
action.Object().WriteString(teaconst.ErrServer)
|
||||
action.Object().ResponseWriter.WriteHeader(http.StatusInternalServerError)
|
||||
if len(action.Object().Request.Header.Get("X-Requested-With")) > 0 {
|
||||
action.Object().WriteString(teaconst.ErrServer)
|
||||
} else {
|
||||
action.Object().WriteString(`<!DOCTYPE html>
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<div style="background: #eee; border: 1px #ccc solid; padding: 10px; font-size: 12px; line-height: 1.8">
|
||||
` + teaconst.ErrServer + `
|
||||
<div>可以通过查看 <strong><em>$安装目录/logs/run.log</em></strong> 日志文件查看具体的错误提示。</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`)
|
||||
}
|
||||
}
|
||||
|
||||
// 判断动作的文件路径是否相当
|
||||
|
||||
@@ -36,6 +36,7 @@ func (this *AdminAction) RunGet(params struct {
|
||||
"username": admin.Username,
|
||||
"isOn": admin.IsOn,
|
||||
"isSuper": admin.IsSuper,
|
||||
"canLogin": admin.CanLogin,
|
||||
}
|
||||
|
||||
// 权限
|
||||
|
||||
@@ -31,6 +31,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
Pass2 string
|
||||
ModuleCodes []string
|
||||
IsSuper bool
|
||||
CanLogin bool
|
||||
|
||||
// OTP
|
||||
OtpOn bool
|
||||
@@ -88,6 +89,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
Fullname: params.Fullname,
|
||||
ModulesJSON: modulesJSON,
|
||||
IsSuper: params.IsSuper,
|
||||
CanLogin: params.CanLogin,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -42,6 +42,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
||||
"fullname": admin.Fullname,
|
||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", admin.CreatedAt),
|
||||
"otpLoginIsOn": admin.OtpLogin != nil && admin.OtpLogin.IsOn,
|
||||
"canLogin": admin.CanLogin,
|
||||
})
|
||||
}
|
||||
this.Data["admins"] = adminMaps
|
||||
|
||||
@@ -18,6 +18,7 @@ func init() {
|
||||
Post("/delete", new(DeleteAction)).
|
||||
Get("/admin", new(AdminAction)).
|
||||
Get("/otpQrcode", new(OtpQrcodeAction)).
|
||||
Post("/options", new(OptionsAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
|
||||
40
internal/web/actions/default/admins/options.go
Normal file
40
internal/web/actions/default/admins/options.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package admins
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// 系统用户选项
|
||||
// 组件中需要用到的系统用户选项
|
||||
type OptionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *OptionsAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *OptionsAction) RunPost(params struct{}) {
|
||||
// TODO 实现关键词搜索
|
||||
adminsResp, err := this.RPC().AdminRPC().ListEnabledAdmins(this.AdminContext(), &pb.ListEnabledAdminsRequest{
|
||||
Offset: 0,
|
||||
Size: 1000,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
adminMaps := []maps.Map{}
|
||||
for _, admin := range adminsResp.Admins {
|
||||
adminMaps = append(adminMaps, maps.Map{
|
||||
"id": admin.Id,
|
||||
"name": admin.Fullname,
|
||||
"username": admin.Username,
|
||||
})
|
||||
}
|
||||
this.Data["admins"] = adminMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package recipients
|
||||
|
||||
import (
|
||||
"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 CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
AdminId int64
|
||||
InstanceId int64
|
||||
User string
|
||||
|
||||
TelegramToken string
|
||||
|
||||
GroupIds string
|
||||
Description string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("adminId", params.AdminId).
|
||||
Gt(0, "请选择系统用户").
|
||||
Field("instanceId", params.InstanceId).
|
||||
Gt(0, "请选择媒介")
|
||||
|
||||
groupIds := utils.SplitNumbers(params.GroupIds)
|
||||
|
||||
resp, err := this.RPC().MessageRecipientRPC().CreateMessageRecipient(this.AdminContext(), &pb.CreateMessageRecipientRequest{
|
||||
AdminId: params.AdminId,
|
||||
MessageMediaInstanceId: params.InstanceId,
|
||||
User: params.User,
|
||||
MessageRecipientGroupIds: groupIds,
|
||||
Description: params.Description,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
defer this.CreateLogInfo("创建媒介接收人 %d", resp.MessageRecipientId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
24
internal/web/actions/default/admins/recipients/delete.go
Normal file
24
internal/web/actions/default/admins/recipients/delete.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package recipients
|
||||
|
||||
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 {
|
||||
RecipientId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo("删除媒介接收人 %d", params.RecipientId)
|
||||
|
||||
_, err := this.RPC().MessageRecipientRPC().DeleteMessageRecipient(this.AdminContext(), &pb.DeleteMessageRecipientRequest{MessageRecipientId: params.RecipientId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Name string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入分组名称")
|
||||
|
||||
_, err := this.RPC().MessageRecipientGroupRPC().CreateMessageRecipientGroup(this.AdminContext(), &pb.CreateMessageRecipientGroupRequest{Name: params.Name})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package groups
|
||||
|
||||
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 {
|
||||
GroupId int64
|
||||
}) {
|
||||
_, err := this.RPC().MessageRecipientGroupRPC().DeleteMessageRecipientGroup(this.AdminContext(), &pb.DeleteMessageRecipientGroupRequest{MessageRecipientGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package groups
|
||||
|
||||
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("", "", "group")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
groupsResp, err := this.RPC().MessageRecipientGroupRPC().FindAllEnabledMessageRecipientGroups(this.AdminContext(), &pb.FindAllEnabledMessageRecipientGroupsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
groupMaps := []maps.Map{}
|
||||
for _, group := range groupsResp.MessageRecipientGroups {
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
"isOn": group.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package groups
|
||||
|
||||
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.AdminModuleCodeAdmin)).
|
||||
Data("teaMenu", "admins").
|
||||
Data("teaSubMenu", "recipients").
|
||||
Prefix("/admins/recipients/groups").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
GetPost("/updatePopup", new(UpdatePopupAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
Get("/selectPopup", new(SelectPopupAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"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/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type SelectPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) RunGet(params struct {
|
||||
GroupIds string
|
||||
}) {
|
||||
selectedGroupIds := utils.SplitNumbers(params.GroupIds)
|
||||
|
||||
groupsResp, err := this.RPC().MessageRecipientGroupRPC().FindAllEnabledMessageRecipientGroups(this.AdminContext(), &pb.FindAllEnabledMessageRecipientGroupsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
groupMaps := []maps.Map{}
|
||||
for _, group := range groupsResp.MessageRecipientGroups {
|
||||
if lists.ContainsInt64(selectedGroupIds, group.Id) {
|
||||
continue
|
||||
}
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
"isOn": group.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package groups
|
||||
|
||||
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 UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
GroupId int64
|
||||
}) {
|
||||
groupResp, err := this.RPC().MessageRecipientGroupRPC().FindEnabledMessageRecipientGroup(this.AdminContext(), &pb.FindEnabledMessageRecipientGroupRequest{MessageRecipientGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
group := groupResp.MessageRecipientGroup
|
||||
if group == nil {
|
||||
this.NotFound("messageRecipientGroup", params.GroupId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["group"] = maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
"isOn": group.IsOn,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
GroupId int64
|
||||
Name string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入分组名称")
|
||||
|
||||
_, err := this.RPC().MessageRecipientGroupRPC().UpdateMessageRecipientGroup(this.AdminContext(), &pb.UpdateMessageRecipientGroupRequest{
|
||||
MessageRecipientGroupId: params.GroupId,
|
||||
Name: params.Name,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
70
internal/web/actions/default/admins/recipients/index.go
Normal file
70
internal/web/actions/default/admins/recipients/index.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package recipients
|
||||
|
||||
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("", "", "recipient")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
}) {
|
||||
// TODO 增加系统用户、媒介类型等条件搜索
|
||||
countResp, err := this.RPC().MessageRecipientRPC().CountAllEnabledMessageRecipients(this.AdminContext(), &pb.CountAllEnabledMessageRecipientsRequest{
|
||||
AdminId: 0,
|
||||
MediaType: "",
|
||||
MessageRecipientGroupId: 0,
|
||||
Keyword: "",
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
recipientsResp, err := this.RPC().MessageRecipientRPC().ListEnabledMessageRecipients(this.AdminContext(), &pb.ListEnabledMessageRecipientsRequest{
|
||||
AdminId: 0,
|
||||
MediaType: "",
|
||||
MessageRecipientGroupId: 0,
|
||||
Keyword: "",
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
|
||||
recipientMaps := []maps.Map{}
|
||||
for _, recipient := range recipientsResp.MessageRecipients {
|
||||
if recipient.Admin == nil {
|
||||
continue
|
||||
}
|
||||
if recipient.MessageMediaInstance == nil {
|
||||
continue
|
||||
}
|
||||
recipientMaps = append(recipientMaps, maps.Map{
|
||||
"id": recipient.Id,
|
||||
"admin": maps.Map{
|
||||
"id": recipient.Admin.Id,
|
||||
"fullname": recipient.Admin.Fullname,
|
||||
"username": recipient.Admin.Username,
|
||||
},
|
||||
"groups": recipient.MessageRecipientGroups,
|
||||
"isOn": recipient.IsOn,
|
||||
"instance": maps.Map{
|
||||
"name": recipient.MessageMediaInstance.Name,
|
||||
},
|
||||
"user": recipient.User,
|
||||
"description": recipient.Description,
|
||||
})
|
||||
}
|
||||
this.Data["recipients"] = recipientMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
25
internal/web/actions/default/admins/recipients/init.go
Normal file
25
internal/web/actions/default/admins/recipients/init.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package recipients
|
||||
|
||||
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.AdminModuleCodeAdmin)).
|
||||
Data("teaMenu", "admins").
|
||||
Data("teaSubMenu", "recipients").
|
||||
Prefix("/admins/recipients").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
Post("/mediaOptions", new(MediaOptionsAction)).
|
||||
Get("/recipient", new(RecipientAction)).
|
||||
GetPost("/test", new(TestAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
package instances
|
||||
|
||||
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{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Name string
|
||||
MediaType string
|
||||
|
||||
EmailSmtp string
|
||||
EmailUsername string
|
||||
EmailPassword string
|
||||
EmailFrom string
|
||||
|
||||
WebHookURL string
|
||||
WebHookMethod string
|
||||
WebHookHeaderNames []string
|
||||
WebHookHeaderValues []string
|
||||
WebHookContentType string
|
||||
WebHookParamNames []string
|
||||
WebHookParamValues []string
|
||||
WebHookBody string
|
||||
|
||||
ScriptType string
|
||||
ScriptPath string
|
||||
ScriptLang string
|
||||
ScriptCode string
|
||||
ScriptCwd string
|
||||
ScriptEnvNames []string
|
||||
ScriptEnvValues []string
|
||||
|
||||
DingTalkWebHookURL string
|
||||
|
||||
QyWeixinCorporateId string
|
||||
QyWeixinAgentId string
|
||||
QyWeixinAppSecret string
|
||||
QyWeixinTextFormat string
|
||||
|
||||
QyWeixinRobotWebHookURL string
|
||||
QyWeixinRobotTextFormat string
|
||||
|
||||
AliyunSmsSign string
|
||||
AliyunSmsTemplateCode string
|
||||
AliyunSmsTemplateVarNames []string
|
||||
AliyunSmsTemplateVarValues []string
|
||||
AliyunSmsAccessKeyId string
|
||||
AliyunSmsAccessKeySecret string
|
||||
|
||||
TelegramToken string
|
||||
|
||||
Description string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入媒介名称").
|
||||
Field("mediaType", params.MediaType).
|
||||
Require("请选择媒介类型")
|
||||
|
||||
options := maps.Map{}
|
||||
|
||||
switch params.MediaType {
|
||||
case "email":
|
||||
params.Must.
|
||||
Field("emailSmtp", params.EmailSmtp).
|
||||
Require("请输入SMTP地址").
|
||||
Field("emailUsername", params.EmailUsername).
|
||||
Require("请输入邮箱账号").
|
||||
Field("emailPassword", params.EmailPassword).
|
||||
Require("请输入密码或授权码")
|
||||
|
||||
options["smtp"] = params.EmailSmtp
|
||||
options["username"] = params.EmailUsername
|
||||
options["password"] = params.EmailPassword
|
||||
options["from"] = params.EmailFrom
|
||||
case "webHook":
|
||||
params.Must.
|
||||
Field("webHookURL", params.WebHookURL).
|
||||
Require("请输入URL地址").
|
||||
Match("(?i)^(http|https)://", "URL地址必须以http或https开头").
|
||||
Field("webHookMethod", params.WebHookMethod).
|
||||
Require("请选择请求方法")
|
||||
|
||||
options["url"] = params.WebHookURL
|
||||
options["method"] = params.WebHookMethod
|
||||
options["contentType"] = params.WebHookContentType
|
||||
|
||||
headers := []maps.Map{}
|
||||
if len(params.WebHookHeaderNames) > 0 {
|
||||
for index, name := range params.WebHookHeaderNames {
|
||||
if index < len(params.WebHookHeaderValues) {
|
||||
headers = append(headers, maps.Map{
|
||||
"name": name,
|
||||
"value": params.WebHookHeaderValues[index],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
options["headers"] = headers
|
||||
|
||||
if params.WebHookContentType == "params" {
|
||||
webHookParams := []maps.Map{}
|
||||
for index, name := range params.WebHookParamNames {
|
||||
if index < len(params.WebHookParamValues) {
|
||||
webHookParams = append(webHookParams, maps.Map{
|
||||
"name": name,
|
||||
"value": params.WebHookParamValues[index],
|
||||
})
|
||||
}
|
||||
}
|
||||
options["params"] = webHookParams
|
||||
} else if params.WebHookContentType == "body" {
|
||||
options["body"] = params.WebHookBody
|
||||
}
|
||||
case "script":
|
||||
if params.ScriptType == "path" {
|
||||
params.Must.
|
||||
Field("scriptPath", params.ScriptPath).
|
||||
Require("请输入脚本路径")
|
||||
} else if params.ScriptType == "code" {
|
||||
params.Must.
|
||||
Field("scriptCode", params.ScriptCode).
|
||||
Require("请输入脚本代码")
|
||||
} else {
|
||||
params.Must.
|
||||
Field("scriptPath", params.ScriptPath).
|
||||
Require("请输入脚本路径")
|
||||
}
|
||||
|
||||
options["scriptType"] = params.ScriptType
|
||||
options["path"] = params.ScriptPath
|
||||
options["scriptLang"] = params.ScriptLang
|
||||
options["script"] = params.ScriptCode
|
||||
options["cwd"] = params.ScriptCwd
|
||||
|
||||
env := []maps.Map{}
|
||||
for index, envName := range params.ScriptEnvNames {
|
||||
if index < len(params.ScriptEnvValues) {
|
||||
env = append(env, maps.Map{
|
||||
"name": envName,
|
||||
"value": params.ScriptEnvValues[index],
|
||||
})
|
||||
}
|
||||
}
|
||||
options["env"] = env
|
||||
case "dingTalk":
|
||||
params.Must.
|
||||
Field("dingTalkWebHookURL", params.DingTalkWebHookURL).
|
||||
Require("请输入Hook地址").
|
||||
Match("^https:", "Hook地址必须以https://开头")
|
||||
|
||||
options["webHookURL"] = params.DingTalkWebHookURL
|
||||
case "qyWeixin":
|
||||
params.Must.
|
||||
Field("qyWeixinCorporateId", params.QyWeixinCorporateId).
|
||||
Require("请输入企业ID").
|
||||
Field("qyWeixinAgentId", params.QyWeixinAgentId).
|
||||
Require("请输入应用AgentId").
|
||||
Field("qyWeixinSecret", params.QyWeixinAppSecret).
|
||||
Require("请输入应用Secret")
|
||||
|
||||
options["corporateId"] = params.QyWeixinCorporateId
|
||||
options["agentId"] = params.QyWeixinAgentId
|
||||
options["appSecret"] = params.QyWeixinAppSecret
|
||||
options["textFormat"] = params.QyWeixinTextFormat
|
||||
case "qyWeixinRobot":
|
||||
params.Must.
|
||||
Field("qyWeixinRobotWebHookURL", params.QyWeixinRobotWebHookURL).
|
||||
Require("请输入WebHook地址").
|
||||
Match("^https:", "WebHook地址必须以https://开头")
|
||||
|
||||
options["webHookURL"] = params.QyWeixinRobotWebHookURL
|
||||
options["textFormat"] = params.QyWeixinRobotTextFormat
|
||||
case "aliyunSms":
|
||||
params.Must.
|
||||
Field("aliyunSmsSign", params.AliyunSmsSign).
|
||||
Require("请输入签名名称").
|
||||
Field("aliyunSmsTemplateCode", params.AliyunSmsTemplateCode).
|
||||
Require("请输入模板CODE").
|
||||
Field("aliyunSmsAccessKeyId", params.AliyunSmsAccessKeyId).
|
||||
Require("请输入AccessKey ID").
|
||||
Field("aliyunSmsAccessKeySecret", params.AliyunSmsAccessKeySecret).
|
||||
Require("请输入AccessKey Secret")
|
||||
|
||||
options["sign"] = params.AliyunSmsSign
|
||||
options["templateCode"] = params.AliyunSmsTemplateCode
|
||||
options["accessKeyId"] = params.AliyunSmsAccessKeyId
|
||||
options["accessKeySecret"] = params.AliyunSmsAccessKeySecret
|
||||
|
||||
variables := []maps.Map{}
|
||||
for index, name := range params.AliyunSmsTemplateVarNames {
|
||||
if index < len(params.AliyunSmsTemplateVarValues) {
|
||||
variables = append(variables, maps.Map{
|
||||
"name": name,
|
||||
"value": params.AliyunSmsTemplateVarValues[index],
|
||||
})
|
||||
}
|
||||
}
|
||||
options["variables"] = variables
|
||||
case "telegram":
|
||||
params.Must.
|
||||
Field("telegramToken", params.TelegramToken).
|
||||
Require("请输入机器人Token")
|
||||
options["token"] = params.TelegramToken
|
||||
default:
|
||||
this.Fail("错误的媒介类型")
|
||||
}
|
||||
|
||||
optionsJSON, err := json.Marshal(options)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := this.RPC().MessageMediaInstanceRPC().CreateMessageMediaInstance(this.AdminContext(), &pb.CreateMessageMediaInstanceRequest{
|
||||
Name: params.Name,
|
||||
MediaType: params.MediaType,
|
||||
ParamsJSON: optionsJSON,
|
||||
Description: params.Description,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
defer this.CreateLogInfo("创建消息媒介 %d", resp.MessageMediaInstanceId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package instances
|
||||
|
||||
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 {
|
||||
InstanceId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo("删除消息媒介 %d", params.InstanceId)
|
||||
|
||||
_, err := this.RPC().MessageMediaInstanceRPC().DeleteMessageMediaInstance(this.AdminContext(), &pb.DeleteMessageMediaInstanceRequest{MessageMediaInstanceId: params.InstanceId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package instances
|
||||
|
||||
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("", "", "instance")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
}) {
|
||||
// TODO 增加系统用户、媒介类型等条件搜索
|
||||
countResp, err := this.RPC().MessageMediaInstanceRPC().CountAllEnabledMessageMediaInstances(this.AdminContext(), &pb.CountAllEnabledMessageMediaInstancesRequest{
|
||||
MediaType: "",
|
||||
Keyword: "",
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
instancesResp, err := this.RPC().MessageMediaInstanceRPC().ListEnabledMessageMediaInstances(this.AdminContext(), &pb.ListEnabledMessageMediaInstancesRequest{
|
||||
MediaType: "",
|
||||
Keyword: "",
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
|
||||
instanceMaps := []maps.Map{}
|
||||
for _, instance := range instancesResp.MessageMediaInstances {
|
||||
if instance.MessageMedia == nil {
|
||||
continue
|
||||
}
|
||||
instanceMaps = append(instanceMaps, maps.Map{
|
||||
"id": instance.Id,
|
||||
"name": instance.Name,
|
||||
"isOn": instance.IsOn,
|
||||
"media": maps.Map{
|
||||
"name": instance.MessageMedia.Name,
|
||||
},
|
||||
"description": instance.Description,
|
||||
})
|
||||
}
|
||||
this.Data["instances"] = instanceMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package instances
|
||||
|
||||
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.AdminModuleCodeAdmin)).
|
||||
Data("teaMenu", "admins").
|
||||
Data("teaSubMenu", "instances").
|
||||
Prefix("/admins/recipients/instances").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
Get("/instance", new(InstanceAction)).
|
||||
GetPost("/test", new(TestAction)).
|
||||
Post("/options", new(OptionsAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type InstanceAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *InstanceAction) Init() {
|
||||
this.Nav("", "", "instance")
|
||||
}
|
||||
|
||||
func (this *InstanceAction) RunGet(params struct {
|
||||
InstanceId int64
|
||||
}) {
|
||||
instanceResp, err := this.RPC().MessageMediaInstanceRPC().FindEnabledMessageMediaInstance(this.AdminContext(), &pb.FindEnabledMessageMediaInstanceRequest{MessageMediaInstanceId: params.InstanceId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
instance := instanceResp.MessageMediaInstance
|
||||
if instance == nil || instance.MessageMedia == nil {
|
||||
this.NotFound("messageMediaInstance", params.InstanceId)
|
||||
return
|
||||
}
|
||||
|
||||
mediaParams := maps.Map{}
|
||||
if len(instance.ParamsJSON) > 0 {
|
||||
err = json.Unmarshal(instance.ParamsJSON, &mediaParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["instance"] = maps.Map{
|
||||
"id": instance.Id,
|
||||
"name": instance.Name,
|
||||
"isOn": instance.IsOn,
|
||||
"media": maps.Map{
|
||||
"type": instance.MessageMedia.Type,
|
||||
"name": instance.MessageMedia.Name,
|
||||
},
|
||||
"description": instance.Description,
|
||||
"params": mediaParams,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// 媒介类型选项
|
||||
type OptionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *OptionsAction) RunPost(params struct{}) {
|
||||
resp, err := this.RPC().MessageMediaInstanceRPC().ListEnabledMessageMediaInstances(this.AdminContext(), &pb.ListEnabledMessageMediaInstancesRequest{
|
||||
Offset: 0,
|
||||
Size: 1000,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
instanceMaps := []maps.Map{}
|
||||
for _, instance := range resp.MessageMediaInstances {
|
||||
instanceMaps = append(instanceMaps, maps.Map{
|
||||
"id": instance.Id,
|
||||
"name": instance.Name,
|
||||
"description": instance.Description,
|
||||
"media": maps.Map{
|
||||
"type": instance.MessageMedia.Type,
|
||||
"name": instance.MessageMedia.Name,
|
||||
"userDescription": instance.MessageMedia.UserDescription,
|
||||
},
|
||||
})
|
||||
}
|
||||
this.Data["instances"] = instanceMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package instances
|
||||
|
||||
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 TestAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TestAction) Init() {
|
||||
this.Nav("", "", "test")
|
||||
}
|
||||
|
||||
func (this *TestAction) RunGet(params struct {
|
||||
InstanceId int64
|
||||
}) {
|
||||
instanceResp, err := this.RPC().MessageMediaInstanceRPC().FindEnabledMessageMediaInstance(this.AdminContext(), &pb.FindEnabledMessageMediaInstanceRequest{MessageMediaInstanceId: params.InstanceId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
instance := instanceResp.MessageMediaInstance
|
||||
if instance == nil || instance.MessageMedia == nil {
|
||||
this.NotFound("messageMediaInstance", params.InstanceId)
|
||||
return
|
||||
}
|
||||
|
||||
mediaParams := maps.Map{}
|
||||
if len(instance.ParamsJSON) > 0 {
|
||||
err = json.Unmarshal(instance.ParamsJSON, &mediaParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["instance"] = maps.Map{
|
||||
"id": instance.Id,
|
||||
"isOn": instance.IsOn,
|
||||
"media": maps.Map{
|
||||
"type": instance.MessageMedia.Type,
|
||||
"name": instance.MessageMedia.Name,
|
||||
"userDescription": instance.MessageMedia.UserDescription,
|
||||
},
|
||||
"description": instance.Description,
|
||||
"params": mediaParams,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *TestAction) RunPost(params struct {
|
||||
InstanceId int64
|
||||
Subject string
|
||||
Body string
|
||||
User string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("instanceId", params.InstanceId).
|
||||
Gt(0, "请选择正确的媒介")
|
||||
|
||||
resp, err := this.RPC().MessageTaskRPC().CreateMessageTask(this.AdminContext(), &pb.CreateMessageTaskRequest{
|
||||
RecipientId: 0,
|
||||
InstanceId: params.InstanceId,
|
||||
User: params.User,
|
||||
Subject: params.Subject,
|
||||
Body: params.Body,
|
||||
IsPrimary: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["taskId"] = resp.MessageTaskId
|
||||
|
||||
defer this.CreateLogInfo("创建媒介测试任务 %d", resp.MessageTaskId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
package instances
|
||||
|
||||
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 {
|
||||
InstanceId int64
|
||||
}) {
|
||||
instanceResp, err := this.RPC().MessageMediaInstanceRPC().FindEnabledMessageMediaInstance(this.AdminContext(), &pb.FindEnabledMessageMediaInstanceRequest{MessageMediaInstanceId: params.InstanceId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
instance := instanceResp.MessageMediaInstance
|
||||
if instance == nil || instance.MessageMedia == nil {
|
||||
this.NotFound("messageMediaInstance", params.InstanceId)
|
||||
return
|
||||
}
|
||||
|
||||
mediaParams := maps.Map{}
|
||||
if len(instance.ParamsJSON) > 0 {
|
||||
err = json.Unmarshal(instance.ParamsJSON, &mediaParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["instance"] = maps.Map{
|
||||
"id": instance.Id,
|
||||
"name": instance.Name,
|
||||
"isOn": instance.IsOn,
|
||||
"media": maps.Map{
|
||||
"type": instance.MessageMedia.Type,
|
||||
"name": instance.MessageMedia.Name,
|
||||
},
|
||||
"description": instance.Description,
|
||||
"params": mediaParams,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
InstanceId int64
|
||||
Name string
|
||||
MediaType string
|
||||
|
||||
EmailSmtp string
|
||||
EmailUsername string
|
||||
EmailPassword string
|
||||
EmailFrom string
|
||||
|
||||
WebHookURL string
|
||||
WebHookMethod string
|
||||
WebHookHeaderNames []string
|
||||
WebHookHeaderValues []string
|
||||
WebHookContentType string
|
||||
WebHookParamNames []string
|
||||
WebHookParamValues []string
|
||||
WebHookBody string
|
||||
|
||||
ScriptType string
|
||||
ScriptPath string
|
||||
ScriptLang string
|
||||
ScriptCode string
|
||||
ScriptCwd string
|
||||
ScriptEnvNames []string
|
||||
ScriptEnvValues []string
|
||||
|
||||
DingTalkWebHookURL string
|
||||
|
||||
QyWeixinCorporateId string
|
||||
QyWeixinAgentId string
|
||||
QyWeixinAppSecret string
|
||||
QyWeixinTextFormat string
|
||||
|
||||
QyWeixinRobotWebHookURL string
|
||||
QyWeixinRobotTextFormat string
|
||||
|
||||
AliyunSmsSign string
|
||||
AliyunSmsTemplateCode string
|
||||
AliyunSmsTemplateVarNames []string
|
||||
AliyunSmsTemplateVarValues []string
|
||||
AliyunSmsAccessKeyId string
|
||||
AliyunSmsAccessKeySecret string
|
||||
|
||||
TelegramToken string
|
||||
|
||||
GroupIds string
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改消息媒介 %d", params.InstanceId)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入媒介名称").
|
||||
Field("mediaType", params.MediaType).
|
||||
Require("请选择媒介类型")
|
||||
|
||||
options := maps.Map{}
|
||||
|
||||
switch params.MediaType {
|
||||
case "email":
|
||||
params.Must.
|
||||
Field("emailSmtp", params.EmailSmtp).
|
||||
Require("请输入SMTP地址").
|
||||
Field("emailUsername", params.EmailUsername).
|
||||
Require("请输入邮箱账号").
|
||||
Field("emailPassword", params.EmailPassword).
|
||||
Require("请输入密码或授权码")
|
||||
|
||||
options["smtp"] = params.EmailSmtp
|
||||
options["username"] = params.EmailUsername
|
||||
options["password"] = params.EmailPassword
|
||||
options["from"] = params.EmailFrom
|
||||
case "webHook":
|
||||
params.Must.
|
||||
Field("webHookURL", params.WebHookURL).
|
||||
Require("请输入URL地址").
|
||||
Match("(?i)^(http|https)://", "URL地址必须以http或https开头").
|
||||
Field("webHookMethod", params.WebHookMethod).
|
||||
Require("请选择请求方法")
|
||||
|
||||
options["url"] = params.WebHookURL
|
||||
options["method"] = params.WebHookMethod
|
||||
options["contentType"] = params.WebHookContentType
|
||||
|
||||
headers := []maps.Map{}
|
||||
if len(params.WebHookHeaderNames) > 0 {
|
||||
for index, name := range params.WebHookHeaderNames {
|
||||
if index < len(params.WebHookHeaderValues) {
|
||||
headers = append(headers, maps.Map{
|
||||
"name": name,
|
||||
"value": params.WebHookHeaderValues[index],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
options["headers"] = headers
|
||||
|
||||
if params.WebHookContentType == "params" {
|
||||
webHookParams := []maps.Map{}
|
||||
for index, name := range params.WebHookParamNames {
|
||||
if index < len(params.WebHookParamValues) {
|
||||
webHookParams = append(webHookParams, maps.Map{
|
||||
"name": name,
|
||||
"value": params.WebHookParamValues[index],
|
||||
})
|
||||
}
|
||||
}
|
||||
options["params"] = webHookParams
|
||||
} else if params.WebHookContentType == "body" {
|
||||
options["body"] = params.WebHookBody
|
||||
}
|
||||
case "script":
|
||||
if params.ScriptType == "path" {
|
||||
params.Must.
|
||||
Field("scriptPath", params.ScriptPath).
|
||||
Require("请输入脚本路径")
|
||||
} else if params.ScriptType == "code" {
|
||||
params.Must.
|
||||
Field("scriptCode", params.ScriptCode).
|
||||
Require("请输入脚本代码")
|
||||
} else {
|
||||
params.Must.
|
||||
Field("scriptPath", params.ScriptPath).
|
||||
Require("请输入脚本路径")
|
||||
}
|
||||
|
||||
options["scriptType"] = params.ScriptType
|
||||
options["path"] = params.ScriptPath
|
||||
options["scriptLang"] = params.ScriptLang
|
||||
options["script"] = params.ScriptCode
|
||||
options["cwd"] = params.ScriptCwd
|
||||
|
||||
env := []maps.Map{}
|
||||
for index, envName := range params.ScriptEnvNames {
|
||||
if index < len(params.ScriptEnvValues) {
|
||||
env = append(env, maps.Map{
|
||||
"name": envName,
|
||||
"value": params.ScriptEnvValues[index],
|
||||
})
|
||||
}
|
||||
}
|
||||
options["env"] = env
|
||||
case "dingTalk":
|
||||
params.Must.
|
||||
Field("dingTalkWebHookURL", params.DingTalkWebHookURL).
|
||||
Require("请输入Hook地址").
|
||||
Match("^https:", "Hook地址必须以https://开头")
|
||||
|
||||
options["webHookURL"] = params.DingTalkWebHookURL
|
||||
case "qyWeixin":
|
||||
params.Must.
|
||||
Field("qyWeixinCorporateId", params.QyWeixinCorporateId).
|
||||
Require("请输入企业ID").
|
||||
Field("qyWeixinAgentId", params.QyWeixinAgentId).
|
||||
Require("请输入应用AgentId").
|
||||
Field("qyWeixinSecret", params.QyWeixinAppSecret).
|
||||
Require("请输入应用Secret")
|
||||
|
||||
options["corporateId"] = params.QyWeixinCorporateId
|
||||
options["agentId"] = params.QyWeixinAgentId
|
||||
options["appSecret"] = params.QyWeixinAppSecret
|
||||
options["textFormat"] = params.QyWeixinTextFormat
|
||||
case "qyWeixinRobot":
|
||||
params.Must.
|
||||
Field("qyWeixinRobotWebHookURL", params.QyWeixinRobotWebHookURL).
|
||||
Require("请输入WebHook地址").
|
||||
Match("^https:", "WebHook地址必须以https://开头")
|
||||
|
||||
options["webHookURL"] = params.QyWeixinRobotWebHookURL
|
||||
options["textFormat"] = params.QyWeixinRobotTextFormat
|
||||
case "aliyunSms":
|
||||
params.Must.
|
||||
Field("aliyunSmsSign", params.AliyunSmsSign).
|
||||
Require("请输入签名名称").
|
||||
Field("aliyunSmsTemplateCode", params.AliyunSmsTemplateCode).
|
||||
Require("请输入模板CODE").
|
||||
Field("aliyunSmsAccessKeyId", params.AliyunSmsAccessKeyId).
|
||||
Require("请输入AccessKey ID").
|
||||
Field("aliyunSmsAccessKeySecret", params.AliyunSmsAccessKeySecret).
|
||||
Require("请输入AccessKey Secret")
|
||||
|
||||
options["sign"] = params.AliyunSmsSign
|
||||
options["templateCode"] = params.AliyunSmsTemplateCode
|
||||
options["accessKeyId"] = params.AliyunSmsAccessKeyId
|
||||
options["accessKeySecret"] = params.AliyunSmsAccessKeySecret
|
||||
|
||||
variables := []maps.Map{}
|
||||
for index, name := range params.AliyunSmsTemplateVarNames {
|
||||
if index < len(params.AliyunSmsTemplateVarValues) {
|
||||
variables = append(variables, maps.Map{
|
||||
"name": name,
|
||||
"value": params.AliyunSmsTemplateVarValues[index],
|
||||
})
|
||||
}
|
||||
}
|
||||
options["variables"] = variables
|
||||
case "telegram":
|
||||
params.Must.
|
||||
Field("telegramToken", params.TelegramToken).
|
||||
Require("请输入机器人Token")
|
||||
options["token"] = params.TelegramToken
|
||||
default:
|
||||
this.Fail("错误的媒介类型")
|
||||
}
|
||||
|
||||
optionsJSON, err := json.Marshal(options)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().MessageMediaInstanceRPC().UpdateMessageMediaInstance(this.AdminContext(), &pb.UpdateMessageMediaInstanceRequest{
|
||||
MessageMediaInstanceId: params.InstanceId,
|
||||
Name: params.Name,
|
||||
MediaType: params.MediaType,
|
||||
ParamsJSON: optionsJSON,
|
||||
Description: params.Description,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
61
internal/web/actions/default/admins/recipients/logs/index.go
Normal file
61
internal/web/actions/default/admins/recipients/logs/index.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "log")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
countResp, err := this.RPC().MessageTaskLogRPC().CountMessageTaskLogs(this.AdminContext(), &pb.CountMessageTaskLogsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
page := this.NewPage(countResp.Count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
logsResp, err := this.RPC().MessageTaskLogRPC().ListMessageTaskLogs(this.AdminContext(), &pb.ListMessageTaskLogsRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
logMaps := []maps.Map{}
|
||||
for _, log := range logsResp.MessageTaskLogs {
|
||||
if log.MessageTask.MessageRecipient != nil {
|
||||
log.MessageTask.User = log.MessageTask.MessageRecipient.User
|
||||
}
|
||||
logMaps = append(logMaps, maps.Map{
|
||||
"task": maps.Map{
|
||||
"id": log.MessageTask.Id,
|
||||
"user": log.MessageTask.User,
|
||||
"subject": log.MessageTask.Subject,
|
||||
"body": log.MessageTask.Body,
|
||||
"instance": maps.Map{
|
||||
"id": log.MessageTask.MessageMediaInstance.Id,
|
||||
"name": log.MessageTask.MessageMediaInstance.Name,
|
||||
},
|
||||
},
|
||||
"isOk": log.IsOk,
|
||||
"error": log.Error,
|
||||
"response": log.Response,
|
||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt),
|
||||
})
|
||||
}
|
||||
this.Data["logs"] = logMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
19
internal/web/actions/default/admins/recipients/logs/init.go
Normal file
19
internal/web/actions/default/admins/recipients/logs/init.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeAdmin)).
|
||||
Data("teaMenu", "admins").
|
||||
Data("teaSubMenu", "recipients").
|
||||
Prefix("/admins/recipients/logs").
|
||||
Get("", new(IndexAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package recipients
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// 媒介类型选项
|
||||
type MediaOptionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *MediaOptionsAction) RunPost(params struct{}) {
|
||||
resp, err := this.RPC().MessageMediaRPC().FindAllMessageMedias(this.AdminContext(), &pb.FindAllMessageMediasRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
mediaMaps := []maps.Map{}
|
||||
for _, media := range resp.MessageMedias {
|
||||
mediaMaps = append(mediaMaps, maps.Map{
|
||||
"id": media.Id,
|
||||
"type": media.Type,
|
||||
"name": media.Name,
|
||||
"description": media.Description,
|
||||
})
|
||||
}
|
||||
this.Data["medias"] = mediaMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
50
internal/web/actions/default/admins/recipients/recipient.go
Normal file
50
internal/web/actions/default/admins/recipients/recipient.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package recipients
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type RecipientAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *RecipientAction) Init() {
|
||||
this.Nav("", "", "recipient")
|
||||
}
|
||||
|
||||
func (this *RecipientAction) RunGet(params struct {
|
||||
RecipientId int64
|
||||
}) {
|
||||
recipientResp, err := this.RPC().MessageRecipientRPC().FindEnabledMessageRecipient(this.AdminContext(), &pb.FindEnabledMessageRecipientRequest{MessageRecipientId: params.RecipientId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
recipient := recipientResp.MessageRecipient
|
||||
if recipient == nil || recipient.Admin == nil || recipient.MessageMediaInstance == nil {
|
||||
this.NotFound("messageRecipient", params.RecipientId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["recipient"] = maps.Map{
|
||||
"id": recipient.Id,
|
||||
"admin": maps.Map{
|
||||
"id": recipient.Admin.Id,
|
||||
"fullname": recipient.Admin.Fullname,
|
||||
"username": recipient.Admin.Username,
|
||||
},
|
||||
"groups": recipient.MessageRecipientGroups,
|
||||
"isOn": recipient.IsOn,
|
||||
"instance": maps.Map{
|
||||
"id": recipient.MessageMediaInstance.Id,
|
||||
"name": recipient.MessageMediaInstance.Name,
|
||||
"description": recipient.MessageMediaInstance.Description,
|
||||
},
|
||||
"user": recipient.User,
|
||||
"description": recipient.Description,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
19
internal/web/actions/default/admins/recipients/tasks/init.go
Normal file
19
internal/web/actions/default/admins/recipients/tasks/init.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package tasks
|
||||
|
||||
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.AdminModuleCodeAdmin)).
|
||||
Data("teaMenu", "admins").
|
||||
Data("teaSubMenu", "recipients").
|
||||
Prefix("/admins/recipients/tasks").
|
||||
Post("/taskInfo", new(TaskInfoAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type TaskInfoAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TaskInfoAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *TaskInfoAction) RunPost(params struct {
|
||||
TaskId int64
|
||||
}) {
|
||||
resp, err := this.RPC().MessageTaskRPC().FindEnabledMessageTask(this.AdminContext(), &pb.FindEnabledMessageTaskRequest{MessageTaskId: params.TaskId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if resp.MessageTask == nil {
|
||||
this.NotFound("messageTask", params.TaskId)
|
||||
return
|
||||
}
|
||||
|
||||
result := resp.MessageTask.Result
|
||||
this.Data["status"] = resp.MessageTask.Status
|
||||
this.Data["result"] = maps.Map{
|
||||
"isOk": result.IsOk,
|
||||
"response": result.Response,
|
||||
"error": result.Error,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
113
internal/web/actions/default/admins/recipients/test.go
Normal file
113
internal/web/actions/default/admins/recipients/test.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package recipients
|
||||
|
||||
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 TestAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TestAction) Init() {
|
||||
this.Nav("", "", "test")
|
||||
}
|
||||
|
||||
func (this *TestAction) RunGet(params struct {
|
||||
RecipientId int64
|
||||
}) {
|
||||
recipientResp, err := this.RPC().MessageRecipientRPC().FindEnabledMessageRecipient(this.AdminContext(), &pb.FindEnabledMessageRecipientRequest{MessageRecipientId: params.RecipientId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
recipient := recipientResp.MessageRecipient
|
||||
if recipient == nil || recipient.Admin == nil || recipient.MessageMediaInstance == nil {
|
||||
this.NotFound("messageRecipient", params.RecipientId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["recipient"] = maps.Map{
|
||||
"id": recipient.Id,
|
||||
"admin": maps.Map{
|
||||
"id": recipient.Admin.Id,
|
||||
"fullname": recipient.Admin.Fullname,
|
||||
"username": recipient.Admin.Username,
|
||||
},
|
||||
"instance": maps.Map{
|
||||
"id": recipient.MessageMediaInstance.Id,
|
||||
"name": recipient.MessageMediaInstance.Name,
|
||||
"description": recipient.MessageMediaInstance.Description,
|
||||
},
|
||||
"user": recipient.User,
|
||||
}
|
||||
|
||||
instanceResp, err := this.RPC().MessageMediaInstanceRPC().FindEnabledMessageMediaInstance(this.AdminContext(), &pb.FindEnabledMessageMediaInstanceRequest{MessageMediaInstanceId: recipient.MessageMediaInstance.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
instance := instanceResp.MessageMediaInstance
|
||||
if instance == nil || instance.MessageMedia == nil {
|
||||
this.NotFound("messageMediaInstance", recipient.MessageMediaInstance.Id)
|
||||
return
|
||||
}
|
||||
|
||||
mediaParams := maps.Map{}
|
||||
if len(instance.ParamsJSON) > 0 {
|
||||
err = json.Unmarshal(instance.ParamsJSON, &mediaParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["instance"] = maps.Map{
|
||||
"id": instance.Id,
|
||||
"isOn": instance.IsOn,
|
||||
"media": maps.Map{
|
||||
"type": instance.MessageMedia.Type,
|
||||
"name": instance.MessageMedia.Name,
|
||||
"userDescription": instance.MessageMedia.UserDescription,
|
||||
},
|
||||
"description": instance.Description,
|
||||
"params": mediaParams,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *TestAction) RunPost(params struct {
|
||||
InstanceId int64
|
||||
Subject string
|
||||
Body string
|
||||
User string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("instanceId", params.InstanceId).
|
||||
Gt(0, "请选择正确的媒介")
|
||||
|
||||
resp, err := this.RPC().MessageTaskRPC().CreateMessageTask(this.AdminContext(), &pb.CreateMessageTaskRequest{
|
||||
RecipientId: 0,
|
||||
InstanceId: params.InstanceId,
|
||||
User: params.User,
|
||||
Subject: params.Subject,
|
||||
Body: params.Body,
|
||||
IsPrimary: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["taskId"] = resp.MessageTaskId
|
||||
|
||||
defer this.CreateLogInfo("创建媒介测试任务 %d", resp.MessageTaskId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
92
internal/web/actions/default/admins/recipients/update.go
Normal file
92
internal/web/actions/default/admins/recipients/update.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package recipients
|
||||
|
||||
import (
|
||||
"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 UpdateAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateAction) Init() {
|
||||
this.Nav("", "", "update")
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunGet(params struct {
|
||||
RecipientId int64
|
||||
}) {
|
||||
recipientResp, err := this.RPC().MessageRecipientRPC().FindEnabledMessageRecipient(this.AdminContext(), &pb.FindEnabledMessageRecipientRequest{MessageRecipientId: params.RecipientId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
recipient := recipientResp.MessageRecipient
|
||||
if recipient == nil || recipient.Admin == nil || recipient.MessageMediaInstance == nil {
|
||||
this.NotFound("messageRecipient", params.RecipientId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["recipient"] = maps.Map{
|
||||
"id": recipient.Id,
|
||||
"admin": maps.Map{
|
||||
"id": recipient.Admin.Id,
|
||||
"fullname": recipient.Admin.Fullname,
|
||||
"username": recipient.Admin.Username,
|
||||
},
|
||||
"groups": recipient.MessageRecipientGroups,
|
||||
"isOn": recipient.IsOn,
|
||||
"instance": maps.Map{
|
||||
"id": recipient.MessageMediaInstance.Id,
|
||||
"name": recipient.MessageMediaInstance.Name,
|
||||
},
|
||||
"user": recipient.User,
|
||||
"description": recipient.Description,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
RecipientId int64
|
||||
|
||||
AdminId int64
|
||||
User string
|
||||
InstanceId int64
|
||||
|
||||
GroupIds string
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改媒介接收人 %d", params.RecipientId)
|
||||
|
||||
params.Must.
|
||||
Field("adminId", params.AdminId).
|
||||
Gt(0, "请选择系统用户").
|
||||
Field("instanceId", params.InstanceId).
|
||||
Gt(0, "请选择媒介")
|
||||
|
||||
groupIds := utils.SplitNumbers(params.GroupIds)
|
||||
|
||||
_, err := this.RPC().MessageRecipientRPC().UpdateMessageRecipient(this.AdminContext(), &pb.UpdateMessageRecipientRequest{
|
||||
MessageRecipientId: params.RecipientId,
|
||||
AdminId: params.AdminId,
|
||||
MessageMediaInstanceId: params.InstanceId,
|
||||
User: params.User,
|
||||
MessageRecipientGroupIds: groupIds,
|
||||
Description: params.Description,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -45,6 +45,7 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
"username": admin.Username,
|
||||
"isOn": admin.IsOn,
|
||||
"isSuper": admin.IsSuper,
|
||||
"canLogin": admin.CanLogin,
|
||||
"otpLoginIsOn": otpLoginIsOn,
|
||||
}
|
||||
|
||||
@@ -76,6 +77,7 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
ModuleCodes []string
|
||||
IsOn bool
|
||||
IsSuper bool
|
||||
CanLogin bool
|
||||
|
||||
// OTP
|
||||
OtpOn bool
|
||||
@@ -139,6 +141,7 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
ModulesJSON: modulesJSON,
|
||||
IsSuper: params.IsSuper,
|
||||
IsOn: params.IsOn,
|
||||
CanLogin: params.CanLogin,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -36,6 +36,15 @@ func (this *IndexAction) RunGet(params struct {
|
||||
this.Data["activeState"] = params.ActiveState
|
||||
this.Data["keyword"] = params.Keyword
|
||||
|
||||
countAllResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["countAll"] = countAllResp.Count
|
||||
|
||||
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
GroupId: params.GroupId,
|
||||
|
||||
@@ -36,6 +36,7 @@ func init() {
|
||||
Get("/node/logs", new(node.LogsAction)).
|
||||
Post("/node/start", new(node.StartAction)).
|
||||
Post("/node/stop", new(node.StopAction)).
|
||||
Post("/node/up", new(node.UpAction)).
|
||||
|
||||
// 分组相关
|
||||
Get("/groups", new(groups.IndexAction)).
|
||||
|
||||
28
internal/web/actions/default/clusters/cluster/node/up.go
Normal file
28
internal/web/actions/default/clusters/cluster/node/up.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
// 手动上线
|
||||
type UpAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo("手动上线节点 %d", params.NodeId)
|
||||
|
||||
_, err := this.RPC().NodeRPC().UpdateNodeUp(this.AdminContext(), &pb.UpdateNodeUpRequest{
|
||||
NodeId: params.NodeId,
|
||||
IsUp: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -43,6 +43,9 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
// http api
|
||||
HttpAPIURL string
|
||||
|
||||
// html
|
||||
HtmlContent string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
@@ -90,6 +93,13 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
actionParams = &firewallconfigs.FirewallActionHTTPAPIConfig{
|
||||
URL: params.HttpAPIURL,
|
||||
}
|
||||
case firewallconfigs.FirewallActionTypeHTML:
|
||||
params.Must.
|
||||
Field("htmlContent", params.HtmlContent).
|
||||
Require("请输入HTML内容")
|
||||
actionParams = &firewallconfigs.FirewallActionHTMLConfig{
|
||||
Content: params.HtmlContent,
|
||||
}
|
||||
default:
|
||||
this.Fail("选择的类型'" + params.Type + "'暂时不支持")
|
||||
}
|
||||
|
||||
@@ -72,6 +72,9 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
// http api
|
||||
HttpAPIURL string
|
||||
|
||||
// HTML内容
|
||||
HtmlContent string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
@@ -119,6 +122,13 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
actionParams = &firewallconfigs.FirewallActionHTTPAPIConfig{
|
||||
URL: params.HttpAPIURL,
|
||||
}
|
||||
case firewallconfigs.FirewallActionTypeHTML:
|
||||
params.Must.
|
||||
Field("htmlContent", params.HtmlContent).
|
||||
Require("请输入HTML内容")
|
||||
actionParams = &firewallconfigs.FirewallActionHTMLConfig{
|
||||
Content: params.HtmlContent,
|
||||
}
|
||||
default:
|
||||
this.Fail("选择的类型'" + params.Type + "'暂时不支持")
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package settings
|
||||
package health
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -9,16 +9,16 @@ import (
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type HealthAction struct {
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *HealthAction) Init() {
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("health")
|
||||
}
|
||||
|
||||
func (this *HealthAction) RunGet(params struct {
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
configResp, err := this.RPC().NodeClusterRPC().FindNodeClusterHealthCheckConfig(this.AdminContext(), &pb.FindNodeClusterHealthCheckConfigRequest{NodeClusterId: params.ClusterId})
|
||||
@@ -40,7 +40,7 @@ func (this *HealthAction) RunGet(params struct {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *HealthAction) RunPost(params struct {
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
HealthCheckJSON []byte
|
||||
Must *actions.Must
|
||||
@@ -1,4 +1,4 @@
|
||||
package settings
|
||||
package health
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
@@ -7,20 +7,19 @@ import (
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type HealthRunPopupAction struct {
|
||||
type RunPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *HealthRunPopupAction) Init() {
|
||||
func (this *RunPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *HealthRunPopupAction) RunGet(params struct{}) {
|
||||
|
||||
func (this *RunPopupAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *HealthRunPopupAction) RunPost(params struct {
|
||||
func (this *RunPopupAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
|
||||
Must *actions.Must
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/cache"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/dns"
|
||||
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/services"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/toa"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/waf"
|
||||
@@ -22,8 +24,8 @@ func init() {
|
||||
GetPost("", new(IndexAction)).
|
||||
|
||||
// 健康检查
|
||||
GetPost("/health", new(HealthAction)).
|
||||
GetPost("/healthRunPopup", new(HealthRunPopupAction)).
|
||||
GetPost("/health", new(health.IndexAction)).
|
||||
GetPost("/health/runPopup", new(health.RunPopupAction)).
|
||||
|
||||
// 缓存
|
||||
GetPost("/cache", new(cache.IndexAction)).
|
||||
@@ -35,6 +37,12 @@ func init() {
|
||||
Prefix("/clusters/cluster/settings/dns").
|
||||
GetPost("", new(dns.IndexAction)).
|
||||
|
||||
// 消息
|
||||
Prefix("/clusters/cluster/settings/message").
|
||||
GetPost("", new(message.IndexAction)).
|
||||
Get("/selectReceiverPopup", new(message.SelectReceiverPopupAction)).
|
||||
Post("/selectedReceivers", new(message.SelectedReceiversAction)).
|
||||
|
||||
// TOA
|
||||
Prefix("/clusters/cluster/settings/toa").
|
||||
GetPost("", new(toa.IndexAction)).
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package message
|
||||
|
||||
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 IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "setting", "")
|
||||
this.SecondMenu("message")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
ReceiversJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改集群 %d 消息接收人", params.ClusterId)
|
||||
|
||||
receiverMaps := []maps.Map{}
|
||||
if len(params.ReceiversJSON) > 0 {
|
||||
err := json.Unmarshal(params.ReceiversJSON, &receiverMaps)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
pbReceiverOptions := &pb.UpdateMessageReceiversRequest_RecipientOptions{}
|
||||
for _, receiverMap := range receiverMaps {
|
||||
recipientId := int64(0)
|
||||
groupId := int64(0)
|
||||
receiverType := receiverMap.GetString("type")
|
||||
switch receiverType {
|
||||
case "recipient":
|
||||
recipientId = receiverMap.GetInt64("id")
|
||||
case "group":
|
||||
groupId = receiverMap.GetInt64("id")
|
||||
default:
|
||||
continue
|
||||
}
|
||||
pbReceiverOptions.RecipientOptions = append(pbReceiverOptions.RecipientOptions, &pb.UpdateMessageReceiversRequest_RecipientOption{
|
||||
MessageRecipientId: recipientId,
|
||||
MessageRecipientGroupId: groupId,
|
||||
})
|
||||
}
|
||||
|
||||
_, err := this.RPC().MessageReceiverRPC().UpdateMessageReceivers(this.AdminContext(), &pb.UpdateMessageReceiversRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeId: 0,
|
||||
ServerId: 0,
|
||||
ParamsJSON: nil,
|
||||
RecipientOptions: map[string]*pb.UpdateMessageReceiversRequest_RecipientOptions{
|
||||
"*": pbReceiverOptions,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
"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/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type SelectReceiverPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SelectReceiverPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *SelectReceiverPopupAction) RunGet(params struct {
|
||||
RecipientIds string
|
||||
GroupIds string
|
||||
}) {
|
||||
recipientIds := utils.SplitNumbers(params.RecipientIds)
|
||||
groupIds := utils.SplitNumbers(params.GroupIds)
|
||||
|
||||
// 所有接收人
|
||||
recipientsResp, err := this.RPC().MessageRecipientRPC().ListEnabledMessageRecipients(this.AdminContext(), &pb.ListEnabledMessageRecipientsRequest{
|
||||
AdminId: 0,
|
||||
MediaType: "",
|
||||
MessageRecipientGroupId: 0,
|
||||
Keyword: "",
|
||||
Offset: 0,
|
||||
Size: 1000, // TODO 支持搜索
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
recipientMaps := []maps.Map{}
|
||||
for _, recipient := range recipientsResp.MessageRecipients {
|
||||
if !recipient.IsOn {
|
||||
continue
|
||||
}
|
||||
if lists.ContainsInt64(recipientIds, recipient.Id) {
|
||||
continue
|
||||
}
|
||||
recipientMaps = append(recipientMaps, maps.Map{
|
||||
"id": recipient.Id,
|
||||
"name": recipient.Admin.Fullname,
|
||||
"instanceName": recipient.MessageMediaInstance.Name,
|
||||
})
|
||||
}
|
||||
this.Data["recipients"] = recipientMaps
|
||||
|
||||
// 所有分组
|
||||
groupsResp, err := this.RPC().MessageRecipientGroupRPC().FindAllEnabledMessageRecipientGroups(this.AdminContext(), &pb.FindAllEnabledMessageRecipientGroupsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
groupMaps := []maps.Map{}
|
||||
for _, group := range groupsResp.MessageRecipientGroups {
|
||||
if !group.IsOn {
|
||||
continue
|
||||
}
|
||||
if lists.ContainsInt64(groupIds, group.Id) {
|
||||
continue
|
||||
}
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package message
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type SelectedReceiversAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SelectedReceiversAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *SelectedReceiversAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
ServerId int64
|
||||
}) {
|
||||
receiversResp, err := this.RPC().MessageReceiverRPC().FindAllMessageReceivers(this.AdminContext(), &pb.FindAllMessageReceiversRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeId: params.NodeId,
|
||||
ServerId: params.ServerId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
receiverMaps := []maps.Map{}
|
||||
for _, receiver := range receiversResp.MessageReceivers {
|
||||
id := int64(0)
|
||||
name := ""
|
||||
receiverType := ""
|
||||
subName := ""
|
||||
if receiver.MessageRecipient != nil {
|
||||
id = receiver.MessageRecipient.Id
|
||||
name = receiver.MessageRecipient.Admin.Fullname
|
||||
subName = receiver.MessageRecipient.MessageMediaInstance.Name
|
||||
receiverType = "recipient"
|
||||
} else if receiver.MessageRecipientGroup != nil {
|
||||
id = receiver.MessageRecipientGroup.Id
|
||||
name = receiver.MessageRecipientGroup.Name
|
||||
receiverType = "group"
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
receiverMaps = append(receiverMaps, maps.Map{
|
||||
"id": id,
|
||||
"name": name,
|
||||
"subName": subName,
|
||||
"type": receiverType,
|
||||
})
|
||||
}
|
||||
this.Data["receivers"] = receiverMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
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"
|
||||
@@ -86,22 +89,47 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedIt
|
||||
"isActive": selectedItem == "waf",
|
||||
"isOn": cluster.HttpFirewallPolicyId > 0,
|
||||
})
|
||||
items = append(items, maps.Map{
|
||||
"name": "WAF动作",
|
||||
"url": "/clusters/cluster/settings/firewall-actions?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "firewallAction",
|
||||
})
|
||||
items = append(items, maps.Map{
|
||||
"name": "健康检查",
|
||||
"url": "/clusters/cluster/settings/health?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "health",
|
||||
})
|
||||
|
||||
{
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
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": "DNS设置",
|
||||
"url": "/clusters/cluster/settings/dns?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "dns",
|
||||
"isOn": cluster.DnsDomainId > 0 || len(cluster.DnsName) > 0,
|
||||
})
|
||||
if teaconst.IsPlus {
|
||||
items = append(items, maps.Map{
|
||||
"name": "消息通知",
|
||||
"url": "/clusters/cluster/settings/message?clusterId=" + clusterId,
|
||||
"isActive": selectedItem == "message",
|
||||
})
|
||||
}
|
||||
|
||||
items = append(items, maps.Map{
|
||||
"name": "-",
|
||||
"url": "",
|
||||
"isActive": false,
|
||||
})
|
||||
|
||||
items = append(items, maps.Map{
|
||||
"name": "系统服务",
|
||||
"url": "/clusters/cluster/settings/services?clusterId=" + clusterId,
|
||||
@@ -114,3 +142,37 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, selectedIt
|
||||
})
|
||||
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
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type GrantAction struct {
|
||||
@@ -37,7 +38,7 @@ func (this *GrantAction) RunGet(params struct {
|
||||
"method": grant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grant.Method),
|
||||
"username": grant.Username,
|
||||
"password": grant.Password,
|
||||
"password": strings.Repeat("*", len(grant.Password)),
|
||||
"privateKey": grant.PrivateKey,
|
||||
"description": grant.Description,
|
||||
"su": grant.Su,
|
||||
|
||||
@@ -55,6 +55,10 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
ParamApiKey string
|
||||
ParamApiSecret string
|
||||
|
||||
// CloudFlare
|
||||
CloudFlareAPIKey string
|
||||
CloudFlareEmail string
|
||||
|
||||
// CustomHTTP
|
||||
ParamCustomHTTPURL string
|
||||
ParamCustomHTTPSecret string
|
||||
@@ -97,6 +101,14 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
|
||||
apiParams["apiKey"] = params.ParamApiKey
|
||||
apiParams["apiSecret"] = params.ParamApiSecret
|
||||
case "cloudFlare":
|
||||
params.Must.
|
||||
Field("cloudFlareAPIKey", params.CloudFlareAPIKey).
|
||||
Require("请输入API密钥").
|
||||
Field("cloudFlareEmail", params.CloudFlareEmail).
|
||||
Email("请输入正确格式的邮箱地址")
|
||||
apiParams["apiKey"] = params.CloudFlareAPIKey
|
||||
apiParams["email"] = params.CloudFlareEmail
|
||||
case "customHTTP":
|
||||
params.Must.
|
||||
Field("paramCustomHTTPURL", params.ParamCustomHTTPURL).
|
||||
|
||||
@@ -84,6 +84,10 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
ParamApiKey string
|
||||
ParamApiSecret string
|
||||
|
||||
// CloudFlare
|
||||
CloudFlareAPIKey string
|
||||
CloudFlareEmail string
|
||||
|
||||
// CustomHTTP
|
||||
ParamCustomHTTPURL string
|
||||
ParamCustomHTTPSecret string
|
||||
@@ -128,6 +132,14 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
|
||||
apiParams["apiKey"] = params.ParamApiKey
|
||||
apiParams["apiSecret"] = params.ParamApiSecret
|
||||
case "cloudFlare":
|
||||
params.Must.
|
||||
Field("cloudFlareAPIKey", params.CloudFlareAPIKey).
|
||||
Require("请输入API密钥").
|
||||
Field("cloudFlareEmail", params.CloudFlareEmail).
|
||||
Email("请输入正确格式的邮箱地址")
|
||||
apiParams["apiKey"] = params.CloudFlareAPIKey
|
||||
apiParams["email"] = params.CloudFlareEmail
|
||||
case "customHTTP":
|
||||
params.Must.
|
||||
Field("paramCustomHTTPURL", params.ParamCustomHTTPURL).
|
||||
|
||||
@@ -65,6 +65,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
} else {
|
||||
this.Data["version"] = teaconst.Version
|
||||
}
|
||||
this.Data["faviconFileId"] = config.FaviconFileId
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -16,30 +16,121 @@ func (this *IndexAction) Init() {
|
||||
this.SecondMenu("list")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
countResp, err := this.RPC().ACMETaskRPC().CountAllEnabledACMETasks(this.AdminContext(), &pb.CountAllEnabledACMETasksRequest{
|
||||
AdminId: this.AdminId(),
|
||||
UserId: 0,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
Type string
|
||||
Keyword string
|
||||
}) {
|
||||
this.Data["type"] = params.Type
|
||||
this.Data["keyword"] = params.Keyword
|
||||
|
||||
tasksResp, err := this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{
|
||||
AdminId: this.AdminId(),
|
||||
UserId: 0,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
countAll := int64(0)
|
||||
countAvailable := int64(0)
|
||||
countExpired := int64(0)
|
||||
count7Days := int64(0)
|
||||
count30Days := int64(0)
|
||||
|
||||
// 计算数量
|
||||
{
|
||||
// all
|
||||
resp, err := this.RPC().ACMETaskRPC().CountAllEnabledACMETasks(this.AdminContext(), &pb.CountAllEnabledACMETasksRequest{
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countAll = resp.Count
|
||||
|
||||
// available
|
||||
resp, err = this.RPC().ACMETaskRPC().CountAllEnabledACMETasks(this.AdminContext(), &pb.CountAllEnabledACMETasksRequest{
|
||||
IsAvailable: true,
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countAvailable = resp.Count
|
||||
|
||||
// expired
|
||||
resp, err = this.RPC().ACMETaskRPC().CountAllEnabledACMETasks(this.AdminContext(), &pb.CountAllEnabledACMETasksRequest{
|
||||
IsExpired: true,
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countExpired = resp.Count
|
||||
|
||||
// expire in 7 days
|
||||
resp, err = this.RPC().ACMETaskRPC().CountAllEnabledACMETasks(this.AdminContext(), &pb.CountAllEnabledACMETasksRequest{
|
||||
ExpiringDays: 7,
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count7Days = resp.Count
|
||||
|
||||
// expire in 30 days
|
||||
resp, err = this.RPC().ACMETaskRPC().CountAllEnabledACMETasks(this.AdminContext(), &pb.CountAllEnabledACMETasksRequest{
|
||||
ExpiringDays: 30,
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count30Days = resp.Count
|
||||
}
|
||||
|
||||
this.Data["countAll"] = countAll
|
||||
this.Data["countAvailable"] = countAvailable
|
||||
this.Data["countExpired"] = countExpired
|
||||
this.Data["count7Days"] = count7Days
|
||||
this.Data["count30Days"] = count30Days
|
||||
|
||||
// 分页
|
||||
var page *actionutils.Page
|
||||
var tasksResp *pb.ListEnabledACMETasksResponse
|
||||
var err error
|
||||
switch params.Type {
|
||||
case "":
|
||||
page = this.NewPage(countAll)
|
||||
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
})
|
||||
case "available":
|
||||
page = this.NewPage(countAvailable)
|
||||
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{IsAvailable: true, Offset: page.Offset, Size: page.Size, Keyword: params.Keyword})
|
||||
case "expired":
|
||||
page = this.NewPage(countExpired)
|
||||
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{IsExpired: true, Offset: page.Offset, Size: page.Size, Keyword: params.Keyword})
|
||||
case "7days":
|
||||
page = this.NewPage(count7Days)
|
||||
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{ExpiringDays: 7, Offset: page.Offset, Size: page.Size, Keyword: params.Keyword})
|
||||
case "30days":
|
||||
page = this.NewPage(count30Days)
|
||||
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{ExpiringDays: 30, Offset: page.Offset, Size: page.Size, Keyword: params.Keyword})
|
||||
default:
|
||||
page = this.NewPage(countAll)
|
||||
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{
|
||||
Keyword: params.Keyword,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
taskMaps := []maps.Map{}
|
||||
for _, task := range tasksResp.AcmeTasks {
|
||||
if task.AcmeUser == nil {
|
||||
|
||||
@@ -138,6 +138,8 @@ func (this *IndexAction) RunGet(params struct {
|
||||
page = this.NewPage(countAll)
|
||||
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||
Keyword: params.Keyword,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
@@ -28,7 +29,8 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
Type string
|
||||
|
||||
// file
|
||||
FileDir string
|
||||
FileDir string
|
||||
FileMemoryCapacityJSON []byte
|
||||
|
||||
CapacityJSON []byte
|
||||
MaxSizeJSON []byte
|
||||
@@ -50,8 +52,21 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
params.Must.
|
||||
Field("fileDir", params.FileDir).
|
||||
Require("请输入缓存目录")
|
||||
|
||||
memoryCapacity := &shared.SizeCapacity{}
|
||||
if len(params.FileMemoryCapacityJSON) > 0 {
|
||||
err := json.Unmarshal(params.FileMemoryCapacityJSON, memoryCapacity)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
options = &serverconfigs.HTTPFileCacheStorage{
|
||||
Dir: params.FileDir,
|
||||
MemoryPolicy: &serverconfigs.HTTPCachePolicy{
|
||||
Capacity: memoryCapacity,
|
||||
},
|
||||
}
|
||||
case serverconfigs.CachePolicyStorageMemory:
|
||||
options = &serverconfigs.HTTPMemoryCacheStorage{
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
@@ -52,7 +53,8 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
Type string
|
||||
|
||||
// file
|
||||
FileDir string
|
||||
FileDir string
|
||||
FileMemoryCapacityJSON []byte
|
||||
|
||||
CapacityJSON []byte
|
||||
MaxSizeJSON []byte
|
||||
@@ -74,8 +76,21 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
params.Must.
|
||||
Field("fileDir", params.FileDir).
|
||||
Require("请输入缓存目录")
|
||||
|
||||
memoryCapacity := &shared.SizeCapacity{}
|
||||
if len(params.FileMemoryCapacityJSON) > 0 {
|
||||
err := json.Unmarshal(params.FileMemoryCapacityJSON, memoryCapacity)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
options = &serverconfigs.HTTPFileCacheStorage{
|
||||
Dir: params.FileDir,
|
||||
MemoryPolicy: &serverconfigs.HTTPCachePolicy{
|
||||
Capacity: memoryCapacity,
|
||||
},
|
||||
}
|
||||
case serverconfigs.CachePolicyStorageMemory:
|
||||
options = &serverconfigs.HTTPMemoryCacheStorage{
|
||||
@@ -91,14 +106,14 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
}
|
||||
_, err = this.RPC().HTTPCachePolicyRPC().UpdateHTTPCachePolicy(this.AdminContext(), &pb.UpdateHTTPCachePolicyRequest{
|
||||
HttpCachePolicyId: params.CachePolicyId,
|
||||
IsOn: params.IsOn,
|
||||
Name: params.Name,
|
||||
Description: params.Description,
|
||||
CapacityJSON: params.CapacityJSON,
|
||||
MaxKeys: params.MaxKeys,
|
||||
MaxSizeJSON: params.MaxSizeJSON,
|
||||
Type: params.Type,
|
||||
OptionsJSON: optionsJSON,
|
||||
IsOn: params.IsOn,
|
||||
Name: params.Name,
|
||||
Description: params.Description,
|
||||
CapacityJSON: params.CapacityJSON,
|
||||
MaxKeys: params.MaxKeys,
|
||||
MaxSizeJSON: params.MaxSizeJSON,
|
||||
Type: params.Type,
|
||||
OptionsJSON: optionsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CreateAction struct {
|
||||
@@ -215,6 +216,22 @@ func (this *CreateAction) RunPost(params struct {
|
||||
if err != nil {
|
||||
this.Fail("域名解析失败:" + err.Error())
|
||||
}
|
||||
|
||||
// 检查域名是否已经存在
|
||||
allServerNames := serverconfigs.PlainServerNames(serverNames)
|
||||
if len(allServerNames) > 0 {
|
||||
dupResp, err := this.RPC().ServerRPC().CheckServerNameDuplicationInNodeCluster(this.AdminContext(), &pb.CheckServerNameDuplicationInNodeClusterRequest{
|
||||
ServerNames: allServerNames,
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(dupResp.DuplicatedServerNames) > 0 {
|
||||
this.Fail("域名 " + strings.Join(dupResp.DuplicatedServerNames, ", ") + " 已经被其他服务所占用,不能重复使用")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 源站地址
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -33,6 +34,9 @@ func (this *AddPopupAction) RunGet(params struct {
|
||||
serverType := serverTypeResp.Type
|
||||
this.Data["serverType"] = serverType
|
||||
|
||||
// 是否为HTTP
|
||||
this.Data["isHTTP"] = serverType == "httpProxy" || serverType == "httpWeb"
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -44,8 +48,15 @@ func (this *AddPopupAction) RunPost(params struct {
|
||||
Protocol string
|
||||
Addr string
|
||||
Name string
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
ConnTimeout int
|
||||
ReadTimeout int
|
||||
MaxConns int32
|
||||
MaxIdleConns int32
|
||||
IdleTimeout int
|
||||
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -61,6 +72,33 @@ func (this *AddPopupAction) RunPost(params struct {
|
||||
host := addr[:portIndex]
|
||||
port := addr[portIndex+1:]
|
||||
|
||||
connTimeoutJSON, err := (&shared.TimeDuration{
|
||||
Count: int64(params.ConnTimeout),
|
||||
Unit: shared.TimeDurationUnitSecond,
|
||||
}).AsJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
readTimeoutJSON, err := (&shared.TimeDuration{
|
||||
Count: int64(params.ReadTimeout),
|
||||
Unit: shared.TimeDurationUnitSecond,
|
||||
}).AsJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
idleTimeoutJSON, err := (&shared.TimeDuration{
|
||||
Count: int64(params.IdleTimeout),
|
||||
Unit: shared.TimeDurationUnitSecond,
|
||||
}).AsJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().OriginRPC().CreateOrigin(this.AdminContext(), &pb.CreateOriginRequest{
|
||||
Name: params.Name,
|
||||
Addr: &pb.NetworkAddress{
|
||||
@@ -68,9 +106,14 @@ func (this *AddPopupAction) RunPost(params struct {
|
||||
Host: host,
|
||||
PortRange: port,
|
||||
},
|
||||
Description: params.Description,
|
||||
Weight: params.Weight,
|
||||
IsOn: params.IsOn,
|
||||
Description: params.Description,
|
||||
Weight: params.Weight,
|
||||
IsOn: params.IsOn,
|
||||
ConnTimeoutJSON: connTimeoutJSON,
|
||||
ReadTimeoutJSON: readTimeoutJSON,
|
||||
IdleTimeoutJSON: idleTimeoutJSON,
|
||||
MaxConns: params.MaxConns,
|
||||
MaxIdleConns: params.MaxIdleConns,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -6,8 +6,10 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
@@ -39,6 +41,10 @@ func (this *UpdatePopupAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
this.Data["serverType"] = serverTypeResp.Type
|
||||
serverType := serverTypeResp.Type
|
||||
|
||||
// 是否为HTTP
|
||||
this.Data["isHTTP"] = serverType == "httpProxy" || serverType == "httpWeb"
|
||||
|
||||
// 源站信息
|
||||
originResp, err := this.RPC().OriginRPC().FindEnabledOriginConfig(this.AdminContext(), &pb.FindEnabledOriginConfigRequest{OriginId: params.OriginId})
|
||||
@@ -54,14 +60,34 @@ func (this *UpdatePopupAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
connTimeout := 0
|
||||
readTimeout := 0
|
||||
idleTimeout := 0
|
||||
if config.ConnTimeout != nil {
|
||||
connTimeout = types.Int(config.ConnTimeout.Count)
|
||||
}
|
||||
|
||||
if config.ReadTimeout != nil {
|
||||
readTimeout = types.Int(config.ReadTimeout.Count)
|
||||
}
|
||||
|
||||
if config.IdleTimeout != nil {
|
||||
idleTimeout = types.Int(config.IdleTimeout.Count)
|
||||
}
|
||||
|
||||
this.Data["origin"] = maps.Map{
|
||||
"id": config.Id,
|
||||
"protocol": config.Addr.Protocol,
|
||||
"addr": config.Addr.Host + ":" + config.Addr.PortRange,
|
||||
"weight": config.Weight,
|
||||
"name": config.Name,
|
||||
"description": config.Description,
|
||||
"isOn": config.IsOn,
|
||||
"id": config.Id,
|
||||
"protocol": config.Addr.Protocol,
|
||||
"addr": config.Addr.Host + ":" + config.Addr.PortRange,
|
||||
"weight": config.Weight,
|
||||
"name": config.Name,
|
||||
"description": config.Description,
|
||||
"isOn": config.IsOn,
|
||||
"connTimeout": connTimeout,
|
||||
"readTimeout": readTimeout,
|
||||
"idleTimeout": idleTimeout,
|
||||
"maxConns": config.MaxConns,
|
||||
"maxIdleConns": config.MaxIdleConns,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
@@ -76,8 +102,15 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
Addr string
|
||||
Weight int32
|
||||
Name string
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
ConnTimeout int
|
||||
ReadTimeout int
|
||||
MaxConns int32
|
||||
MaxIdleConns int32
|
||||
IdleTimeout int
|
||||
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -93,7 +126,34 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
host := addr[:portIndex]
|
||||
port := addr[portIndex+1:]
|
||||
|
||||
_, err := this.RPC().OriginRPC().UpdateOrigin(this.AdminContext(), &pb.UpdateOriginRequest{
|
||||
connTimeoutJSON, err := (&shared.TimeDuration{
|
||||
Count: int64(params.ConnTimeout),
|
||||
Unit: shared.TimeDurationUnitSecond,
|
||||
}).AsJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
readTimeoutJSON, err := (&shared.TimeDuration{
|
||||
Count: int64(params.ReadTimeout),
|
||||
Unit: shared.TimeDurationUnitSecond,
|
||||
}).AsJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
idleTimeoutJSON, err := (&shared.TimeDuration{
|
||||
Count: int64(params.IdleTimeout),
|
||||
Unit: shared.TimeDurationUnitSecond,
|
||||
}).AsJSON()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().OriginRPC().UpdateOrigin(this.AdminContext(), &pb.UpdateOriginRequest{
|
||||
OriginId: params.OriginId,
|
||||
Name: params.Name,
|
||||
Addr: &pb.NetworkAddress{
|
||||
@@ -101,9 +161,14 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
||||
Host: host,
|
||||
PortRange: port,
|
||||
},
|
||||
Description: params.Description,
|
||||
Weight: params.Weight,
|
||||
IsOn: params.IsOn,
|
||||
Description: params.Description,
|
||||
Weight: params.Weight,
|
||||
IsOn: params.IsOn,
|
||||
ConnTimeoutJSON: connTimeoutJSON,
|
||||
ReadTimeoutJSON: readTimeoutJSON,
|
||||
IdleTimeoutJSON: idleTimeoutJSON,
|
||||
MaxConns: params.MaxConns,
|
||||
MaxIdleConns: params.MaxIdleConns,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -24,9 +24,12 @@ func (this *CreatePopupAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
BeforeURL string
|
||||
AfterURL string
|
||||
Status int
|
||||
BeforeURL string
|
||||
AfterURL string
|
||||
MatchPrefix bool
|
||||
KeepRequestURI bool
|
||||
|
||||
Status int
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
@@ -69,10 +72,12 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
Gte(0, "请选择正确的跳转状态码")
|
||||
|
||||
this.Data["redirect"] = maps.Map{
|
||||
"status": params.Status,
|
||||
"beforeURL": params.BeforeURL,
|
||||
"afterURL": params.AfterURL,
|
||||
"isOn": true,
|
||||
"status": params.Status,
|
||||
"beforeURL": params.BeforeURL,
|
||||
"afterURL": params.AfterURL,
|
||||
"matchPrefix": params.MatchPrefix,
|
||||
"keepRequestURI": params.KeepRequestURI,
|
||||
"isOn": true,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
@@ -68,6 +69,33 @@ func (this *SettingAction) RunPost(params struct {
|
||||
this.Fail("配置校验失败:" + err.Error())
|
||||
}
|
||||
|
||||
if reverseProxyConfig.ConnTimeout == nil {
|
||||
reverseProxyConfig.ConnTimeout = &shared.TimeDuration{Count: 0, Unit: "second"}
|
||||
}
|
||||
connTimeoutJSON, err := json.Marshal(reverseProxyConfig.ConnTimeout)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if reverseProxyConfig.ReadTimeout == nil {
|
||||
reverseProxyConfig.ReadTimeout = &shared.TimeDuration{Count: 0, Unit: "second"}
|
||||
}
|
||||
readTimeoutJSON, err := json.Marshal(reverseProxyConfig.ReadTimeout)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if reverseProxyConfig.IdleTimeout == nil {
|
||||
reverseProxyConfig.IdleTimeout = &shared.TimeDuration{Count: 0, Unit: "second"}
|
||||
}
|
||||
idleTimeoutJSON, err := json.Marshal(reverseProxyConfig.IdleTimeout)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 设置是否启用
|
||||
_, err = this.RPC().ServerRPC().UpdateServerReverseProxy(this.AdminContext(), &pb.UpdateServerReverseProxyRequest{
|
||||
ServerId: params.ServerId,
|
||||
@@ -87,6 +115,11 @@ func (this *SettingAction) RunPost(params struct {
|
||||
StripPrefix: reverseProxyConfig.StripPrefix,
|
||||
AutoFlush: reverseProxyConfig.AutoFlush,
|
||||
AddHeaders: reverseProxyConfig.AddHeaders,
|
||||
ConnTimeoutJSON: connTimeoutJSON,
|
||||
ReadTimeoutJSON: readTimeoutJSON,
|
||||
IdleTimeoutJSON: idleTimeoutJSON,
|
||||
MaxConns: types.Int32(reverseProxyConfig.MaxConns),
|
||||
MaxIdleConns: types.Int32(reverseProxyConfig.MaxIdleConns),
|
||||
})
|
||||
|
||||
this.Success()
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 域名管理
|
||||
@@ -74,6 +75,34 @@ func (this *IndexAction) RunPost(params struct {
|
||||
this.Fail("域名解析失败:" + err.Error())
|
||||
}
|
||||
|
||||
serverResp, err := this.RPC().ServerRPC().FindEnabledUserServerBasic(this.AdminContext(), &pb.FindEnabledUserServerBasicRequest{ServerId: params.ServerId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if serverResp.Server == nil || serverResp.Server.NodeCluster == nil {
|
||||
this.NotFound("server", params.ServerId)
|
||||
return
|
||||
}
|
||||
clusterId := serverResp.Server.NodeCluster.Id
|
||||
|
||||
// 检查域名是否已经存在
|
||||
allServerNames := serverconfigs.PlainServerNames(serverNames)
|
||||
if len(allServerNames) > 0 {
|
||||
dupResp, err := this.RPC().ServerRPC().CheckServerNameDuplicationInNodeCluster(this.AdminContext(), &pb.CheckServerNameDuplicationInNodeClusterRequest{
|
||||
ServerNames: allServerNames,
|
||||
NodeClusterId: clusterId,
|
||||
ExcludeServerId: params.ServerId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(dupResp.DuplicatedServerNames) > 0 {
|
||||
this.Fail("域名 " + strings.Join(dupResp.DuplicatedServerNames, ", ") + " 已经被其他服务所占用,不能重复使用")
|
||||
}
|
||||
}
|
||||
|
||||
_, err = this.RPC().ServerRPC().UpdateServerNames(this.AdminContext(), &pb.UpdateServerNamesRequest{
|
||||
ServerId: params.ServerId,
|
||||
ServerNamesJSON: []byte(params.ServerNames),
|
||||
|
||||
@@ -75,7 +75,7 @@ func (this *ClientsAction) RunGet(params struct {
|
||||
"count": stat.Count,
|
||||
"system": maps.Map{
|
||||
"id": stat.ClientSystem.Id,
|
||||
"name": stat.ClientSystem.Name,
|
||||
"name": stat.ClientSystem.Name + " " + stat.Version,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -97,7 +97,7 @@ func (this *ClientsAction) RunGet(params struct {
|
||||
"count": stat.Count,
|
||||
"browser": maps.Map{
|
||||
"id": stat.ClientBrowser.Id,
|
||||
"name": stat.ClientBrowser.Name,
|
||||
"name": stat.ClientBrowser.Name + " " + stat.Version,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
70
internal/web/actions/default/settings/authority/index.go
Normal file
70
internal/web/actions/default/settings/authority/index.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
keyResp, err := this.RPC().AuthorityKeyRPC().ReadAuthorityKey(this.AdminContext(), &pb.ReadAuthorityKeyRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var keyMap maps.Map = nil
|
||||
teaconst.IsPlus = false
|
||||
if keyResp.AuthorityKey != nil {
|
||||
if len(keyResp.AuthorityKey.MacAddresses) == 0 {
|
||||
keyResp.AuthorityKey.MacAddresses = []string{}
|
||||
}
|
||||
|
||||
isActive := len(keyResp.AuthorityKey.DayTo) > 0 && keyResp.AuthorityKey.DayTo >= timeutil.Format("Y-m-d")
|
||||
if isActive {
|
||||
teaconst.IsPlus = true
|
||||
}
|
||||
|
||||
keyMap = maps.Map{
|
||||
"dayFrom": keyResp.AuthorityKey.DayFrom,
|
||||
"dayTo": keyResp.AuthorityKey.DayTo,
|
||||
"macAddresses": keyResp.AuthorityKey.MacAddresses,
|
||||
"hostname": keyResp.AuthorityKey.Hostname,
|
||||
"company": keyResp.AuthorityKey.Company,
|
||||
"isExpired": !isActive,
|
||||
"updatedTime": timeutil.FormatTime("Y-m-d H:i:s", keyResp.AuthorityKey.UpdatedAt),
|
||||
}
|
||||
}
|
||||
this.Data["key"] = keyMap
|
||||
|
||||
// 检查是否有认证节点,如果没有认证节点,则自动生成一个
|
||||
countResp, err := this.RPC().AuthorityNodeRPC().CountAllEnabledAuthorityNodes(this.AdminContext(), &pb.CountAllEnabledAuthorityNodesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if countResp.Count == 0 {
|
||||
_, err = this.RPC().AuthorityNodeRPC().CreateAuthorityNode(this.AdminContext(), &pb.CreateAuthorityNodeRequest{
|
||||
Name: "默认节点",
|
||||
Description: "系统自动生成的默认节点",
|
||||
IsOn: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
19
internal/web/actions/default/settings/authority/init.go
Normal file
19
internal/web/actions/default/settings/authority/init.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/settingutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)).
|
||||
Helper(settingutils.NewAdvancedHelper("authority")).
|
||||
Prefix("/settings/authority").
|
||||
Get("", new(IndexAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"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 {
|
||||
NodeId int64
|
||||
}) {
|
||||
// TODO 检查权限
|
||||
|
||||
_, err := this.RPC().AuthorityNodeRPC().DeleteAuthorityNode(this.AdminContext(), &pb.DeleteAuthorityNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "删除认证节点 %d", params.NodeId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type Helper struct {
|
||||
}
|
||||
|
||||
func NewHelper() *Helper {
|
||||
return &Helper{}
|
||||
}
|
||||
|
||||
func (this *Helper) BeforeAction(action *actions.ActionObject) {
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "node")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
countResp, err := this.RPC().AuthorityNodeRPC().CountAllEnabledAuthorityNodes(this.AdminContext(), &pb.CountAllEnabledAuthorityNodesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
nodeMaps := []maps.Map{}
|
||||
if count > 0 {
|
||||
nodesResp, err := this.RPC().AuthorityNodeRPC().ListEnabledAuthorityNodes(this.AdminContext(), &pb.ListEnabledAuthorityNodesRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, node := range nodesResp.Nodes {
|
||||
// 状态
|
||||
status := &nodeconfigs.NodeStatus{}
|
||||
if len(node.StatusJSON) > 0 {
|
||||
err = json.Unmarshal(node.StatusJSON, &status)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
continue
|
||||
}
|
||||
status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
|
||||
}
|
||||
|
||||
nodeMaps = append(nodeMaps, maps.Map{
|
||||
"id": node.Id,
|
||||
"isOn": node.IsOn,
|
||||
"name": node.Name,
|
||||
"status": maps.Map{
|
||||
"isActive": status.IsActive,
|
||||
"updatedAt": status.UpdatedAt,
|
||||
"hostname": status.Hostname,
|
||||
"cpuUsage": status.CPUUsage,
|
||||
"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
|
||||
"memUsage": status.MemoryUsage,
|
||||
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
|
||||
"buildVersion": status.BuildVersion,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/authority/nodes/node"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/settingutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)).
|
||||
Helper(NewHelper()).
|
||||
Helper(settingutils.NewAdvancedHelper("authority")).
|
||||
Prefix("/settings/authority/nodes").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/node/createPopup", new(node.CreatePopupAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "node", "create")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Name string
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入认证节点名称")
|
||||
|
||||
createResp, err := this.RPC().AuthorityNodeRPC().CreateAuthorityNode(this.AdminContext(), &pb.CreateAuthorityNodeRequest{
|
||||
Name: params.Name,
|
||||
Description: params.Description,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "创建认证节点 %d", createResp.NodeId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Helper struct {
|
||||
}
|
||||
|
||||
func NewHelper() *Helper {
|
||||
return &Helper{}
|
||||
}
|
||||
|
||||
func (this *Helper) BeforeAction(action *actions.ActionObject) (goNext bool) {
|
||||
if action.Request.Method != http.MethodGet {
|
||||
return true
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package node
|
||||
|
||||
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("", "", "index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
nodeResp, err := this.RPC().AuthorityNodeRPC().FindEnabledAuthorityNode(this.AdminContext(), &pb.FindEnabledAuthorityNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.Node
|
||||
if node == nil {
|
||||
this.NotFound("authorityNode", params.NodeId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"description": node.Description,
|
||||
"isOn": node.IsOn,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/settingutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)).
|
||||
Helper(settingutils.NewAdvancedHelper("authority")).
|
||||
Prefix("/settings/authority/nodes/node").
|
||||
|
||||
// 节点相关
|
||||
Helper(NewHelper()).
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
Get("/install", new(InstallAction)).
|
||||
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type InstallAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *InstallAction) Init() {
|
||||
this.Nav("", "", "install")
|
||||
}
|
||||
|
||||
func (this *InstallAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
// 认证节点信息
|
||||
nodeResp, err := this.RPC().AuthorityNodeRPC().FindEnabledAuthorityNode(this.AdminContext(), &pb.FindEnabledAuthorityNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.Node
|
||||
if node == nil {
|
||||
this.NotFound("authorityNode", params.NodeId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"uniqueId": node.UniqueId,
|
||||
"secret": node.Secret,
|
||||
}
|
||||
|
||||
// API节点列表
|
||||
apiNodesResp, err := this.RPC().APINodeRPC().FindAllEnabledAPINodes(this.AdminContext(), &pb.FindAllEnabledAPINodesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
apiNodes := apiNodesResp.Nodes
|
||||
apiEndpoints := []string{}
|
||||
for _, apiNode := range apiNodes {
|
||||
if !apiNode.IsOn {
|
||||
continue
|
||||
}
|
||||
apiEndpoints = append(apiEndpoints, apiNode.AccessAddrs...)
|
||||
}
|
||||
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"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 {
|
||||
NodeId int64
|
||||
}) {
|
||||
nodeResp, err := this.RPC().AuthorityNodeRPC().FindEnabledAuthorityNode(this.AdminContext(), &pb.FindEnabledAuthorityNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.Node
|
||||
if node == nil {
|
||||
this.WriteString("要操作的节点不存在")
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"description": node.Description,
|
||||
"isOn": node.IsOn,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
// 保存基础设置
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
Name string
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入认证节点名称")
|
||||
|
||||
_, err := this.RPC().AuthorityNodeRPC().UpdateAuthorityNode(this.AdminContext(), &pb.UpdateAuthorityNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
Name: params.Name,
|
||||
Description: params.Description,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "修改认证节点 %d", params.NodeId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -91,6 +91,7 @@ func (this *UploadPopupAction) RunPost(params struct {
|
||||
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 保存
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package monitornodes
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"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 {
|
||||
NodeId int64
|
||||
}) {
|
||||
// TODO 检查权限
|
||||
|
||||
_, err := this.RPC().MonitorNodeRPC().DeleteMonitorNode(this.AdminContext(), &pb.DeleteMonitorNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "删除监控节点 %d", params.NodeId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package monitornodes
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type Helper struct {
|
||||
}
|
||||
|
||||
func NewHelper() *Helper {
|
||||
return &Helper{}
|
||||
}
|
||||
|
||||
func (this *Helper) BeforeAction(action *actions.ActionObject) {
|
||||
}
|
||||
75
internal/web/actions/default/settings/monitor-nodes/index.go
Normal file
75
internal/web/actions/default/settings/monitor-nodes/index.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package monitornodes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "node", "index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
countResp, err := this.RPC().MonitorNodeRPC().CountAllEnabledMonitorNodes(this.AdminContext(), &pb.CountAllEnabledMonitorNodesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
count := countResp.Count
|
||||
page := this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
nodeMaps := []maps.Map{}
|
||||
if count > 0 {
|
||||
nodesResp, err := this.RPC().MonitorNodeRPC().ListEnabledMonitorNodes(this.AdminContext(), &pb.ListEnabledMonitorNodesRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, node := range nodesResp.Nodes {
|
||||
// 状态
|
||||
status := &nodeconfigs.NodeStatus{}
|
||||
if len(node.StatusJSON) > 0 {
|
||||
err = json.Unmarshal(node.StatusJSON, &status)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
continue
|
||||
}
|
||||
status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
|
||||
}
|
||||
|
||||
nodeMaps = append(nodeMaps, maps.Map{
|
||||
"id": node.Id,
|
||||
"isOn": node.IsOn,
|
||||
"name": node.Name,
|
||||
"status": maps.Map{
|
||||
"isActive": status.IsActive,
|
||||
"updatedAt": status.UpdatedAt,
|
||||
"hostname": status.Hostname,
|
||||
"cpuUsage": status.CPUUsage,
|
||||
"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
|
||||
"memUsage": status.MemoryUsage,
|
||||
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
|
||||
"buildVersion": status.BuildVersion,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
23
internal/web/actions/default/settings/monitor-nodes/init.go
Normal file
23
internal/web/actions/default/settings/monitor-nodes/init.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package monitornodes
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/monitor-nodes/node"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/settingutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)).
|
||||
Helper(NewHelper()).
|
||||
Helper(settingutils.NewAdvancedHelper("monitorNodes")).
|
||||
Prefix("/settings/monitorNodes").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/node/createPopup", new(node.CreatePopupAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "node", "create")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Name string
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入监控节点名称")
|
||||
|
||||
createResp, err := this.RPC().MonitorNodeRPC().CreateMonitorNode(this.AdminContext(), &pb.CreateMonitorNodeRequest{
|
||||
Name: params.Name,
|
||||
Description: params.Description,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "创建监控节点 %d", createResp.NodeId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Helper struct {
|
||||
}
|
||||
|
||||
func NewHelper() *Helper {
|
||||
return &Helper{}
|
||||
}
|
||||
|
||||
func (this *Helper) BeforeAction(action *actions.ActionObject) (goNext bool) {
|
||||
if action.Request.Method != http.MethodGet {
|
||||
return true
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package node
|
||||
|
||||
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("", "", "index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
nodeResp, err := this.RPC().MonitorNodeRPC().FindEnabledMonitorNode(this.AdminContext(), &pb.FindEnabledMonitorNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.Node
|
||||
if node == nil {
|
||||
this.NotFound("monitorNode", params.NodeId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"description": node.Description,
|
||||
"isOn": node.IsOn,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/settingutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)).
|
||||
Helper(settingutils.NewAdvancedHelper("monitorNodes")).
|
||||
Prefix("/settings/monitorNodes/node").
|
||||
|
||||
// 节点相关
|
||||
Helper(NewHelper()).
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
Get("/install", new(InstallAction)).
|
||||
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type InstallAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *InstallAction) Init() {
|
||||
this.Nav("", "", "install")
|
||||
}
|
||||
|
||||
func (this *InstallAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
}) {
|
||||
// 监控节点信息
|
||||
nodeResp, err := this.RPC().MonitorNodeRPC().FindEnabledMonitorNode(this.AdminContext(), &pb.FindEnabledMonitorNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.Node
|
||||
if node == nil {
|
||||
this.NotFound("monitorNode", params.NodeId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"uniqueId": node.UniqueId,
|
||||
"secret": node.Secret,
|
||||
}
|
||||
|
||||
// API节点列表
|
||||
apiNodesResp, err := this.RPC().APINodeRPC().FindAllEnabledAPINodes(this.AdminContext(), &pb.FindAllEnabledAPINodesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
apiNodes := apiNodesResp.Nodes
|
||||
apiEndpoints := []string{}
|
||||
for _, apiNode := range apiNodes {
|
||||
if !apiNode.IsOn {
|
||||
continue
|
||||
}
|
||||
apiEndpoints = append(apiEndpoints, apiNode.AccessAddrs...)
|
||||
}
|
||||
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"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 {
|
||||
NodeId int64
|
||||
}) {
|
||||
nodeResp, err := this.RPC().MonitorNodeRPC().FindEnabledMonitorNode(this.AdminContext(), &pb.FindEnabledMonitorNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.Node
|
||||
if node == nil {
|
||||
this.WriteString("要操作的节点不存在")
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"description": node.Description,
|
||||
"isOn": node.IsOn,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
// 保存基础设置
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
Name string
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入监控节点名称")
|
||||
|
||||
_, err := this.RPC().MonitorNodeRPC().UpdateMonitorNode(this.AdminContext(), &pb.UpdateMonitorNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
Name: params.Name,
|
||||
Description: params.Description,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "修改监控节点 %d", params.NodeId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
@@ -23,6 +24,9 @@ func (this *IndexAction) RunGet(params struct{}) {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if config.AllowIPs == nil {
|
||||
config.AllowIPs = []string{}
|
||||
}
|
||||
|
||||
// 国家和地区
|
||||
countryMaps := []maps.Map{}
|
||||
@@ -69,6 +73,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
CountryIdsJSON []byte
|
||||
ProvinceIdsJSON []byte
|
||||
AllowLocal bool
|
||||
AllowIPs []string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
@@ -106,6 +111,19 @@ func (this *IndexAction) RunPost(params struct {
|
||||
}
|
||||
config.AllowProvinceIds = provinceIds
|
||||
|
||||
// 允许的IP
|
||||
if len(params.AllowIPs) > 0 {
|
||||
for _, ip := range params.AllowIPs {
|
||||
_, err := shared.ParseIPRange(ip)
|
||||
if err != nil {
|
||||
this.Fail("允许访问的IP '" + ip + "' 格式错误:" + err.Error())
|
||||
}
|
||||
}
|
||||
config.AllowIPs = params.AllowIPs
|
||||
} else {
|
||||
config.AllowIPs = []string{}
|
||||
}
|
||||
|
||||
// 允许本地
|
||||
config.AllowLocal = params.AllowLocal
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package settingutils
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
@@ -34,6 +35,11 @@ func (this *AdvancedHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNex
|
||||
tabbar.Add("API节点", "", "/api", "", this.tab == "apiNodes")
|
||||
tabbar.Add("用户节点", "", "/settings/userNodes", "", this.tab == "userNodes")
|
||||
tabbar.Add("日志数据库", "", "/db", "", this.tab == "dbNodes")
|
||||
if teaconst.IsPlus {
|
||||
tabbar.Add("监控节点", "", "/settings/monitorNodes", "", this.tab == "monitorNodes")
|
||||
}
|
||||
tabbar.Add("企业版认证", "", "/settings/authority", "", this.tab == "authority")
|
||||
|
||||
//tabbar.Add("备份", "", "/settings/backup", "", this.tab == "backup")
|
||||
}
|
||||
actionutils.SetTabbar(actionPtr, tabbar)
|
||||
|
||||
@@ -3,7 +3,9 @@ package ui
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"io"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
@@ -32,10 +34,14 @@ func (this *IndexAction) RunPost(params struct {
|
||||
ShowFinance bool
|
||||
ShowVersion bool
|
||||
Version string
|
||||
FaviconFile *actions.File
|
||||
LogoFile *actions.File
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo("修改管理界面设置")
|
||||
|
||||
params.Must.
|
||||
Field("productName", params.ProductName).
|
||||
Require("请输入产品名称").
|
||||
@@ -53,6 +59,101 @@ func (this *IndexAction) RunPost(params struct {
|
||||
config.ShowFinance = params.ShowFinance
|
||||
config.ShowVersion = params.ShowVersion
|
||||
config.Version = params.Version
|
||||
|
||||
// 上传Favicon文件
|
||||
if params.FaviconFile != nil {
|
||||
createResp, err := this.RPC().FileRPC().CreateFile(this.AdminContext(), &pb.CreateFileRequest{
|
||||
Filename: params.FaviconFile.Filename,
|
||||
Size: params.FaviconFile.Size,
|
||||
IsPublic: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
fileId := createResp.FileId
|
||||
|
||||
// 上传内容
|
||||
buf := make([]byte, 512*1024)
|
||||
reader, err := params.FaviconFile.OriginFile.Open()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
n, err := reader.Read(buf)
|
||||
if n > 0 {
|
||||
_, err = this.RPC().FileChunkRPC().CreateFileChunk(this.AdminContext(), &pb.CreateFileChunkRequest{
|
||||
FileId: fileId,
|
||||
Data: buf[:n],
|
||||
})
|
||||
if err != nil {
|
||||
this.Fail("上传失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
this.Fail("上传失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// 置为已完成
|
||||
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
}
|
||||
config.FaviconFileId = fileId
|
||||
}
|
||||
|
||||
// 上传Logo文件
|
||||
if params.LogoFile != nil {
|
||||
createResp, err := this.RPC().FileRPC().CreateFile(this.AdminContext(), &pb.CreateFileRequest{
|
||||
Filename: params.LogoFile.Filename,
|
||||
Size: params.LogoFile.Size,
|
||||
IsPublic: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
fileId := createResp.FileId
|
||||
|
||||
// 上传内容
|
||||
buf := make([]byte, 512*1024)
|
||||
reader, err := params.LogoFile.OriginFile.Open()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
n, err := reader.Read(buf)
|
||||
if n > 0 {
|
||||
_, err = this.RPC().FileChunkRPC().CreateFileChunk(this.AdminContext(), &pb.CreateFileChunkRequest{
|
||||
FileId: fileId,
|
||||
Data: buf[:n],
|
||||
})
|
||||
if err != nil {
|
||||
this.Fail("上传失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
this.Fail("上传失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// 置为已完成
|
||||
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
}
|
||||
config.LogoFileId = fileId
|
||||
}
|
||||
|
||||
err = configloaders.UpdateAdminUIConfig(config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -3,7 +3,9 @@ package userui
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"io"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
@@ -32,6 +34,8 @@ func (this *IndexAction) RunPost(params struct {
|
||||
ShowVersion bool
|
||||
Version string
|
||||
ShowFinance bool
|
||||
FaviconFile *actions.File
|
||||
LogoFile *actions.File
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
@@ -53,6 +57,101 @@ func (this *IndexAction) RunPost(params struct {
|
||||
config.ShowVersion = params.ShowVersion
|
||||
config.Version = params.Version
|
||||
config.ShowFinance = params.ShowFinance
|
||||
|
||||
// 上传Favicon文件
|
||||
if params.FaviconFile != nil {
|
||||
createResp, err := this.RPC().FileRPC().CreateFile(this.AdminContext(), &pb.CreateFileRequest{
|
||||
Filename: params.FaviconFile.Filename,
|
||||
Size: params.FaviconFile.Size,
|
||||
IsPublic: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
fileId := createResp.FileId
|
||||
|
||||
// 上传内容
|
||||
buf := make([]byte, 512*1024)
|
||||
reader, err := params.FaviconFile.OriginFile.Open()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
n, err := reader.Read(buf)
|
||||
if n > 0 {
|
||||
_, err = this.RPC().FileChunkRPC().CreateFileChunk(this.AdminContext(), &pb.CreateFileChunkRequest{
|
||||
FileId: fileId,
|
||||
Data: buf[:n],
|
||||
})
|
||||
if err != nil {
|
||||
this.Fail("上传失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
this.Fail("上传失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// 置为已完成
|
||||
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
}
|
||||
config.FaviconFileId = fileId
|
||||
}
|
||||
|
||||
// 上传Logo文件
|
||||
if params.LogoFile != nil {
|
||||
createResp, err := this.RPC().FileRPC().CreateFile(this.AdminContext(), &pb.CreateFileRequest{
|
||||
Filename: params.LogoFile.Filename,
|
||||
Size: params.LogoFile.Size,
|
||||
IsPublic: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
fileId := createResp.FileId
|
||||
|
||||
// 上传内容
|
||||
buf := make([]byte, 512*1024)
|
||||
reader, err := params.LogoFile.OriginFile.Open()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
n, err := reader.Read(buf)
|
||||
if n > 0 {
|
||||
_, err = this.RPC().FileChunkRPC().CreateFileChunk(this.AdminContext(), &pb.CreateFileChunkRequest{
|
||||
FileId: fileId,
|
||||
Data: buf[:n],
|
||||
})
|
||||
if err != nil {
|
||||
this.Fail("上传失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
this.Fail("上传失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// 置为已完成
|
||||
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
}
|
||||
config.LogoFileId = fileId
|
||||
}
|
||||
|
||||
err = configloaders.UpdateUserUIConfig(config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user