Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffac080611 | ||
|
|
f7a1e60735 | ||
|
|
f22651821c | ||
|
|
b2a5a9ac9b | ||
|
|
245af2bd77 | ||
|
|
9dd2b1d35c | ||
|
|
bdbfd3e055 | ||
|
|
1518c03d2b | ||
|
|
45920d4df2 | ||
|
|
1c106ac6eb | ||
|
|
9f4a32b4ac | ||
|
|
2565b10491 | ||
|
|
34d632a401 | ||
|
|
a9df27c0e1 | ||
|
|
313011a168 | ||
|
|
5c595aad83 | ||
|
|
2c67eac63c | ||
|
|
d20c20cb33 | ||
|
|
fa76f032be | ||
|
|
3f74910640 | ||
|
|
22bd2a57e9 | ||
|
|
e45a1d0367 | ||
|
|
ee7acdc6a0 | ||
|
|
32264f2700 | ||
|
|
249ea32973 | ||
|
|
9c31b69a58 | ||
|
|
6e985cf6cc | ||
|
|
0f35b45704 | ||
|
|
ba9245e724 | ||
|
|
6e806f2822 | ||
|
|
7c6842a859 | ||
|
|
39f9fa0e6b | ||
|
|
0c8ae8960d | ||
|
|
ffd6a20829 | ||
|
|
2ee3e2782c | ||
|
|
61324c28c6 | ||
|
|
e9f70ecb90 | ||
|
|
cc3b802575 | ||
|
|
9b780ff4a3 | ||
|
|
deb1a33e78 | ||
|
|
5021350aa0 | ||
|
|
41b3dab135 | ||
|
|
ecf94170c8 | ||
|
|
56acdf3ce3 | ||
|
|
5d6d970d49 | ||
|
|
b501cf3c88 | ||
|
|
deac2baa18 | ||
|
|
b1e3f54055 | ||
|
|
8ebf79ffbe | ||
|
|
8d7307cddf | ||
|
|
c547837ae3 | ||
|
|
b408996e72 | ||
|
|
6b5866524d | ||
|
|
4994dfb488 | ||
|
|
5d5040651e | ||
|
|
5252188a68 | ||
|
|
3f664882d5 | ||
|
|
15f2a2d517 | ||
|
|
6637b0fb8f | ||
|
|
a06eeb9129 | ||
|
|
a24fce2c22 | ||
|
|
ddbdb64fc4 | ||
|
|
38c6d545ec | ||
|
|
fe880abbb0 | ||
|
|
081ed76c39 | ||
|
|
613a00686f | ||
|
|
11739ee671 | ||
|
|
d06951e3b5 | ||
|
|
63bbacd4d8 | ||
|
|
6ba130b62c | ||
|
|
5529d644ac | ||
|
|
7e5e6fb5b4 | ||
|
|
f5fb1911f7 | ||
|
|
e26e129a63 | ||
|
|
280cedad8d |
@@ -46,7 +46,7 @@
|
||||
* [开发者指南](https://goedge.cn/docs/Developer/Build.md)
|
||||
|
||||
## 架构
|
||||

|
||||

|
||||
|
||||
其中的组件源码地址如下:
|
||||
* [边缘节点](https://github.com/TeaOSLab/EdgeNode)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 72 KiB |
BIN
doc/architect-zh.png
Normal file
BIN
doc/architect-zh.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 MiB |
@@ -1,11 +1,15 @@
|
||||
FROM alpine:latest
|
||||
FROM --platform=linux/amd64 alpine:latest
|
||||
LABEL maintainer="goedge.cdn@gmail.com"
|
||||
ENV TZ "Asia/Shanghai"
|
||||
ENV VERSION 1.2.7
|
||||
ENV VERSION 1.2.11
|
||||
ENV ROOT_DIR /usr/local/goedge
|
||||
ENV TAR_FILE edge-admin-linux-amd64-plus-v${VERSION}.zip
|
||||
|
||||
# remote official repository
|
||||
ENV TAR_URL "https://dl.goedge.cn/edge/v${VERSION}/edge-admin-linux-amd64-plus-v${VERSION}.zip"
|
||||
#ENV TAR_URL "http://192.168.2.61:8080/edge-admin-linux-amd64-plus-v${VERSION}.zip" # your local repository
|
||||
|
||||
# your local repository
|
||||
#ENV TAR_URL "http://192.168.2.61:8080/edge-admin-linux-amd64-plus-v${VERSION}.zip"
|
||||
|
||||
RUN apk add --no-cache tzdata
|
||||
|
||||
|
||||
@@ -41,12 +41,17 @@ func LoadAPIConfig() (*APIConfig, error) {
|
||||
|
||||
var data []byte
|
||||
var err error
|
||||
var isFromOld = false
|
||||
for _, path := range paths {
|
||||
data, err = os.ReadFile(path)
|
||||
if err == nil {
|
||||
if path == realFile || path == oldRealFile {
|
||||
isFromLocal = true
|
||||
}
|
||||
|
||||
// 自动生成新的配置文件
|
||||
isFromOld = path == oldRealFile
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -70,6 +75,12 @@ func LoadAPIConfig() (*APIConfig, error) {
|
||||
_ = os.WriteFile(realFile, data, 0666)
|
||||
}
|
||||
|
||||
// 自动生成新配置文件
|
||||
if isFromOld {
|
||||
config.OldRPC.Endpoints = nil
|
||||
_ = config.WriteFile(Tea.ConfigFile(ConfigFileName))
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "1.2.7"
|
||||
Version = "1.2.11"
|
||||
|
||||
APINodeVersion = "1.2.7"
|
||||
APINodeVersion = "1.2.11"
|
||||
|
||||
ProductName = "Edge Admin"
|
||||
ProcessName = "edge-admin"
|
||||
|
||||
@@ -280,34 +280,6 @@ 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())
|
||||
}
|
||||
@@ -416,14 +388,6 @@ func (this *RPCClient) NodeTaskRPC() pb.NodeTaskServiceClient {
|
||||
return pb.NewNodeTaskServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) AuthorityKeyRPC() pb.AuthorityKeyServiceClient {
|
||||
return pb.NewAuthorityKeyServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) AuthorityNodeRPC() pb.AuthorityNodeServiceClient {
|
||||
return pb.NewAuthorityNodeServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) LatestItemRPC() pb.LatestItemServiceClient {
|
||||
return pb.NewLatestItemServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
95
internal/utils/unzip.go
Normal file
95
internal/utils/unzip.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Unzip struct {
|
||||
zipFile string
|
||||
targetDir string
|
||||
}
|
||||
|
||||
func NewUnzip(zipFile string, targetDir string) *Unzip {
|
||||
return &Unzip{
|
||||
zipFile: zipFile,
|
||||
targetDir: targetDir,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Unzip) Run() error {
|
||||
if len(this.zipFile) == 0 {
|
||||
return errors.New("zip file should not be empty")
|
||||
}
|
||||
if len(this.targetDir) == 0 {
|
||||
return errors.New("target dir should not be empty")
|
||||
}
|
||||
|
||||
reader, err := zip.OpenReader(this.zipFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = reader.Close()
|
||||
}()
|
||||
|
||||
for _, file := range reader.File {
|
||||
var info = file.FileInfo()
|
||||
var target = this.targetDir + "/" + file.Name
|
||||
|
||||
// 目录
|
||||
if info.IsDir() {
|
||||
stat, err := os.Stat(target)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
} else {
|
||||
err = os.MkdirAll(target, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if !stat.IsDir() {
|
||||
err = os.MkdirAll(target, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// 文件
|
||||
err = func(file *zip.File, target string) error {
|
||||
fileReader, err := file.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = fileReader.Close()
|
||||
}()
|
||||
|
||||
// remove old
|
||||
_ = os.Remove(target)
|
||||
|
||||
// create new
|
||||
fileWriter, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, file.FileInfo().Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = fileWriter.Close()
|
||||
}()
|
||||
|
||||
_, err = io.Copy(fileWriter, fileReader)
|
||||
return err
|
||||
}(file, target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -88,10 +88,6 @@ func (this *UpgradeManager) Start() error {
|
||||
|
||||
// 检查unzip
|
||||
unzipExe, _ := exec.LookPath("unzip")
|
||||
if len(unzipExe) == 0 {
|
||||
// TODO install unzip automatically or pack with a static 'unzip' file
|
||||
return errors.New("can not find 'unzip' command")
|
||||
}
|
||||
|
||||
// 检查cp
|
||||
cpExe, _ := exec.LookPath("cp")
|
||||
@@ -232,12 +228,24 @@ func (this *UpgradeManager) Start() error {
|
||||
return fmt.Errorf("remove old dir '%s' failed: %w", unzipDir, err)
|
||||
}
|
||||
}
|
||||
var unzipCmd = exec.Command(unzipExe, "-q", "-o", destFile, "-d", unzipDir)
|
||||
var unzipStderr = &bytes.Buffer{}
|
||||
unzipCmd.Stderr = unzipStderr
|
||||
err = unzipCmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unzip installation file failed: %w: %s", err, unzipStderr.String())
|
||||
|
||||
if len(unzipExe) > 0 {
|
||||
var unzipCmd = exec.Command(unzipExe, "-q", "-o", destFile, "-d", unzipDir)
|
||||
var unzipStderr = &bytes.Buffer{}
|
||||
unzipCmd.Stderr = unzipStderr
|
||||
err = unzipCmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unzip installation file failed: %w: %s", err, unzipStderr.String())
|
||||
}
|
||||
} else {
|
||||
var unzipCmd = &Unzip{
|
||||
zipFile: destFile,
|
||||
targetDir: unzipDir,
|
||||
}
|
||||
err = unzipCmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unzip installation file failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
installationFiles, err := filepath.Glob(unzipDir + "/edge-" + this.component + "/*")
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
package recipients
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
TimeFromHour string
|
||||
TimeFromMinute string
|
||||
TimeFromSecond string
|
||||
|
||||
TimeToHour string
|
||||
TimeToMinute string
|
||||
TimeToSecond 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)
|
||||
|
||||
var digitReg = regexp.MustCompile(`^\d+$`)
|
||||
|
||||
var timeFrom = ""
|
||||
if digitReg.MatchString(params.TimeFromHour) && digitReg.MatchString(params.TimeFromMinute) && digitReg.MatchString(params.TimeFromSecond) {
|
||||
timeFrom = params.TimeFromHour + ":" + params.TimeFromMinute + ":" + params.TimeFromSecond
|
||||
}
|
||||
|
||||
var timeTo = ""
|
||||
if digitReg.MatchString(params.TimeToHour) && digitReg.MatchString(params.TimeToMinute) && digitReg.MatchString(params.TimeToSecond) {
|
||||
timeTo = params.TimeToHour + ":" + params.TimeToMinute + ":" + params.TimeToSecond
|
||||
}
|
||||
|
||||
resp, err := this.RPC().MessageRecipientRPC().CreateMessageRecipient(this.AdminContext(), &pb.CreateMessageRecipientRequest{
|
||||
AdminId: params.AdminId,
|
||||
MessageMediaInstanceId: params.InstanceId,
|
||||
User: params.User,
|
||||
MessageRecipientGroupIds: groupIds,
|
||||
Description: params.Description,
|
||||
TimeFrom: timeFrom,
|
||||
TimeTo: timeTo,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
defer this.CreateLogInfo(codes.MessageRecipient_LogCreateMessageRecipient, resp.MessageRecipientId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package recipients
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
RecipientId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.MessageRecipient_LogDeleteMessageRecipient, params.RecipientId)
|
||||
|
||||
_, err := this.RPC().MessageRecipientRPC().DeleteMessageRecipient(this.AdminContext(), &pb.DeleteMessageRecipientRequest{MessageRecipientId: params.RecipientId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
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()
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
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()
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
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()
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
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()
|
||||
})
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
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()
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
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()
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
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,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
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()
|
||||
})
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/monitorconfigs"
|
||||
"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
|
||||
|
||||
RateMinutes int32
|
||||
RateCount int32
|
||||
|
||||
HashLife int32
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
var rateConfig = &monitorconfigs.RateConfig{
|
||||
Minutes: params.RateMinutes,
|
||||
Count: params.RateCount,
|
||||
}
|
||||
rateJSON, err := json.Marshal(rateConfig)
|
||||
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,
|
||||
RateJSON: rateJSON,
|
||||
HashLife: params.HashLife,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
defer this.CreateLogInfo(codes.MessageMediaInstance_LogCreateMessageMediaInstance, resp.MessageMediaInstanceId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
InstanceId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.MessageMediaInstance_LogDeleteMessageMediaInstance, params.InstanceId)
|
||||
|
||||
_, err := this.RPC().MessageMediaInstanceRPC().DeleteMessageMediaInstance(this.AdminContext(), &pb.DeleteMessageMediaInstanceRequest{MessageMediaInstanceId: params.InstanceId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
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,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
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()
|
||||
})
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/monitorconfigs"
|
||||
"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
|
||||
}
|
||||
}
|
||||
|
||||
// 频率
|
||||
var rateConfig = &monitorconfigs.RateConfig{}
|
||||
if len(instance.RateJSON) > 0 {
|
||||
err = json.Unmarshal(instance.RateJSON, rateConfig)
|
||||
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,
|
||||
"rate": rateConfig,
|
||||
"hashLife": instance.HashLife,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
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()
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"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(codes.MessageTask_LogCreateTestingMessageTask, resp.MessageTaskId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,317 +0,0 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/monitorconfigs"
|
||||
"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
|
||||
}
|
||||
}
|
||||
|
||||
var rateConfig = &monitorconfigs.RateConfig{}
|
||||
if len(instance.RateJSON) > 0 {
|
||||
err = json.Unmarshal(instance.RateJSON, rateConfig)
|
||||
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,
|
||||
"rate": rateConfig,
|
||||
"hashLife": instance.HashLife,
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
RateMinutes int32
|
||||
RateCount int32
|
||||
|
||||
HashLife int32
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.MessageMediaInstance_LogUpdateMessageMediaInstance, 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
|
||||
}
|
||||
|
||||
var rateConfig = &monitorconfigs.RateConfig{
|
||||
Minutes: params.RateMinutes,
|
||||
Count: params.RateCount,
|
||||
}
|
||||
rateJSON, err := json.Marshal(rateConfig)
|
||||
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,
|
||||
RateJSON: rateJSON,
|
||||
HashLife: params.HashLife,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
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()
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
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()
|
||||
})
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
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()
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
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,
|
||||
"timeFrom": recipient.TimeFrom,
|
||||
"timeTo": recipient.TimeTo,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
TaskId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.MessageTask_LogDeleteMessageTask, params.TaskId)
|
||||
|
||||
_, err := this.RPC().MessageTaskRPC().DeleteMessageTask(this.AdminContext(), &pb.DeleteMessageTaskRequest{MessageTaskId: params.TaskId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package tasks
|
||||
|
||||
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("", "", "task")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
Status int32
|
||||
}) {
|
||||
this.Data["status"] = params.Status
|
||||
if params.Status > 3 {
|
||||
params.Status = 0
|
||||
}
|
||||
|
||||
countWaitingResp, err := this.RPC().MessageTaskRPC().CountMessageTasksWithStatus(this.AdminContext(), &pb.CountMessageTasksWithStatusRequest{Status: pb.CountMessageTasksWithStatusRequest_MessageTaskStatusNone})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countWaiting = countWaitingResp.Count
|
||||
this.Data["countWaiting"] = countWaiting
|
||||
|
||||
countFailedResp, err := this.RPC().MessageTaskRPC().CountMessageTasksWithStatus(this.AdminContext(), &pb.CountMessageTasksWithStatusRequest{Status: pb.CountMessageTasksWithStatusRequest_MessageTaskStatusFailed})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countFailed = countFailedResp.Count
|
||||
this.Data["countFailed"] = countFailed
|
||||
|
||||
// 列表
|
||||
var total = int64(0)
|
||||
switch params.Status {
|
||||
case 0:
|
||||
total = countWaiting
|
||||
case 3:
|
||||
total = countFailed
|
||||
}
|
||||
page := this.NewPage(total)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
var taskMaps = []maps.Map{}
|
||||
tasksResp, err := this.RPC().MessageTaskRPC().ListMessageTasksWithStatus(this.AdminContext(), &pb.ListMessageTasksWithStatusRequest{
|
||||
Status: pb.ListMessageTasksWithStatusRequest_Status(params.Status),
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, task := range tasksResp.MessageTasks {
|
||||
var resultMap = maps.Map{}
|
||||
var result = task.Result
|
||||
if result != nil {
|
||||
resultMap = maps.Map{
|
||||
"isOk": result.IsOk,
|
||||
"error": result.Error,
|
||||
"response": result.Response,
|
||||
}
|
||||
}
|
||||
|
||||
//var recipients = []string{}
|
||||
var user = ""
|
||||
var instanceMap maps.Map
|
||||
if task.MessageRecipient != nil {
|
||||
user = task.MessageRecipient.User
|
||||
if task.MessageRecipient.MessageMediaInstance != nil {
|
||||
instanceMap = maps.Map{
|
||||
"id": task.MessageRecipient.MessageMediaInstance.Id,
|
||||
"name": task.MessageRecipient.MessageMediaInstance.Name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
taskMaps = append(taskMaps, maps.Map{
|
||||
"id": task.Id,
|
||||
"subject": task.Subject,
|
||||
"body": task.Body,
|
||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", task.CreatedAt),
|
||||
"result": resultMap,
|
||||
"status": task.Status,
|
||||
"user": user,
|
||||
"instance": instanceMap,
|
||||
})
|
||||
}
|
||||
this.Data["tasks"] = taskMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
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").
|
||||
Get("", new(IndexAction)).
|
||||
Post("/taskInfo", new(TaskInfoAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
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()
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package recipients
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"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(codes.MessageTask_LogCreateTestingMessageTask, resp.MessageTaskId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
package recipients
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
var timeFromHour = ""
|
||||
var timeFromMinute = ""
|
||||
var timeFromSecond = ""
|
||||
|
||||
if len(recipient.TimeFrom) > 0 {
|
||||
var pieces = strings.Split(recipient.TimeFrom, ":")
|
||||
timeFromHour = pieces[0]
|
||||
timeFromMinute = pieces[1]
|
||||
timeFromSecond = pieces[2]
|
||||
}
|
||||
|
||||
var timeToHour = ""
|
||||
var timeToMinute = ""
|
||||
var timeToSecond = ""
|
||||
if len(recipient.TimeTo) > 0 {
|
||||
var pieces = strings.Split(recipient.TimeTo, ":")
|
||||
timeToHour = pieces[0]
|
||||
timeToMinute = pieces[1]
|
||||
timeToSecond = pieces[2]
|
||||
}
|
||||
|
||||
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,
|
||||
"timeFromHour": timeFromHour,
|
||||
"timeFromMinute": timeFromMinute,
|
||||
"timeFromSecond": timeFromSecond,
|
||||
"timeToHour": timeToHour,
|
||||
"timeToMinute": timeToMinute,
|
||||
"timeToSecond": timeToSecond,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
RecipientId int64
|
||||
|
||||
AdminId int64
|
||||
User string
|
||||
InstanceId int64
|
||||
|
||||
GroupIds string
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
TimeFromHour string
|
||||
TimeFromMinute string
|
||||
TimeFromSecond string
|
||||
|
||||
TimeToHour string
|
||||
TimeToMinute string
|
||||
TimeToSecond string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.MessageRecipient_LogUpdateMessageRecipient, params.RecipientId)
|
||||
|
||||
params.Must.
|
||||
Field("adminId", params.AdminId).
|
||||
Gt(0, "请选择系统用户").
|
||||
Field("instanceId", params.InstanceId).
|
||||
Gt(0, "请选择媒介")
|
||||
|
||||
groupIds := utils.SplitNumbers(params.GroupIds)
|
||||
|
||||
var digitReg = regexp.MustCompile(`^\d+$`)
|
||||
|
||||
var timeFrom = ""
|
||||
if digitReg.MatchString(params.TimeFromHour) && digitReg.MatchString(params.TimeFromMinute) && digitReg.MatchString(params.TimeFromSecond) {
|
||||
timeFrom = params.TimeFromHour + ":" + params.TimeFromMinute + ":" + params.TimeFromSecond
|
||||
}
|
||||
|
||||
var timeTo = ""
|
||||
if digitReg.MatchString(params.TimeToHour) && digitReg.MatchString(params.TimeToMinute) && digitReg.MatchString(params.TimeToSecond) {
|
||||
timeTo = params.TimeToHour + ":" + params.TimeToMinute + ":" + params.TimeToSecond
|
||||
}
|
||||
|
||||
_, 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,
|
||||
TimeFrom: timeFrom,
|
||||
TimeTo: timeTo,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
@@ -35,6 +36,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
clusters = append(clusters, node.SecondaryNodeClusters...)
|
||||
var allDNSRouteMaps = map[int64][]maps.Map{} // domain id => routes
|
||||
var routeMaps = map[int64][]maps.Map{} // domain id => routes
|
||||
var domainIds = []int64{}
|
||||
for _, cluster := range clusters {
|
||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{
|
||||
NodeId: params.NodeId,
|
||||
@@ -49,6 +51,13 @@ func (this *IndexAction) RunGet(params struct {
|
||||
continue
|
||||
}
|
||||
var domainId = dnsInfo.DnsDomainId
|
||||
|
||||
// remove same domain
|
||||
if lists.ContainsInt64(domainIds, domainId) {
|
||||
continue
|
||||
}
|
||||
domainIds = append(domainIds, domainId)
|
||||
|
||||
var domainName = dnsInfo.DnsDomainName
|
||||
if len(dnsInfo.Routes) > 0 {
|
||||
for _, route := range dnsInfo.Routes {
|
||||
@@ -102,15 +111,23 @@ func (this *IndexAction) RunPost(params struct {
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeDNS_LogUpdateNodeDNS, params.NodeId)
|
||||
|
||||
dnsRouteCodes := []string{}
|
||||
var rawRouteCodes = []string{}
|
||||
if len(params.DnsRoutesJSON) > 0 {
|
||||
err := json.Unmarshal(params.DnsRoutesJSON, &dnsRouteCodes)
|
||||
err := json.Unmarshal(params.DnsRoutesJSON, &rawRouteCodes)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// remove duplications
|
||||
var dnsRouteCodes = []string{}
|
||||
for _, routeCode := range rawRouteCodes {
|
||||
if !lists.ContainsString(dnsRouteCodes, routeCode) {
|
||||
dnsRouteCodes = append(dnsRouteCodes, routeCode)
|
||||
}
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeRPC().UpdateNodeDNS(this.AdminContext(), &pb.UpdateNodeDNSRequest{
|
||||
NodeId: params.NodeId,
|
||||
IpAddr: "",
|
||||
|
||||
@@ -43,13 +43,19 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["config"] = config
|
||||
|
||||
var httpAllDomainMismatchActionCode = serverconfigs.DomainMismatchActionPage
|
||||
var httpAllDomainMismatchActionContentHTML string
|
||||
var httpAllDomainMismatchActionStatusCode = "404"
|
||||
if config.HTTPAll.DomainMismatchAction != nil && config.HTTPAll.DomainMismatchAction.Options != nil {
|
||||
httpAllDomainMismatchActionContentHTML = config.HTTPAll.DomainMismatchAction.Options.GetString("contentHTML")
|
||||
var statusCode = config.HTTPAll.DomainMismatchAction.Options.GetInt("statusCode")
|
||||
if statusCode > 0 {
|
||||
httpAllDomainMismatchActionStatusCode = types.String(statusCode)
|
||||
if config.HTTPAll.DomainMismatchAction != nil {
|
||||
httpAllDomainMismatchActionCode = config.HTTPAll.DomainMismatchAction.Code
|
||||
|
||||
if config.HTTPAll.DomainMismatchAction.Options != nil {
|
||||
// 即使是非 page 处理动作,也读取这些内容,以便于在切换到 page 时,可以顺利读取到先前的设置
|
||||
httpAllDomainMismatchActionContentHTML = config.HTTPAll.DomainMismatchAction.Options.GetString("contentHTML")
|
||||
var statusCode = config.HTTPAll.DomainMismatchAction.Options.GetInt("statusCode")
|
||||
if statusCode > 0 {
|
||||
httpAllDomainMismatchActionStatusCode = types.String(statusCode)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
httpAllDomainMismatchActionContentHTML = `<!DOCTYPE html>
|
||||
@@ -73,6 +79,7 @@ p { color: grey; }
|
||||
</html>`
|
||||
}
|
||||
|
||||
this.Data["httpAllDomainMismatchActionCode"] = httpAllDomainMismatchActionCode
|
||||
this.Data["httpAllDomainMismatchActionContentHTML"] = httpAllDomainMismatchActionContentHTML
|
||||
this.Data["httpAllDomainMismatchActionStatusCode"] = httpAllDomainMismatchActionStatusCode
|
||||
|
||||
@@ -83,6 +90,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
|
||||
HttpAllMatchDomainStrictly bool
|
||||
HttpAllDomainMismatchActionCode string
|
||||
HttpAllDomainMismatchActionContentHTML string
|
||||
HttpAllDomainMismatchActionStatusCode string
|
||||
HttpAllAllowMismatchDomainsJSON []byte
|
||||
@@ -90,11 +98,16 @@ func (this *IndexAction) RunPost(params struct {
|
||||
HttpAllDefaultDomain string
|
||||
HttpAllNodeIPPageHTML string
|
||||
HttpAllNodeIPShowPage bool
|
||||
HttpAllEnableServerAddrVariable bool
|
||||
|
||||
HttpAllServerName string
|
||||
HttpAllSupportsLowVersionHTTP bool
|
||||
HttpAllMatchCertFromAllServers bool
|
||||
HttpAllForceLnRequest bool
|
||||
HttpAllDomainAuditingIsOn bool
|
||||
HttpAllDomainAuditingPrompt string
|
||||
|
||||
HttpAllServerName string
|
||||
HttpAllSupportsLowVersionHTTP bool
|
||||
HttpAllMatchCertFromAllServers bool
|
||||
HttpAllForceLnRequest bool
|
||||
HttpAllLnRequestSchedulingMethod string
|
||||
|
||||
HttpAccessLogIsOn bool
|
||||
HttpAccessLogEnableRequestHeaders bool
|
||||
@@ -109,6 +122,11 @@ func (this *IndexAction) RunPost(params struct {
|
||||
PerformanceAutoWriteTimeout bool
|
||||
PerformanceDebug bool
|
||||
|
||||
// TCP端口设置
|
||||
TcpAllPortRangeMin int
|
||||
TcpAllPortRangeMax int
|
||||
TcpAllDenyPorts []int
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
@@ -139,7 +157,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
|
||||
config.HTTPAll.MatchDomainStrictly = params.HttpAllMatchDomainStrictly
|
||||
config.HTTPAll.DomainMismatchAction = &serverconfigs.DomainMismatchAction{
|
||||
Code: serverconfigs.DomainMismatchActionPage,
|
||||
Code: params.HttpAllDomainMismatchActionCode,
|
||||
Options: maps.Map{
|
||||
"statusCode": domainMisMatchStatusCode,
|
||||
"contentHTML": params.HttpAllDomainMismatchActionContentHTML,
|
||||
@@ -162,11 +180,16 @@ func (this *IndexAction) RunPost(params struct {
|
||||
config.HTTPAll.NodeIPShowPage = params.HttpAllNodeIPShowPage
|
||||
config.HTTPAll.NodeIPPageHTML = params.HttpAllNodeIPPageHTML
|
||||
|
||||
config.HTTPAll.DomainAuditingIsOn = params.HttpAllDomainAuditingIsOn
|
||||
config.HTTPAll.DomainAuditingPrompt = params.HttpAllDomainAuditingPrompt
|
||||
|
||||
// HTTP All
|
||||
config.HTTPAll.ServerName = params.HttpAllServerName
|
||||
config.HTTPAll.SupportsLowVersionHTTP = params.HttpAllSupportsLowVersionHTTP
|
||||
config.HTTPAll.MatchCertFromAllServers = params.HttpAllMatchCertFromAllServers
|
||||
config.HTTPAll.ForceLnRequest = params.HttpAllForceLnRequest
|
||||
config.HTTPAll.LnRequestSchedulingMethod = params.HttpAllLnRequestSchedulingMethod
|
||||
config.HTTPAll.EnableServerAddrVariable = params.HttpAllEnableServerAddrVariable
|
||||
|
||||
// 访问日志
|
||||
config.HTTPAccessLog.IsOn = params.HttpAccessLogIsOn
|
||||
@@ -179,6 +202,23 @@ func (this *IndexAction) RunPost(params struct {
|
||||
// 日志
|
||||
config.Log.RecordServerError = params.LogRecordServerError
|
||||
|
||||
// TCP
|
||||
if params.TcpAllPortRangeMin < 1024 {
|
||||
params.TcpAllPortRangeMin = 1024
|
||||
}
|
||||
if params.TcpAllPortRangeMax > 65534 {
|
||||
params.TcpAllPortRangeMax = 65534
|
||||
} else if params.TcpAllPortRangeMax < 1024 {
|
||||
params.TcpAllPortRangeMax = 1024
|
||||
}
|
||||
if params.TcpAllPortRangeMin > params.TcpAllPortRangeMax {
|
||||
params.TcpAllPortRangeMin, params.TcpAllPortRangeMax = params.TcpAllPortRangeMax, params.TcpAllPortRangeMin
|
||||
}
|
||||
|
||||
config.TCPAll.DenyPorts = params.TcpAllDenyPorts
|
||||
config.TCPAll.PortRangeMin = params.TcpAllPortRangeMin
|
||||
config.TCPAll.PortRangeMax = params.TcpAllPortRangeMax
|
||||
|
||||
// 性能
|
||||
config.Performance.AutoReadTimeout = params.PerformanceAutoReadTimeout
|
||||
config.Performance.AutoWriteTimeout = params.PerformanceAutoWriteTimeout
|
||||
|
||||
@@ -112,6 +112,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
"clock": clockConfig,
|
||||
"autoRemoteStart": cluster.AutoRemoteStart,
|
||||
"autoInstallNftables": cluster.AutoInstallNftables,
|
||||
"autoSystemTuning": cluster.AutoSystemTuning,
|
||||
"sshParams": sshParams,
|
||||
"domainName": fullDomainName,
|
||||
}
|
||||
@@ -139,6 +140,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
ClockCheckChrony bool
|
||||
AutoRemoteStart bool
|
||||
AutoInstallNftables bool
|
||||
AutoSystemTuning bool
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
@@ -193,6 +195,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
ClockJSON: clockConfigJSON,
|
||||
AutoRemoteStart: params.AutoRemoteStart,
|
||||
AutoInstallNftables: params.AutoInstallNftables,
|
||||
AutoSystemTuning: params.AutoSystemTuning,
|
||||
SshParamsJSON: sshParamsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -64,6 +64,7 @@ func (this *CreateAction) RunPost(params struct {
|
||||
InstallDir string
|
||||
SystemdServiceIsOn bool
|
||||
AutoInstallNftables bool
|
||||
AutoSystemTuning bool
|
||||
|
||||
// DNS相关
|
||||
DnsDomainId int64
|
||||
@@ -132,6 +133,7 @@ func (this *CreateAction) RunPost(params struct {
|
||||
SystemServicesJSON: systemServicesJSON,
|
||||
GlobalServerConfigJSON: globalServerConfigJSON,
|
||||
AutoInstallNftables: params.AutoInstallNftables,
|
||||
AutoSystemTuning: params.AutoSystemTuning,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CheckDiskPartitions 检查服务器磁盘空间
|
||||
@@ -47,6 +48,14 @@ func CheckDiskPartitions(thresholdPercent float64) (path string, usage uint64, u
|
||||
if p.Fstype != rootFS {
|
||||
continue
|
||||
}
|
||||
|
||||
// skip some specified partitions on macOS
|
||||
if runtime.GOOS == "darwin" {
|
||||
if strings.Contains(p.Mountpoint, "/Developer/") {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
stat, _ := disk.Usage(p.Mountpoint)
|
||||
if stat != nil {
|
||||
if stat.Used < 2*uint64(sizes.G) {
|
||||
|
||||
@@ -154,17 +154,6 @@ func (this *IndexAction) RunPost(params struct{}) {
|
||||
"version": "",
|
||||
}
|
||||
}
|
||||
if resp.MonitorNodeUpgradeInfo != nil {
|
||||
this.Data["monitorNodeUpgradeInfo"] = maps.Map{
|
||||
"count": resp.MonitorNodeUpgradeInfo.CountNodes,
|
||||
"version": resp.MonitorNodeUpgradeInfo.NewVersion,
|
||||
}
|
||||
} else {
|
||||
this.Data["monitorNodeUpgradeInfo"] = maps.Map{
|
||||
"count": 0,
|
||||
"version": "",
|
||||
}
|
||||
}
|
||||
if resp.ApiNodeUpgradeInfo != nil {
|
||||
this.Data["apiNodeUpgradeInfo"] = maps.Map{
|
||||
"count": resp.ApiNodeUpgradeInfo.CountNodes,
|
||||
@@ -176,39 +165,6 @@ func (this *IndexAction) RunPost(params struct{}) {
|
||||
"version": "",
|
||||
}
|
||||
}
|
||||
if resp.UserNodeUpgradeInfo != nil {
|
||||
this.Data["userNodeUpgradeInfo"] = maps.Map{
|
||||
"count": resp.UserNodeUpgradeInfo.CountNodes,
|
||||
"version": resp.UserNodeUpgradeInfo.NewVersion,
|
||||
}
|
||||
} else {
|
||||
this.Data["userNodeUpgradeInfo"] = maps.Map{
|
||||
"count": 0,
|
||||
"version": 0,
|
||||
}
|
||||
}
|
||||
if resp.AuthorityNodeUpgradeInfo != nil {
|
||||
this.Data["authorityNodeUpgradeInfo"] = maps.Map{
|
||||
"count": resp.AuthorityNodeUpgradeInfo.CountNodes,
|
||||
"version": resp.AuthorityNodeUpgradeInfo.NewVersion,
|
||||
}
|
||||
} else {
|
||||
this.Data["authorityNodeUpgradeInfo"] = maps.Map{
|
||||
"count": 0,
|
||||
"version": "",
|
||||
}
|
||||
}
|
||||
if resp.NsNodeUpgradeInfo != nil {
|
||||
this.Data["nsNodeUpgradeInfo"] = maps.Map{
|
||||
"count": resp.NsNodeUpgradeInfo.CountNodes,
|
||||
"version": resp.NsNodeUpgradeInfo.NewVersion,
|
||||
}
|
||||
} else {
|
||||
this.Data["nsNodeUpgradeInfo"] = maps.Map{
|
||||
"count": 0,
|
||||
"version": "",
|
||||
}
|
||||
}
|
||||
|
||||
// 域名排行
|
||||
{
|
||||
|
||||
@@ -3,11 +3,11 @@ package log
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"github.com/tealeg/xlsx/v3"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ExportExcelAction struct {
|
||||
@@ -65,23 +65,11 @@ func (this *ExportExcelAction) RunGet(params struct {
|
||||
for _, log := range logsResp.Logs {
|
||||
var regionName = ""
|
||||
var ispName = ""
|
||||
regionResp, err := this.RPC().IPLibraryRPC().LookupIPRegion(this.AdminContext(), &pb.LookupIPRegionRequest{Ip: log.Ip})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if regionResp.IpRegion != nil {
|
||||
regionName = regionResp.IpRegion.Summary
|
||||
|
||||
// remove isp from regionName
|
||||
var index = strings.LastIndex(regionName, "|")
|
||||
if index > 0 {
|
||||
regionName = regionName[:index]
|
||||
}
|
||||
|
||||
if len(regionResp.IpRegion.Isp) > 0 {
|
||||
ispName = regionResp.IpRegion.Isp
|
||||
}
|
||||
var ipRegion = iplibrary.LookupIP(log.Ip)
|
||||
if ipRegion != nil && ipRegion.IsOk() {
|
||||
regionName = ipRegion.RegionSummary()
|
||||
ispName = ipRegion.ProviderName()
|
||||
}
|
||||
|
||||
var row = sheet.AddRow()
|
||||
|
||||
@@ -3,6 +3,7 @@ package log
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
@@ -84,14 +85,10 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
var logMaps = []maps.Map{}
|
||||
for _, log := range logsResp.Logs {
|
||||
regionName := ""
|
||||
regionResp, err := this.RPC().IPLibraryRPC().LookupIPRegion(this.AdminContext(), &pb.LookupIPRegionRequest{Ip: log.Ip})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if regionResp.IpRegion != nil {
|
||||
regionName = regionResp.IpRegion.Summary
|
||||
var regionName = ""
|
||||
var ipRegion = iplibrary.LookupIP(log.Ip)
|
||||
if ipRegion != nil && ipRegion.IsOk() {
|
||||
regionName = ipRegion.Summary()
|
||||
}
|
||||
|
||||
logMaps = append(logMaps, maps.Map{
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -43,6 +44,14 @@ func (this *AddServerNamePopupAction) RunPost(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
// 去除端口
|
||||
if regexp.MustCompile(`:\d+$`).MatchString(serverName) {
|
||||
host, _, err := net.SplitHostPort(serverName)
|
||||
if err == nil && len(host) > 0 {
|
||||
serverName = host
|
||||
}
|
||||
}
|
||||
|
||||
params.Must.
|
||||
Field("serverName", serverName).
|
||||
Require("请输入域名")
|
||||
@@ -72,6 +81,14 @@ func (this *AddServerNamePopupAction) RunPost(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
// 去除端口
|
||||
if regexp.MustCompile(`:\d+$`).MatchString(serverName) {
|
||||
host, _, err := net.SplitHostPort(serverName)
|
||||
if err == nil && len(host) > 0 {
|
||||
serverName = host
|
||||
}
|
||||
}
|
||||
|
||||
// 转成小写
|
||||
serverName = strings.ToLower(serverName)
|
||||
|
||||
|
||||
@@ -17,12 +17,16 @@ func (this *IndexAction) Init() {
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
UserId int64
|
||||
Type string
|
||||
Keyword string
|
||||
UserId int64
|
||||
Type string
|
||||
Keyword string
|
||||
UserType string
|
||||
}) {
|
||||
this.Data["type"] = params.Type
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["userType"] = params.UserType
|
||||
|
||||
var userOnly = params.UserId > 0 || params.UserType == "user"
|
||||
|
||||
// 当前用户
|
||||
this.Data["searchingUserId"] = params.UserId
|
||||
@@ -58,8 +62,9 @@ func (this *IndexAction) RunGet(params struct {
|
||||
{
|
||||
// all
|
||||
resp, err := this.RPC().ACMETaskRPC().CountAllEnabledACMETasks(this.AdminContext(), &pb.CountAllEnabledACMETasksRequest{
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -72,6 +77,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
UserId: params.UserId,
|
||||
IsAvailable: true,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -84,6 +90,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
UserId: params.UserId,
|
||||
IsExpired: true,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -96,6 +103,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
UserId: params.UserId,
|
||||
ExpiringDays: 7,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -108,6 +116,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
UserId: params.UserId,
|
||||
ExpiringDays: 30,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -130,10 +139,11 @@ func (this *IndexAction) RunGet(params struct {
|
||||
case "":
|
||||
page = this.NewPage(countAll)
|
||||
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{
|
||||
UserId: params.UserId,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserId: params.UserId,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "available":
|
||||
page = this.NewPage(countAvailable)
|
||||
@@ -143,6 +153,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "expired":
|
||||
page = this.NewPage(countExpired)
|
||||
@@ -152,6 +163,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "7days":
|
||||
page = this.NewPage(count7Days)
|
||||
@@ -161,6 +173,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "30days":
|
||||
page = this.NewPage(count30Days)
|
||||
@@ -170,14 +183,16 @@ func (this *IndexAction) RunGet(params struct {
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
default:
|
||||
page = this.NewPage(countAll)
|
||||
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
@@ -242,6 +257,23 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
// user
|
||||
userResp, err := this.RPC().ACMETaskRPC().FindACMETaskUser(this.AdminContext(), &pb.FindACMETaskUserRequest{AcmeTaskId: task.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var taskUserMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
if userResp.User != nil {
|
||||
taskUserMap = maps.Map{
|
||||
"id": userResp.User.Id,
|
||||
"username": userResp.User.Username,
|
||||
"fullname": userResp.User.Fullname,
|
||||
}
|
||||
}
|
||||
|
||||
taskMaps = append(taskMaps, maps.Map{
|
||||
"id": task.Id,
|
||||
"authType": task.AuthType,
|
||||
@@ -257,6 +289,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
"autoRenew": task.AutoRenew,
|
||||
"cert": certMap,
|
||||
"log": logMap,
|
||||
"user": taskUserMap,
|
||||
})
|
||||
}
|
||||
this.Data["tasks"] = taskMaps
|
||||
|
||||
@@ -19,13 +19,19 @@ func (this *IndexAction) Init() {
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
UserId int64
|
||||
Type string
|
||||
Keyword string
|
||||
UserId int64
|
||||
Type string // [empty] | ca | 7days | ...
|
||||
Keyword string
|
||||
UserType string
|
||||
}) {
|
||||
this.Data["type"] = params.Type
|
||||
this.Data["keyword"] = params.Keyword
|
||||
|
||||
if params.UserId > 0 {
|
||||
params.UserType = "user"
|
||||
}
|
||||
this.Data["userType"] = params.UserType
|
||||
|
||||
// 当前用户
|
||||
this.Data["searchingUserId"] = params.UserId
|
||||
var userMap = maps.Map{
|
||||
@@ -57,12 +63,15 @@ func (this *IndexAction) RunGet(params struct {
|
||||
var count7Days int64
|
||||
var count30Days int64
|
||||
|
||||
var userOnly = params.UserType == "user" || params.UserId > 0
|
||||
|
||||
// 计算数量
|
||||
{
|
||||
// all
|
||||
resp, err := this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -72,9 +81,10 @@ func (this *IndexAction) RunGet(params struct {
|
||||
|
||||
// CA
|
||||
resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
|
||||
UserId: params.UserId,
|
||||
IsCA: true,
|
||||
Keyword: params.Keyword,
|
||||
UserId: params.UserId,
|
||||
IsCA: true,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -87,6 +97,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
UserId: params.UserId,
|
||||
IsAvailable: true,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -99,6 +110,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
UserId: params.UserId,
|
||||
IsExpired: true,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -111,6 +123,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
UserId: params.UserId,
|
||||
ExpiringDays: 7,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -123,6 +136,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
UserId: params.UserId,
|
||||
ExpiringDays: 30,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -146,19 +160,21 @@ func (this *IndexAction) RunGet(params struct {
|
||||
case "":
|
||||
page = this.NewPage(countAll)
|
||||
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||
UserId: params.UserId,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserId: params.UserId,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "ca":
|
||||
page = this.NewPage(countCA)
|
||||
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||
UserId: params.UserId,
|
||||
IsCA: true,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserId: params.UserId,
|
||||
IsCA: true,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "available":
|
||||
page = this.NewPage(countAvailable)
|
||||
@@ -168,6 +184,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "expired":
|
||||
page = this.NewPage(countExpired)
|
||||
@@ -177,6 +194,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
case "7days":
|
||||
page = this.NewPage(count7Days)
|
||||
@@ -195,14 +213,16 @@ func (this *IndexAction) RunGet(params struct {
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
})
|
||||
default:
|
||||
page = this.NewPage(countAll)
|
||||
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
UserId: params.UserId,
|
||||
Keyword: params.Keyword,
|
||||
UserOnly: userOnly,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
@@ -221,6 +241,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
var certMaps = []maps.Map{}
|
||||
var nowTime = time.Now().Unix()
|
||||
for _, certConfig := range certConfigs {
|
||||
// count servers
|
||||
countServersResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledServersWithSSLCertIdRequest{
|
||||
SslCertId: certConfig.Id,
|
||||
})
|
||||
@@ -229,6 +250,23 @@ func (this *IndexAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
// user
|
||||
userResp, err := this.RPC().SSLCertRPC().FindSSLCertUser(this.AdminContext(), &pb.FindSSLCertUserRequest{SslCertId: certConfig.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var certUserMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
if userResp.User != nil {
|
||||
certUserMap = maps.Map{
|
||||
"id": userResp.User.Id,
|
||||
"username": userResp.User.Username,
|
||||
"fullname": userResp.User.Fullname,
|
||||
}
|
||||
}
|
||||
|
||||
certMaps = append(certMaps, maps.Map{
|
||||
"isOn": certConfig.IsOn,
|
||||
"beginDay": timeutil.FormatTime("Y-m-d", certConfig.TimeBeginAt),
|
||||
@@ -236,6 +274,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
"isExpired": nowTime > certConfig.TimeEndAt,
|
||||
"isAvailable": nowTime <= certConfig.TimeEndAt,
|
||||
"countServers": countServersResp.Count,
|
||||
"user": certUserMap,
|
||||
})
|
||||
}
|
||||
this.Data["certInfos"] = certMaps
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package components
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type Helper struct {
|
||||
}
|
||||
|
||||
func NewHelper() *Helper {
|
||||
return &Helper{}
|
||||
}
|
||||
|
||||
func (this *Helper) BeforeAction(action *actions.ActionObject) {
|
||||
action.Data["teaMenu"] = "servers"
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
package components
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
const (
|
||||
SettingCodeServerGlobalConfig = "serverGlobalConfig"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "component", "index")
|
||||
this.SecondMenu("global")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
valueJSONResp, err := this.RPC().SysSettingRPC().ReadSysSetting(this.AdminContext(), &pb.ReadSysSettingRequest{Code: SettingCodeServerGlobalConfig})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
valueJSON := valueJSONResp.ValueJSON
|
||||
globalConfig := &serverconfigs.GlobalConfig{}
|
||||
|
||||
// 默认值
|
||||
globalConfig.HTTPAll.DomainAuditingIsOn = false
|
||||
|
||||
if len(valueJSON) > 0 {
|
||||
err = json.Unmarshal(valueJSON, globalConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Data["globalConfig"] = globalConfig
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
GlobalConfigJSON []byte
|
||||
Must *actions.Must
|
||||
|
||||
// 不匹配域名相关
|
||||
AllowMismatchDomains []string
|
||||
DomainMismatchAction string
|
||||
DomainMismatchActionPageStatusCode int
|
||||
DomainMismatchActionPageContentHTML string
|
||||
|
||||
// TCP端口设置
|
||||
TcpAllPortRangeMin int
|
||||
TcpAllPortRangeMax int
|
||||
TcpAllDenyPorts []int
|
||||
|
||||
DefaultDomain string
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.Server_LogUpdateGlobalSettings)
|
||||
|
||||
if len(params.GlobalConfigJSON) == 0 {
|
||||
this.Fail("错误的配置信息,请刷新当前页面后重试")
|
||||
}
|
||||
|
||||
globalConfig := &serverconfigs.GlobalConfig{}
|
||||
err := json.Unmarshal(params.GlobalConfigJSON, globalConfig)
|
||||
if err != nil {
|
||||
this.Fail("配置校验失败:" + err.Error())
|
||||
}
|
||||
|
||||
// TCP端口范围
|
||||
if params.TcpAllPortRangeMin < 1024 {
|
||||
params.TcpAllPortRangeMin = 1024
|
||||
}
|
||||
if params.TcpAllPortRangeMax > 65534 {
|
||||
params.TcpAllPortRangeMax = 65534
|
||||
} else if params.TcpAllPortRangeMax < 1024 {
|
||||
params.TcpAllPortRangeMax = 1024
|
||||
}
|
||||
if params.TcpAllPortRangeMin > params.TcpAllPortRangeMax {
|
||||
params.TcpAllPortRangeMin, params.TcpAllPortRangeMax = params.TcpAllPortRangeMax, params.TcpAllPortRangeMin
|
||||
}
|
||||
globalConfig.TCPAll.DenyPorts = params.TcpAllDenyPorts
|
||||
globalConfig.TCPAll.PortRangeMin = params.TcpAllPortRangeMin
|
||||
globalConfig.TCPAll.PortRangeMax = params.TcpAllPortRangeMax
|
||||
|
||||
// 修改配置
|
||||
globalConfigJSON, err := json.Marshal(globalConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
_, err = this.RPC().SysSettingRPC().UpdateSysSetting(this.AdminContext(), &pb.UpdateSysSettingRequest{
|
||||
Code: SettingCodeServerGlobalConfig,
|
||||
ValueJSON: globalConfigJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 通知更新
|
||||
_, err = this.RPC().ServerRPC().NotifyServersChange(this.AdminContext(), &pb.NotifyServersChangeRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package components
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
|
||||
Data("teaMenu", "servers").
|
||||
Data("teaSubMenu", "global").
|
||||
Helper(NewHelper()).
|
||||
Prefix("/servers/components").
|
||||
GetPost("", new(IndexAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -71,7 +71,13 @@ func (this *CreateRulePopupAction) RunPost(params struct {
|
||||
Field("prefix", params.Prefix).
|
||||
Require("请选择参数")
|
||||
|
||||
rule := &firewallconfigs.HTTPFirewallRule{
|
||||
|
||||
if len(params.Value) > 4096 {
|
||||
this.FailField("value", "对比值内容长度不能超过4096个字符")
|
||||
return
|
||||
}
|
||||
|
||||
var rule = &firewallconfigs.HTTPFirewallRule{
|
||||
Id: params.RuleId,
|
||||
IsOn: true,
|
||||
}
|
||||
@@ -81,7 +87,7 @@ func (this *CreateRulePopupAction) RunPost(params struct {
|
||||
rule.Param = "${" + params.Prefix + "}"
|
||||
}
|
||||
|
||||
paramFilters := []*firewallconfigs.ParamFilter{}
|
||||
var paramFilters = []*firewallconfigs.ParamFilter{}
|
||||
if len(params.ParamFiltersJSON) > 0 {
|
||||
err := json.Unmarshal(params.ParamFiltersJSON, ¶mFilters)
|
||||
if err != nil {
|
||||
|
||||
@@ -3,6 +3,7 @@ package waf
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
@@ -141,20 +142,7 @@ func (this *LogAction) RunGet(params struct {
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
// 根据IP查询区域
|
||||
regionMap := map[string]string{} // ip => region
|
||||
if len(ipList) > 0 {
|
||||
resp, err := this.RPC().IPLibraryRPC().LookupIPRegions(this.AdminContext(), &pb.LookupIPRegionsRequest{IpList: ipList})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if resp.IpRegionMap != nil {
|
||||
for ip, region := range resp.IpRegionMap {
|
||||
regionMap[ip] = region.Summary
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["regions"] = regionMap
|
||||
this.Data["regions"] = iplibrary.LookupIPSummaries(ipList)
|
||||
|
||||
// WAF相关
|
||||
var wafInfos = map[int64]maps.Map{} // set id => WAF Map
|
||||
|
||||
@@ -564,9 +564,11 @@ func (this *CreateAction) RunPost(params struct {
|
||||
var remoteAddrConfig = &serverconfigs.HTTPRemoteAddrConfig{
|
||||
IsOn: true,
|
||||
Value: "${rawRemoteAddr}",
|
||||
Type: serverconfigs.HTTPRemoteAddrTypeDefault,
|
||||
}
|
||||
if params.RemoteAddrIsOn {
|
||||
remoteAddrConfig.Value = "${remoteAddr}"
|
||||
remoteAddrConfig.Type = serverconfigs.HTTPRemoteAddrTypeProxy
|
||||
}
|
||||
remoteAddrConfigJSON, err := json.Marshal(remoteAddrConfig)
|
||||
if err != nil {
|
||||
|
||||
@@ -42,7 +42,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["reverseProxyRef"] = reverseProxyRef
|
||||
|
||||
var reverseProxy = &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -34,7 +34,7 @@ func (this *SchedulingAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
reverseProxy := &serverconfigs.ReverseProxyConfig{}
|
||||
reverseProxy := serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -36,14 +36,14 @@ func (this *SettingAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
|
||||
var reverseProxyRef = &serverconfigs.ReverseProxyRef{}
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyRefJSON, reverseProxyRef)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
reverseProxy := &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -67,7 +67,7 @@ func (this *SettingAction) RunPost(params struct {
|
||||
|
||||
// TODO 校验配置
|
||||
|
||||
var reverseProxyConfig = &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxyConfig = serverconfigs.NewReverseProxyConfig()
|
||||
err := json.Unmarshal(params.ReverseProxyJSON, reverseProxyConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -110,6 +110,7 @@ func (this *SettingAction) RunPost(params struct {
|
||||
AddHeaders: reverseProxyConfig.AddHeaders,
|
||||
FollowRedirects: reverseProxyConfig.FollowRedirects,
|
||||
ProxyProtocolJSON: proxyProtocolJSON,
|
||||
Retry50X: reverseProxyConfig.Retry50X,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -54,9 +55,29 @@ func (this *IndexAction) RunPost(params struct {
|
||||
err := json.Unmarshal(params.RemoteAddrJSON, remoteAddrConfig)
|
||||
if err != nil {
|
||||
this.Fail("参数校验失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
remoteAddrConfig.Value = strings.TrimSpace(remoteAddrConfig.Value)
|
||||
|
||||
switch remoteAddrConfig.Type {
|
||||
case serverconfigs.HTTPRemoteAddrTypeRequestHeader:
|
||||
if len(remoteAddrConfig.RequestHeaderName) == 0 {
|
||||
this.FailField("requestHeaderName", "请输入请求报头")
|
||||
return
|
||||
}
|
||||
if !regexp.MustCompile(`^[\w-_,]+$`).MatchString(remoteAddrConfig.RequestHeaderName) {
|
||||
this.FailField("requestHeaderName", "请求报头中只能含有数字、英文字母、下划线、中划线")
|
||||
return
|
||||
}
|
||||
remoteAddrConfig.Value = "${header." + remoteAddrConfig.RequestHeaderName + "}"
|
||||
case serverconfigs.HTTPRemoteAddrTypeVariable:
|
||||
if len(remoteAddrConfig.Value) == 0 {
|
||||
this.FailField("value", "请输入自定义变量")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = remoteAddrConfig.Init()
|
||||
if err != nil {
|
||||
this.Fail("配置校验失败:" + err.Error())
|
||||
|
||||
@@ -42,7 +42,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["reverseProxyRef"] = reverseProxyRef
|
||||
|
||||
var reverseProxy = &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -34,7 +34,7 @@ func (this *SchedulingAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
reverseProxy := &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -42,8 +42,8 @@ func (this *SchedulingAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["reverseProxyId"] = reverseProxy.Id
|
||||
|
||||
schedulingCode := reverseProxy.FindSchedulingConfig().Code
|
||||
schedulingMap := schedulingconfigs.FindSchedulingType(schedulingCode)
|
||||
var schedulingCode = reverseProxy.FindSchedulingConfig().Code
|
||||
var schedulingMap = schedulingconfigs.FindSchedulingType(schedulingCode)
|
||||
if schedulingMap == nil {
|
||||
this.ErrorPage(errors.New("invalid scheduling code '" + schedulingCode + "'"))
|
||||
return
|
||||
|
||||
@@ -36,14 +36,14 @@ func (this *SettingAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
|
||||
var reverseProxyRef = &serverconfigs.ReverseProxyRef{}
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyRefJSON, reverseProxyRef)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
reverseProxy := &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -67,7 +67,7 @@ func (this *SettingAction) RunPost(params struct {
|
||||
|
||||
// TODO 校验配置
|
||||
|
||||
var reverseProxyConfig = &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxyConfig = serverconfigs.NewReverseProxyConfig()
|
||||
err := json.Unmarshal(params.ReverseProxyJSON, reverseProxyConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -110,6 +110,7 @@ func (this *SettingAction) RunPost(params struct {
|
||||
AddHeaders: reverseProxyConfig.AddHeaders,
|
||||
FollowRedirects: reverseProxyConfig.FollowRedirects,
|
||||
ProxyProtocolJSON: proxyProtocolJSON,
|
||||
Retry50X: reverseProxyConfig.Retry50X,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -42,7 +42,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["reverseProxyRef"] = reverseProxyRef
|
||||
|
||||
var reverseProxy = &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -34,7 +34,7 @@ func (this *SchedulingAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
reverseProxy := &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -43,7 +43,7 @@ func (this *SettingAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
reverseProxy := &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -67,7 +67,7 @@ func (this *SettingAction) RunPost(params struct {
|
||||
|
||||
// TODO 校验配置
|
||||
|
||||
reverseProxyConfig := &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxyConfig = serverconfigs.NewReverseProxyConfig()
|
||||
err := json.Unmarshal(params.ReverseProxyJSON, reverseProxyConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -4,10 +4,10 @@ package ipbox
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -25,24 +25,15 @@ func (this *IndexAction) RunGet(params struct {
|
||||
this.Data["ip"] = params.Ip
|
||||
|
||||
// IP信息
|
||||
regionResp, err := this.RPC().IPLibraryRPC().LookupIPRegion(this.AdminContext(), &pb.LookupIPRegionRequest{Ip: params.Ip})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
this.Data["regions"] = ""
|
||||
this.Data["isp"] = ""
|
||||
if regionResp.IpRegion != nil {
|
||||
var regionName = regionResp.IpRegion.Summary
|
||||
|
||||
// remove isp from regionName
|
||||
var index = strings.LastIndex(regionName, "|")
|
||||
if index > 0 {
|
||||
regionName = regionName[:index]
|
||||
}
|
||||
this.Data["regions"] = regionName
|
||||
this.Data["isp"] = regionResp.IpRegion.Isp
|
||||
var ipRegion = iplibrary.LookupIP(params.Ip)
|
||||
if ipRegion != nil && ipRegion.IsOk() {
|
||||
this.Data["regions"] = ipRegion.RegionSummary()
|
||||
this.Data["isp"] = ipRegion.ProviderName()
|
||||
}
|
||||
|
||||
// IP列表
|
||||
|
||||
@@ -4,11 +4,11 @@ package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -162,22 +162,10 @@ func (this *IndexAction) RunGet(params struct {
|
||||
var region = ""
|
||||
var isp = ""
|
||||
if len(item.IpFrom) > 0 && len(item.IpTo) == 0 {
|
||||
regionResp, err := this.RPC().IPLibraryRPC().LookupIPRegion(this.AdminContext(), &pb.LookupIPRegionRequest{Ip: item.IpFrom})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var ipRegion = regionResp.IpRegion
|
||||
if ipRegion != nil {
|
||||
region = ipRegion.Summary
|
||||
|
||||
// remove isp from regionName
|
||||
var index = strings.LastIndex(region, "|")
|
||||
if index > 0 {
|
||||
region = region[:index]
|
||||
}
|
||||
|
||||
isp = ipRegion.Isp
|
||||
var ipRegion = iplibrary.LookupIP(item.IpFrom)
|
||||
if ipRegion != nil && ipRegion.IsOk() {
|
||||
region = ipRegion.RegionSummary()
|
||||
isp = ipRegion.ProviderName()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@ package iplists
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -109,22 +109,10 @@ func (this *ItemsAction) RunGet(params struct {
|
||||
var region = ""
|
||||
var isp = ""
|
||||
if len(item.IpFrom) > 0 && len(item.IpTo) == 0 {
|
||||
regionResp, err := this.RPC().IPLibraryRPC().LookupIPRegion(this.AdminContext(), &pb.LookupIPRegionRequest{Ip: item.IpFrom})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var ipRegion = regionResp.IpRegion
|
||||
if ipRegion != nil {
|
||||
region = ipRegion.Summary
|
||||
|
||||
// remove isp from regionName
|
||||
var index = strings.LastIndex(region, "|")
|
||||
if index > 0 {
|
||||
region = region[:index]
|
||||
}
|
||||
|
||||
isp = ipRegion.Isp
|
||||
var ipRegion = iplibrary.LookupIP(item.IpFrom)
|
||||
if ipRegion != nil && ipRegion.IsOk() {
|
||||
region = ipRegion.RegionSummary()
|
||||
isp = ipRegion.ProviderName()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ package logs
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
@@ -169,20 +170,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
// 根据IP查询区域
|
||||
var regionMap = map[string]string{} // ip => region
|
||||
if len(ipList) > 0 {
|
||||
resp, err := this.RPC().IPLibraryRPC().LookupIPRegions(this.AdminContext(), &pb.LookupIPRegionsRequest{IpList: ipList})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if resp.IpRegionMap != nil {
|
||||
for ip, region := range resp.IpRegionMap {
|
||||
regionMap[ip] = region.Summary
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["regions"] = regionMap
|
||||
this.Data["regions"] = iplibrary.LookupIPSummaries(ipList)
|
||||
|
||||
// WAF相关
|
||||
var wafInfos = map[int64]maps.Map{} // set id => WAF Map
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
@@ -60,6 +62,27 @@ func (this *HistoryAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
// 检查当前网站有无开启访问日志
|
||||
this.Data["serverAccessLogIsOn"] = true
|
||||
|
||||
groupResp, err := this.RPC().ServerGroupRPC().FindEnabledServerGroupConfigInfo(this.AdminContext(), &pb.FindEnabledServerGroupConfigInfoRequest{
|
||||
ServerId: params.ServerId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !groupResp.HasAccessLogConfig {
|
||||
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithServerId(this.AdminContext(), params.ServerId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if webConfig != nil && webConfig.AccessLogRef != nil && !webConfig.AccessLogRef.IsOn {
|
||||
this.Data["serverAccessLogIsOn"] = false
|
||||
}
|
||||
}
|
||||
|
||||
var day = params.Day
|
||||
var ipList = []string{}
|
||||
var wafMaps = []maps.Map{}
|
||||
@@ -160,20 +183,7 @@ func (this *HistoryAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
// 根据IP查询区域
|
||||
var regionMap = map[string]string{} // ip => region
|
||||
if len(ipList) > 0 {
|
||||
resp, err := this.RPC().IPLibraryRPC().LookupIPRegions(this.AdminContext(), &pb.LookupIPRegionsRequest{IpList: ipList})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if resp.IpRegionMap != nil {
|
||||
for ip, region := range resp.IpRegionMap {
|
||||
regionMap[ip] = region.Summary
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["regions"] = regionMap
|
||||
this.Data["regions"] = iplibrary.LookupIPSummaries(ipList)
|
||||
|
||||
// WAF相关
|
||||
var wafInfos = map[int64]maps.Map{} // set id => WAF Map
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
@@ -40,8 +42,29 @@ func (this *IndexAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
// 检查当前网站有无开启访问日志
|
||||
this.Data["serverAccessLogIsOn"] = true
|
||||
|
||||
groupResp, err := this.RPC().ServerGroupRPC().FindEnabledServerGroupConfigInfo(this.AdminContext(), &pb.FindEnabledServerGroupConfigInfoRequest{
|
||||
ServerId: params.ServerId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !groupResp.HasAccessLogConfig {
|
||||
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithServerId(this.AdminContext(), params.ServerId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if webConfig != nil && webConfig.AccessLogRef != nil && !webConfig.AccessLogRef.IsOn {
|
||||
this.Data["serverAccessLogIsOn"] = false
|
||||
}
|
||||
}
|
||||
|
||||
// 记录最近使用
|
||||
_, err := this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
|
||||
_, err = this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
|
||||
ItemType: "server",
|
||||
ItemId: params.ServerId,
|
||||
})
|
||||
@@ -129,20 +152,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
this.Data["hasMore"] = accessLogsResp.HasMore
|
||||
|
||||
// 根据IP查询区域
|
||||
var regionMap = map[string]string{} // ip => region
|
||||
if len(ipList) > 0 {
|
||||
resp, err := this.RPC().IPLibraryRPC().LookupIPRegions(this.AdminContext(), &pb.LookupIPRegionsRequest{IpList: ipList})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if resp.IpRegionMap != nil {
|
||||
for ip, region := range resp.IpRegionMap {
|
||||
regionMap[ip] = region.Summary
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["regions"] = regionMap
|
||||
this.Data["regions"] = iplibrary.LookupIPSummaries(ipList)
|
||||
|
||||
// WAF相关
|
||||
var wafInfos = map[int64]maps.Map{} // set id => WAF Map
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
@@ -54,6 +56,27 @@ func (this *TodayAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
// 检查当前网站有无开启访问日志
|
||||
this.Data["serverAccessLogIsOn"] = true
|
||||
|
||||
groupResp, err := this.RPC().ServerGroupRPC().FindEnabledServerGroupConfigInfo(this.AdminContext(), &pb.FindEnabledServerGroupConfigInfoRequest{
|
||||
ServerId: params.ServerId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if !groupResp.HasAccessLogConfig {
|
||||
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithServerId(this.AdminContext(), params.ServerId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if webConfig != nil && webConfig.AccessLogRef != nil && !webConfig.AccessLogRef.IsOn {
|
||||
this.Data["serverAccessLogIsOn"] = false
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
|
||||
Partition: params.Partition,
|
||||
RequestId: params.RequestId,
|
||||
@@ -141,20 +164,7 @@ func (this *TodayAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
// 根据IP查询区域
|
||||
var regionMap = map[string]string{} // ip => region
|
||||
if len(ipList) > 0 {
|
||||
resp, err := this.RPC().IPLibraryRPC().LookupIPRegions(this.AdminContext(), &pb.LookupIPRegionsRequest{IpList: ipList})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if resp.IpRegionMap != nil {
|
||||
for ip, region := range resp.IpRegionMap {
|
||||
regionMap[ip] = region.Summary
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["regions"] = regionMap
|
||||
this.Data["regions"] = iplibrary.LookupIPSummaries(ipList)
|
||||
|
||||
// WAF相关
|
||||
var wafInfos = map[int64]maps.Map{} // set id => WAF Map
|
||||
|
||||
@@ -2,6 +2,7 @@ package log
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net/http"
|
||||
@@ -86,24 +87,11 @@ func (this *ViewPopupAction) RunGet(params struct {
|
||||
|
||||
// 地域相关
|
||||
var regionMap maps.Map = nil
|
||||
regionResp, err := this.RPC().IPLibraryRPC().LookupIPRegion(this.AdminContext(), &pb.LookupIPRegionRequest{Ip: accessLog.RemoteAddr})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
region := regionResp.IpRegion
|
||||
if region != nil {
|
||||
var regionName = region.Summary
|
||||
|
||||
// remove isp from regionName
|
||||
var index = strings.LastIndex(regionName, "|")
|
||||
if index > 0 {
|
||||
regionName = regionName[:index]
|
||||
}
|
||||
|
||||
var ipRegion = iplibrary.LookupIP(accessLog.RemoteAddr)
|
||||
if ipRegion != nil && ipRegion.IsOk() {
|
||||
regionMap = maps.Map{
|
||||
"full": regionName,
|
||||
"isp": region.Isp,
|
||||
"full": ipRegion.RegionSummary(),
|
||||
"isp": ipRegion.ProviderName(),
|
||||
}
|
||||
}
|
||||
this.Data["region"] = regionMap
|
||||
|
||||
@@ -21,7 +21,7 @@ func (this *IndexAction) Init() {
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ServerId int64
|
||||
}) {
|
||||
// 服务分组设置
|
||||
// 网站分组设置
|
||||
groupResp, err := this.RPC().ServerGroupRPC().FindEnabledServerGroupConfigInfo(this.AdminContext(), &pb.FindEnabledServerGroupConfigInfoRequest{
|
||||
ServerId: params.ServerId,
|
||||
})
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -46,9 +47,29 @@ func (this *IndexAction) RunPost(params struct {
|
||||
err := json.Unmarshal(params.RemoteAddrJSON, remoteAddrConfig)
|
||||
if err != nil {
|
||||
this.Fail("参数校验失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
remoteAddrConfig.Value = strings.TrimSpace(remoteAddrConfig.Value)
|
||||
|
||||
switch remoteAddrConfig.Type {
|
||||
case serverconfigs.HTTPRemoteAddrTypeRequestHeader:
|
||||
if len(remoteAddrConfig.RequestHeaderName) == 0 {
|
||||
this.FailField("requestHeaderName", "请输入请求报头")
|
||||
return
|
||||
}
|
||||
if !regexp.MustCompile(`^[\w-_,]+$`).MatchString(remoteAddrConfig.RequestHeaderName) {
|
||||
this.FailField("requestHeaderName", "请求报头中只能含有数字、英文字母、下划线、中划线")
|
||||
return
|
||||
}
|
||||
remoteAddrConfig.Value = "${header." + remoteAddrConfig.RequestHeaderName + "}"
|
||||
case serverconfigs.HTTPRemoteAddrTypeVariable:
|
||||
if len(remoteAddrConfig.Value) == 0 {
|
||||
this.FailField("value", "请输入自定义变量")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = remoteAddrConfig.Init()
|
||||
if err != nil {
|
||||
this.Fail("配置校验失败:" + err.Error())
|
||||
|
||||
@@ -41,7 +41,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["reverseProxyRef"] = reverseProxyRef
|
||||
|
||||
var reverseProxy = &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -18,7 +18,7 @@ func (this *SchedulingAction) Init() {
|
||||
}
|
||||
|
||||
func (this *SchedulingAction) RunGet(params struct {
|
||||
ServerId int64
|
||||
ServerId int64
|
||||
LocationId int64
|
||||
}) {
|
||||
reverseProxyResp, err := this.RPC().HTTPLocationRPC().FindAndInitHTTPLocationReverseProxyConfig(this.AdminContext(), &pb.FindAndInitHTTPLocationReverseProxyConfigRequest{LocationId: params.LocationId})
|
||||
@@ -26,7 +26,7 @@ func (this *SchedulingAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
reverseProxy := &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -34,8 +34,8 @@ func (this *SchedulingAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["reverseProxyId"] = reverseProxy.Id
|
||||
|
||||
schedulingCode := reverseProxy.FindSchedulingConfig().Code
|
||||
schedulingMap := schedulingconfigs.FindSchedulingType(schedulingCode)
|
||||
var schedulingCode = reverseProxy.FindSchedulingConfig().Code
|
||||
var schedulingMap = schedulingconfigs.FindSchedulingType(schedulingCode)
|
||||
if schedulingMap == nil {
|
||||
this.ErrorPage(errors.New("invalid scheduling code '" + schedulingCode + "'"))
|
||||
return
|
||||
|
||||
@@ -34,7 +34,7 @@ func (this *SettingAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
reverseProxy := &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -58,7 +58,7 @@ func (this *SettingAction) RunPost(params struct {
|
||||
|
||||
// TODO 校验配置
|
||||
|
||||
var reverseProxyConfig = &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxyConfig = serverconfigs.NewReverseProxyConfig()
|
||||
err := json.Unmarshal(params.ReverseProxyJSON, reverseProxyConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -101,6 +101,7 @@ func (this *SettingAction) RunPost(params struct {
|
||||
AddHeaders: reverseProxyConfig.AddHeaders,
|
||||
FollowRedirects: reverseProxyConfig.FollowRedirects,
|
||||
ProxyProtocolJSON: proxyProtocolJSON,
|
||||
Retry50X: reverseProxyConfig.Retry50X,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -63,6 +64,25 @@ func (this *IndexAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
remoteAddrConfig.Value = strings.TrimSpace(remoteAddrConfig.Value)
|
||||
|
||||
switch remoteAddrConfig.Type {
|
||||
case serverconfigs.HTTPRemoteAddrTypeRequestHeader:
|
||||
if len(remoteAddrConfig.RequestHeaderName) == 0 {
|
||||
this.FailField("requestHeaderName", "请输入请求报头")
|
||||
return
|
||||
}
|
||||
if !regexp.MustCompile(`^[\w-_,]+$`).MatchString(remoteAddrConfig.RequestHeaderName) {
|
||||
this.FailField("requestHeaderName", "请求报头中只能含有数字、英文字母、下划线、中划线")
|
||||
return
|
||||
}
|
||||
remoteAddrConfig.Value = "${header." + remoteAddrConfig.RequestHeaderName + "}"
|
||||
case serverconfigs.HTTPRemoteAddrTypeVariable:
|
||||
if len(remoteAddrConfig.Value) == 0 {
|
||||
this.FailField("value", "请输入自定义变量")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = remoteAddrConfig.Init()
|
||||
if err != nil {
|
||||
this.Fail("配置校验失败:" + err.Error())
|
||||
|
||||
@@ -68,7 +68,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["reverseProxyRef"] = reverseProxyRef
|
||||
|
||||
var reverseProxy = &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -25,7 +25,7 @@ func (this *SchedulingAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
reverseProxy := &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -28,14 +28,14 @@ func (this *SettingAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
|
||||
var reverseProxyRef = &serverconfigs.ReverseProxyRef{}
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyRefJSON, reverseProxyRef)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
reverseProxy := &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(reverseProxyResp.ReverseProxyJSON, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -57,7 +57,7 @@ func (this *SettingAction) RunPost(params struct {
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ServerReverseProxy_LogUpdateServerReverseProxySettings, params.ServerId)
|
||||
|
||||
var reverseProxyConfig = &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxyConfig = serverconfigs.NewReverseProxyConfig()
|
||||
err := json.Unmarshal(params.ReverseProxyJSON, reverseProxyConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -133,6 +133,7 @@ func (this *SettingAction) RunPost(params struct {
|
||||
ProxyProtocolJSON: proxyProtocolJSON,
|
||||
FollowRedirects: reverseProxyConfig.FollowRedirects,
|
||||
RequestHostExcludingPort: reverseProxyConfig.RequestHostExcludingPort,
|
||||
Retry50X: reverseProxyConfig.Retry50X,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -43,7 +43,7 @@ func (this *UpdateSchedulingPopupAction) RunGet(params struct {
|
||||
}
|
||||
configData := reverseProxyResp.ReverseProxyJSON
|
||||
|
||||
reverseProxyConfig := &serverconfigs.ReverseProxyConfig{}
|
||||
var reverseProxyConfig = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(configData, reverseProxyConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -126,8 +126,8 @@ func (this *UpdateSchedulingPopupAction) RunPost(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
configData := reverseProxyResp.ReverseProxyJSON
|
||||
reverseProxy := &serverconfigs.ReverseProxyConfig{}
|
||||
var configData = reverseProxyResp.ReverseProxyJSON
|
||||
var reverseProxy = serverconfigs.NewReverseProxyConfig()
|
||||
err = json.Unmarshal(configData, reverseProxy)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -291,10 +291,11 @@ func (this *ServerHelper) createSettingsMenu(secondMenuItem string, serverIdStri
|
||||
"isOn": serverConfig.Web != nil && len(serverConfig.Web.RewriteRefs) > 0,
|
||||
})
|
||||
menuItems = append(menuItems, maps.Map{
|
||||
"name": this.Lang(actionPtr, codes.Server_MenuSettingWAF),
|
||||
"url": "/servers/server/settings/waf?serverId=" + serverIdString,
|
||||
"isActive": secondMenuItem == "waf",
|
||||
"isOn": serverConfig.Web != nil && serverConfig.Web.FirewallRef != nil && serverConfig.Web.FirewallRef.IsOn,
|
||||
"name": this.Lang(actionPtr, codes.Server_MenuSettingWAF),
|
||||
"url": "/servers/server/settings/waf?serverId=" + serverIdString,
|
||||
"isActive": secondMenuItem == "waf",
|
||||
"isOn": serverConfig.Web != nil && serverConfig.Web.FirewallRef != nil && serverConfig.Web.FirewallRef.IsOn,
|
||||
"configCode": serverconfigs.ConfigCodeWAF,
|
||||
})
|
||||
menuItems = append(menuItems, maps.Map{
|
||||
"name": this.Lang(actionPtr, codes.Server_MenuSettingCache),
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"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/maps"
|
||||
@@ -28,17 +27,7 @@ func (this *StatusAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
// 读取全局配置
|
||||
globalConfig, err := dao.SharedSysSettingDAO.ReadGlobalConfig(this.AdminContext())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
auditingPrompt := ""
|
||||
if globalConfig != nil {
|
||||
auditingPrompt = globalConfig.HTTPAll.DomainAuditingPrompt
|
||||
}
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
var wg = sync.WaitGroup{}
|
||||
wg.Add(len(params.ServerIds))
|
||||
|
||||
for _, serverId := range params.ServerIds {
|
||||
@@ -98,6 +87,17 @@ func (this *StatusAction) RunPost(params struct {
|
||||
if serverNamesResp.IsAuditing {
|
||||
m["type"] = "auditing"
|
||||
m["message"] = "审核中"
|
||||
|
||||
auditingPromptResp, err := this.RPC().ServerRPC().FindServerAuditingPrompt(this.AdminContext(), &pb.FindServerAuditingPromptRequest{ServerId: serverId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
m["type"] = "serverErr"
|
||||
m["message"] = "服务器错误"
|
||||
m["todo"] = "错误信息:FindServerNames(): " + err.Error() + ",请联系管理员修复此问题"
|
||||
return
|
||||
}
|
||||
|
||||
var auditingPrompt = auditingPromptResp.PromptText
|
||||
if len(auditingPrompt) > 0 {
|
||||
m["todo"] = auditingPrompt
|
||||
} else {
|
||||
|
||||
@@ -41,6 +41,7 @@ func (this *CleanSettingAction) RunPost(params struct {
|
||||
ServerAccessLogCleanDays int
|
||||
ServerBandwidthStatCleanDays int
|
||||
UserBandwidthStatCleanDays int
|
||||
UserPlanBandwidthStatCleanDays int
|
||||
ServerDailyStatCleanDays int
|
||||
ServerDomainHourlyStatCleanDays int
|
||||
TrafficDailyStatCleanDays int
|
||||
@@ -85,6 +86,11 @@ func (this *CleanSettingAction) RunPost(params struct {
|
||||
}
|
||||
config.UserBandwidthStat.Clean.Days = params.UserBandwidthStatCleanDays
|
||||
|
||||
if params.UserPlanBandwidthStatCleanDays < 0 {
|
||||
params.UserPlanBandwidthStatCleanDays = 0
|
||||
}
|
||||
config.UserPlanBandwidthStat.Clean.Days = params.UserPlanBandwidthStatCleanDays
|
||||
|
||||
if params.ServerDailyStatCleanDays < 0 {
|
||||
params.ServerDailyStatCleanDays = 0
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ func (this *MySQLInstaller) InstallFromFile(xzFilePath string, targetDir string)
|
||||
}
|
||||
|
||||
// waiting for startup
|
||||
for i := 0; i < 5; i++ {
|
||||
for i := 0; i < 30; i++ {
|
||||
_, err = net.Dial("tcp", "127.0.0.1:3306")
|
||||
if err != nil {
|
||||
time.Sleep(1 * time.Second)
|
||||
@@ -362,7 +362,7 @@ func (this *MySQLInstaller) InstallFromFile(xzFilePath string, targetDir string)
|
||||
this.log("changing mysql password ...")
|
||||
var passwordSQL = "ALTER USER 'root'@'localhost' IDENTIFIED BY '" + newPassword + "';"
|
||||
{
|
||||
var cmd = utils.NewCmd("sh", "-c", baseDir+"/bin/mysql --user=root --password=\""+generatedPassword+"\" --execute=\""+passwordSQL+"\" --connect-expired-password")
|
||||
var cmd = utils.NewCmd("sh", "-c", baseDir+"/bin/mysql --host=\"127.0.0.1\" --user=root --password=\""+generatedPassword+"\" --execute=\""+passwordSQL+"\" --connect-expired-password")
|
||||
cmd.WithStderr()
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/users/userutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
@@ -60,13 +61,9 @@ func (this *UserAction) RunGet(params struct {
|
||||
// IP地址
|
||||
var registeredRegion = ""
|
||||
if len(user.RegisteredIP) > 0 {
|
||||
regionResp, err := this.RPC().IPLibraryRPC().LookupIPRegion(this.AdminContext(), &pb.LookupIPRegionRequest{Ip: user.RegisteredIP})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if regionResp.IpRegion != nil {
|
||||
registeredRegion = regionResp.IpRegion.Summary
|
||||
var ipRegion = iplibrary.LookupIP(user.RegisteredIP)
|
||||
if ipRegion != nil && ipRegion.IsOk() {
|
||||
registeredRegion = ipRegion.Summary()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@ package helpers
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
||||
nodes "github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/regionconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
@@ -77,23 +77,25 @@ func checkIPWithoutCache(config *systemconfigs.SecurityConfig, ipAddr string) bo
|
||||
|
||||
// 检查位置
|
||||
if len(config.AllowCountryIds) > 0 || len(config.AllowProvinceIds) > 0 {
|
||||
rpc, err := nodes.SharedRPC()
|
||||
if err != nil {
|
||||
logs.Println("[USER_MUST_AUTH][ERROR]" + err.Error())
|
||||
var userRegion = iplibrary.Lookup(ip)
|
||||
if userRegion == nil || !userRegion.IsOk() {
|
||||
return false
|
||||
}
|
||||
resp, err := rpc.IPLibraryRPC().LookupIPRegion(rpc.Context(0), &pb.LookupIPRegionRequest{Ip: ipAddr})
|
||||
if err != nil {
|
||||
logs.Println("[USER_MUST_AUTH][ERROR]" + err.Error())
|
||||
return false
|
||||
if len(config.AllowCountryIds) > 0 {
|
||||
// 检查大中华区
|
||||
var found = false
|
||||
for _, countryId := range config.AllowCountryIds {
|
||||
if regionconfigs.MatchUserRegion(userRegion.CountryId(), userRegion.ProvinceId(), countryId) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if resp.IpRegion == nil {
|
||||
return true
|
||||
}
|
||||
if len(config.AllowCountryIds) > 0 && !lists.ContainsInt64(config.AllowCountryIds, resp.IpRegion.CountryId) {
|
||||
return false
|
||||
}
|
||||
if len(config.AllowProvinceIds) > 0 && !lists.ContainsInt64(config.AllowProvinceIds, resp.IpRegion.ProvinceId) {
|
||||
if len(config.AllowProvinceIds) > 0 && !lists.ContainsInt64(config.AllowProvinceIds, userRegion.ProvinceId()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ import (
|
||||
// 服务相关
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/cache/batch"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/components/log"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -2840,6 +2840,42 @@ Vue.component("plan-user-selector", {
|
||||
</div>`
|
||||
})
|
||||
|
||||
// 显示流量限制说明
|
||||
Vue.component("plan-limit-view", {
|
||||
props: ["value", "v-single-mode"],
|
||||
data: function () {
|
||||
let config = this.value
|
||||
|
||||
let hasLimit = false
|
||||
if (!this.vSingleMode) {
|
||||
if (config.trafficLimit != null && config.trafficLimit.isOn && ((config.trafficLimit.dailySize != null && config.trafficLimit.dailySize.count > 0) || (config.trafficLimit.monthlySize != null && config.trafficLimit.monthlySize.count > 0))) {
|
||||
hasLimit = true
|
||||
} else if (config.dailyRequests > 0 || config.monthlyRequests > 0) {
|
||||
hasLimit = true
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
config: config,
|
||||
hasLimit: hasLimit
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatNumber: function (n) {
|
||||
return teaweb.formatNumber(n)
|
||||
}
|
||||
},
|
||||
template: `<div style="font-size: 0.8em; color: grey">
|
||||
<div class="ui divider" v-if="hasLimit"></div>
|
||||
<div v-if="config.trafficLimit != null && config.trafficLimit.isOn">
|
||||
<span v-if="config.trafficLimit.dailySize != null && config.trafficLimit.dailySize.count > 0">日流量限制:{{config.trafficLimit.dailySize.count}}{{config.trafficLimit.dailySize.unit.toUpperCase()}}<br/></span>
|
||||
<span v-if="config.trafficLimit.monthlySize != null && config.trafficLimit.monthlySize.count > 0">月流量限制:{{config.trafficLimit.monthlySize.count}}{{config.trafficLimit.monthlySize.unit.toUpperCase()}}<br/></span>
|
||||
</div>
|
||||
<div v-if="config.dailyRequests > 0">单日请求数限制:{{formatNumber(config.dailyRequests)}}</div>
|
||||
<div v-if="config.monthlyRequests > 0">单月请求数限制:{{formatNumber(config.monthlyRequests)}}</div>
|
||||
</div>`
|
||||
})
|
||||
|
||||
Vue.component("plan-price-view", {
|
||||
props: ["v-plan"],
|
||||
data: function () {
|
||||
@@ -3033,6 +3069,7 @@ Vue.component("plan-price-config-box", {
|
||||
<input type="text" style="width: 7em" maxlength="10" v-model="monthlyPrice"/>
|
||||
<span class="ui label">元</span>
|
||||
</div>
|
||||
<p class="comment">如果为0表示免费。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -3042,6 +3079,7 @@ Vue.component("plan-price-config-box", {
|
||||
<input type="text" style="width: 7em" maxlength="10" v-model="seasonallyPrice"/>
|
||||
<span class="ui label">元</span>
|
||||
</div>
|
||||
<p class="comment">如果为0表示免费。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -3051,6 +3089,7 @@ Vue.component("plan-price-config-box", {
|
||||
<input type="text" style="width: 7em" maxlength="10" v-model="yearlyPrice"/>
|
||||
<span class="ui label">元</span>
|
||||
</div>
|
||||
<p class="comment">如果为0表示免费。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -4505,44 +4544,6 @@ Vue.component("http-firewall-actions-view", {
|
||||
</div>`
|
||||
})
|
||||
|
||||
Vue.component("http-request-scripts-config-box", {
|
||||
props: ["vRequestScriptsConfig", "v-is-location"],
|
||||
data: function () {
|
||||
let config = this.vRequestScriptsConfig
|
||||
if (config == null) {
|
||||
config = {}
|
||||
}
|
||||
return {
|
||||
config: config
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeInitGroup: function (group) {
|
||||
this.config.initGroup = group
|
||||
this.$forceUpdate()
|
||||
},
|
||||
changeRequestGroup: function (group) {
|
||||
this.config.requestGroup = group
|
||||
this.$forceUpdate()
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<input type="hidden" name="requestScriptsJSON" :value="JSON.stringify(config)"/>
|
||||
<div class="margin"></div>
|
||||
<h4 style="margin-bottom: 0">请求初始化</h4>
|
||||
<p class="comment">在请求刚初始化时调用,此时自定义Header等尚未生效。</p>
|
||||
<div>
|
||||
<script-group-config-box :v-group="config.initGroup" @change="changeInitGroup" :v-is-location="vIsLocation"></script-group-config-box>
|
||||
</div>
|
||||
<h4 style="margin-bottom: 0">准备发送请求</h4>
|
||||
<p class="comment">在准备执行请求或者转发请求之前调用,此时自定义Header、源站等已准备好。</p>
|
||||
<div>
|
||||
<script-group-config-box :v-group="config.requestGroup" @change="changeRequestGroup" :v-is-location="vIsLocation"></script-group-config-box>
|
||||
</div>
|
||||
<div class="margin"></div>
|
||||
</div>`
|
||||
})
|
||||
|
||||
// 显示WAF规则的标签
|
||||
Vue.component("http-firewall-rule-label", {
|
||||
props: ["v-rule"],
|
||||
@@ -5043,7 +5044,7 @@ Vue.component("http-cache-ref-box", {
|
||||
isOn: true,
|
||||
cachePolicyId: 0,
|
||||
key: "${scheme}://${host}${requestPath}${isArgs}${args}",
|
||||
life: {count: 2, unit: "hour"},
|
||||
life: {count: 1, unit: "day"},
|
||||
status: [200],
|
||||
maxSize: {count: 128, unit: "mb"},
|
||||
minSize: {count: 0, unit: "kb"},
|
||||
@@ -5200,13 +5201,13 @@ Vue.component("http-cache-ref-box", {
|
||||
},
|
||||
template: `<tbody>
|
||||
<tr v-if="condCategory == 'simple'">
|
||||
<td class="title">条件类型 *</td>
|
||||
<td class="title">缓存对象 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="condType" v-model="condType" @change="changeCondType(condType, false)">
|
||||
<option value="url-extension">文件扩展名</option>
|
||||
<option value="url-eq-index">首页</option>
|
||||
<option value="url-all">全站</option>
|
||||
<option value="url-prefix">URL前缀</option>
|
||||
<option value="url-prefix">URL目录前缀</option>
|
||||
<option value="url-eq">URL完整路径</option>
|
||||
<option value="url-wildcard-match">URL通配符</option>
|
||||
<option value="url-regexp">URL正则匹配</option>
|
||||
@@ -5244,7 +5245,7 @@ Vue.component("http-cache-ref-box", {
|
||||
<tr v-show="!vIsReverse">
|
||||
<td>缓存有效期 *</td>
|
||||
<td>
|
||||
<time-duration-box :v-value="ref.life" @change="changeLife"></time-duration-box>
|
||||
<time-duration-box :v-value="ref.life" @change="changeLife" :v-min-unit="'minute'" maxlength="4"></time-duration-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="!vIsReverse">
|
||||
@@ -5255,15 +5256,15 @@ Vue.component("http-cache-ref-box", {
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="!vIsReverse">
|
||||
<td colspan="2"><more-options-indicator @change="changeOptionsVisible"></more-options-indicator></td>
|
||||
</tr>
|
||||
<tr v-show="moreOptionsVisible && !vIsReverse">
|
||||
<td>缓存Key *</td>
|
||||
<td>
|
||||
<input type="text" v-model="ref.key" @input="changeKey(ref.key)"/>
|
||||
<p class="comment">用来区分不同缓存内容的唯一Key。<request-variables-describer ref="variablesDescriber"></request-variables-describer>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="!vIsReverse">
|
||||
<td colspan="2"><more-options-indicator @change="changeOptionsVisible"></more-options-indicator></td>
|
||||
</tr>
|
||||
<tr v-show="moreOptionsVisible && !vIsReverse">
|
||||
<td>请求方法限制</td>
|
||||
<td>
|
||||
@@ -5333,7 +5334,7 @@ Vue.component("http-cache-ref-box", {
|
||||
<input type="checkbox" value="1" v-model="ref.skipSetCookie"/>
|
||||
<label></label>
|
||||
</div>
|
||||
<p class="comment">选中后,当响应的Header中有Set-Cookie时不缓存响应内容。</p>
|
||||
<p class="comment">选中后,当响应的报头中有Set-Cookie时不缓存响应内容,防止动态内容被缓存。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="moreOptionsVisible && !vIsReverse">
|
||||
@@ -5343,7 +5344,7 @@ Vue.component("http-cache-ref-box", {
|
||||
<input type="checkbox" name="enableRequestCachePragma" value="1" v-model="ref.enableRequestCachePragma"/>
|
||||
<label></label>
|
||||
</div>
|
||||
<p class="comment">选中后,当请求的Header中含有Pragma: no-cache或Cache-Control: no-cache时,会跳过缓存直接读取源内容。</p>
|
||||
<p class="comment">选中后,当请求的报头中含有Pragma: no-cache或Cache-Control: no-cache时,会跳过缓存直接读取源内容,一般仅用于调试。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="moreOptionsVisible && !vIsReverse">
|
||||
@@ -5699,7 +5700,7 @@ Vue.component("http-firewall-config-box", {
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<more-options-tbody @change="changeOptionsVisible"></more-options-tbody>
|
||||
<more-options-tbody @change="changeOptionsVisible" v-show="firewall.isOn"></more-options-tbody>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>启用系统全局规则</td>
|
||||
@@ -8614,11 +8615,15 @@ Vue.component("http-firewall-actions-box", {
|
||||
}
|
||||
|
||||
var defaultPageBody = `<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<title>403 Forbidden</title>
|
||||
\t<style>
|
||||
\t\taddress { line-height: 1.8; }
|
||||
\t</style>
|
||||
<body>
|
||||
<h1>403 Forbidden</h1>
|
||||
<address>Request ID: \${requestId}.</address>
|
||||
<address>Connection: \${remoteAddr} (Client) -> \${serverAddr} (Server)</address>
|
||||
<address>Request ID: \${requestId}</address>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
@@ -9055,9 +9060,12 @@ Vue.component("http-firewall-actions-box", {
|
||||
if (isNaN(timeout)) {
|
||||
timeout = 0
|
||||
}
|
||||
if (this.recordIPListId <= 0) {
|
||||
if (this.recordIPListId < 0) {
|
||||
return
|
||||
}
|
||||
|
||||
// recordIPListId can be 0
|
||||
|
||||
this.actionOptions = {
|
||||
type: this.recordIPType,
|
||||
level: this.recordIPLevel,
|
||||
@@ -9233,7 +9241,7 @@ Vue.component("http-firewall-actions-box", {
|
||||
<span v-if="config.code == 'post_307' && config.options.life > 0">:有效期{{config.options.life}}秒</span>
|
||||
|
||||
<!-- record_ip -->
|
||||
<span v-if="config.code == 'record_ip'">:{{config.options.ipListName}}</span>
|
||||
<span v-if="config.code == 'record_ip'">:<span :class="{red: config.options.ipListIsDeleted}">{{config.options.ipListName}}</span></span>
|
||||
|
||||
<!-- tag -->
|
||||
<span v-if="config.code == 'tag'">:{{config.options.tags.join(", ")}}</span>
|
||||
@@ -9405,7 +9413,7 @@ Vue.component("http-firewall-actions-box", {
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="actionCode == 'record_ip'">
|
||||
<td>选择IP名单 *</td>
|
||||
<td>选择IP名单</td>
|
||||
<td>
|
||||
<div v-if="recordIPListId > 0" class="ui label basic small">{{recordIPListName}} <a href="" @click.prevent="removeRecordIPList"><i class="icon remove small"></i></a></div>
|
||||
<button type="button" class="ui button tiny" @click.prevent="selectRecordIPList">+</button>
|
||||
@@ -10178,17 +10186,21 @@ Vue.component("http-pages-and-shutdown-box", {
|
||||
},
|
||||
addShutdownHTMLTemplate: function () {
|
||||
this.shutdownConfig.body = `<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
\t<title>升级中</title>
|
||||
\t<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
\t<style>
|
||||
\t\taddress { line-height: 1.8; }
|
||||
\t</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>网站升级中</h1>
|
||||
<p>为了给您提供更好的服务,我们正在升级网站,请稍后重新访问。</p>
|
||||
|
||||
<address>Request ID: \${requestId}.</address>
|
||||
<address>Connection: \${remoteAddr} (Client) -> \${serverAddr} (Server)</address>
|
||||
<address>Request ID: \${requestId}</address>
|
||||
|
||||
</body>
|
||||
</html>`
|
||||
@@ -10661,16 +10673,6 @@ Vue.component("http-cc-config-box", {
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody v-show="moreOptionsVisible && config.isOn">
|
||||
<tr>
|
||||
<td>单IP最低QPS</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="minQPSPerIP" maxlength="6" style="width: 6em" v-model="minQPSPerIP"/>
|
||||
<span class="ui label">请求数/秒</span>
|
||||
</div>
|
||||
<p class="comment">当某个IP在1分钟内平均QPS达到此值时,才会触发CC防护;如果设置为0,表示任何访问都会触发。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>例外URL</td>
|
||||
<td>
|
||||
@@ -10700,13 +10702,23 @@ Vue.component("http-cc-config-box", {
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">使用自定义阈值</td>
|
||||
<td>单IP最低QPS</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="minQPSPerIP" maxlength="6" style="width: 6em" v-model="minQPSPerIP"/>
|
||||
<span class="ui label">请求数/秒</span>
|
||||
</div>
|
||||
<p class="comment">当某个IP在1分钟内平均QPS达到此值时,才会开始检测;如果设置为0,表示任何访问都会检测。(注意这里设置的是检测开启阈值,不是拦截阈值,拦截阈值在当前表单下方可以设置)</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">使用自定义拦截阈值</td>
|
||||
<td>
|
||||
<checkbox v-model="useCustomThresholds"></checkbox>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="!config.useDefaultThresholds">
|
||||
<td class="color-border">自定义阈值设置</td>
|
||||
<td class="color-border">自定义拦截阈值设置</td>
|
||||
<td>
|
||||
<div>
|
||||
<div class="ui input left right labeled">
|
||||
@@ -11560,23 +11572,6 @@ Vue.component("http-access-log-config-box", {
|
||||
</div>`
|
||||
})
|
||||
|
||||
// 显示流量限制说明
|
||||
Vue.component("traffic-limit-view", {
|
||||
props: ["v-traffic-limit"],
|
||||
data: function () {
|
||||
return {
|
||||
config: this.vTrafficLimit
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<div v-if="config.isOn">
|
||||
<span v-if="config.dailySize != null && config.dailySize.count > 0">日流量限制:{{config.dailySize.count}}{{config.dailySize.unit.toUpperCase()}}<br/></span>
|
||||
<span v-if="config.monthlySize != null && config.monthlySize.count > 0">月流量限制:{{config.monthlySize.count}}{{config.monthlySize.unit.toUpperCase()}}<br/></span>
|
||||
</div>
|
||||
<span v-else class="disabled">没有限制。</span>
|
||||
</div>`
|
||||
})
|
||||
|
||||
// 基本认证用户配置
|
||||
Vue.component("http-auth-basic-auth-user-box", {
|
||||
props: ["v-users"],
|
||||
@@ -12041,7 +12036,8 @@ Vue.component("reverse-proxy-box", {
|
||||
idleTimeout: {count: 0, unit: "second"},
|
||||
maxConns: 0,
|
||||
maxIdleConns: 0,
|
||||
followRedirects: false
|
||||
followRedirects: false,
|
||||
retry50X: true
|
||||
}
|
||||
}
|
||||
if (reverseProxyConfig.addHeaders == null) {
|
||||
@@ -12181,6 +12177,7 @@ Vue.component("reverse-proxy-box", {
|
||||
<input type="checkbox" v-model="reverseProxyRef.isOn"/>
|
||||
<label></label>
|
||||
</div>
|
||||
<p class="comment">选中后,所有源站设置才会生效。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="family == null || family == 'http'">
|
||||
@@ -12192,7 +12189,7 @@ Vue.component("reverse-proxy-box", {
|
||||
<div v-show="reverseProxyConfig.requestHostType == 2" style="margin-top: 0.8em">
|
||||
<input type="text" placeholder="比如example.com" v-model="reverseProxyConfig.requestHost"/>
|
||||
</div>
|
||||
<p class="comment">请求源站时的Host,用于修改源站接收到的域名
|
||||
<p class="comment">请求源站时的主机名(Host),用于修改源站接收到的域名
|
||||
<span v-if="reverseProxyConfig.requestHostType == 0">,"跟随CDN域名"是指源站接收到的域名和当前CDN访问域名保持一致</span>
|
||||
<span v-if="reverseProxyConfig.requestHostType == 1">,"跟随源站"是指源站接收到的域名仍然是填写的源站地址中的信息,不随代理服务域名改变而改变</span>
|
||||
<span v-if="reverseProxyConfig.requestHostType == 2">,自定义Host内容中支持请求变量</span>。</p>
|
||||
@@ -12215,7 +12212,7 @@ Vue.component("reverse-proxy-box", {
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="family == null || family == 'http'">
|
||||
<td>自动添加的Header</td>
|
||||
<td>自动添加报头</td>
|
||||
<td>
|
||||
<div>
|
||||
<div style="width: 14em; float: left; margin-bottom: 1em" v-for="header in forwardHeaders" :key="header.name">
|
||||
@@ -12223,7 +12220,7 @@ Vue.component("reverse-proxy-box", {
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
<p class="comment">选中后,会自动向源站请求添加这些Header。</p>
|
||||
<p class="comment">选中后,会自动向源站请求添加这些报头,以便于源站获取客户端信息。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="family == null || family == 'http'">
|
||||
@@ -12314,6 +12311,13 @@ Vue.component("reverse-proxy-box", {
|
||||
<p class="comment">源站保持等待的空闲超时时间,0表示使用默认时间。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="family == null || family == 'http'">
|
||||
<td>自动重试50X</td>
|
||||
<td>
|
||||
<checkbox v-model="reverseProxyConfig.retry50X"></checkbox>
|
||||
<p class="comment">选中后,表示当源站返回状态码为50X(比如502、504)时,自动重试。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="family != 'unix'">
|
||||
<td>PROXY Protocol</td>
|
||||
<td>
|
||||
@@ -12428,13 +12432,35 @@ Vue.component("http-remote-addr-config-box", {
|
||||
isPrior: false,
|
||||
isOn: false,
|
||||
value: "${rawRemoteAddr}",
|
||||
isCustomized: false
|
||||
type: "default",
|
||||
|
||||
requestHeaderName: ""
|
||||
}
|
||||
}
|
||||
|
||||
let optionValue = ""
|
||||
if (!config.isCustomized && (config.value == "${remoteAddr}" || config.value == "${rawRemoteAddr}")) {
|
||||
optionValue = config.value
|
||||
// type
|
||||
if (config.type == null || config.type.length == 0) {
|
||||
config.type = "default"
|
||||
switch (config.value) {
|
||||
case "${rawRemoteAddr}":
|
||||
config.type = "default"
|
||||
break
|
||||
case "${remoteAddrValue}":
|
||||
config.type = "default"
|
||||
break
|
||||
case "${remoteAddr}":
|
||||
config.type = "proxy"
|
||||
break
|
||||
default:
|
||||
if (config.value != null && config.value.length > 0) {
|
||||
config.type = "variable"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// value
|
||||
if (config.value == null || config.value.length == 0) {
|
||||
config.value = "${rawRemoteAddr}"
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -12442,33 +12468,70 @@ Vue.component("http-remote-addr-config-box", {
|
||||
options: [
|
||||
{
|
||||
name: "直接获取",
|
||||
description: "用户直接访问边缘节点,即 \"用户 --> 边缘节点\" 模式,这时候可以直接从连接中读取到真实的IP地址。",
|
||||
value: "${rawRemoteAddr}"
|
||||
description: "用户直接访问边缘节点,即 \"用户 --> 边缘节点\" 模式,这时候系统会试图从直接的连接中读取到客户端IP地址。",
|
||||
value: "${rawRemoteAddr}",
|
||||
type: "default"
|
||||
},
|
||||
{
|
||||
name: "从上级代理中获取",
|
||||
description: "用户和边缘节点之间有别的代理服务转发,即 \"用户 --> [第三方代理服务] --> 边缘节点\",这时候只能从上级代理中获取传递的IP地址。",
|
||||
value: "${remoteAddr}"
|
||||
description: "用户和边缘节点之间有别的代理服务转发,即 \"用户 --> [第三方代理服务] --> 边缘节点\",这时候只能从上级代理中获取传递的IP地址;上级代理传递的请求报头中必须包含 X-Forwarded-For 或 X-Real-IP 信息。",
|
||||
value: "${remoteAddr}",
|
||||
type: "proxy"
|
||||
},
|
||||
{
|
||||
name: "[自定义]",
|
||||
name: "从请求报头中读取",
|
||||
description: "从自定义请求报头读取客户端IP。",
|
||||
value: "",
|
||||
type: "requestHeader"
|
||||
},
|
||||
{
|
||||
name: "[自定义变量]",
|
||||
description: "通过自定义变量来获取客户端真实的IP地址。",
|
||||
value: ""
|
||||
value: "",
|
||||
type: "variable"
|
||||
}
|
||||
],
|
||||
optionValue: optionValue
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
"config.requestHeaderName": function (value) {
|
||||
if (this.config.type == "requestHeader"){
|
||||
this.config.value = "${header." + value.trim() + "}"
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isOn: function () {
|
||||
return ((!this.vIsLocation && !this.vIsGroup) || this.config.isPrior) && this.config.isOn
|
||||
},
|
||||
changeOptionValue: function () {
|
||||
if (this.optionValue.length > 0) {
|
||||
this.config.value = this.optionValue
|
||||
this.config.isCustomized = false
|
||||
} else {
|
||||
this.config.isCustomized = true
|
||||
changeOptionType: function () {
|
||||
let that = this
|
||||
|
||||
switch(this.config.type) {
|
||||
case "default":
|
||||
this.config.value = "${rawRemoteAddr}"
|
||||
break
|
||||
case "proxy":
|
||||
this.config.value = "${remoteAddr}"
|
||||
break
|
||||
case "requestHeader":
|
||||
this.config.value = ""
|
||||
if (this.requestHeaderName != null && this.requestHeaderName.length > 0) {
|
||||
this.config.value = "${header." + this.requestHeaderName + "}"
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
that.$refs.requestHeaderInput.focus()
|
||||
})
|
||||
break
|
||||
case "variable":
|
||||
this.config.value = "${rawRemoteAddr}"
|
||||
|
||||
setTimeout(function () {
|
||||
that.$refs.variableInput.focus()
|
||||
})
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -12484,7 +12547,7 @@ Vue.component("http-remote-addr-config-box", {
|
||||
<input type="checkbox" value="1" v-model="config.isOn"/>
|
||||
<label></label>
|
||||
</div>
|
||||
<p class="comment">选中后表示使用自定义的请求变量获取客户端IP。</p>
|
||||
<p class="comment">选中后,表示使用自定义的请求变量获取客户端IP。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -12492,20 +12555,28 @@ Vue.component("http-remote-addr-config-box", {
|
||||
<tr>
|
||||
<td>获取IP方式 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" v-model="optionValue" @change="changeOptionValue">
|
||||
<option v-for="option in options" :value="option.value">{{option.name}}</option>
|
||||
<select class="ui dropdown auto-width" v-model="config.type" @change="changeOptionType">
|
||||
<option v-for="option in options" :value="option.type">{{option.name}}</option>
|
||||
</select>
|
||||
<p class="comment" v-for="option in options" v-if="option.value == optionValue && option.description.length > 0">{{option.description}}</p>
|
||||
<p class="comment" v-for="option in options" v-if="option.type == config.type && option.description.length > 0">{{option.description}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="optionValue.length == 0">
|
||||
|
||||
<!-- read from request header -->
|
||||
<tr v-show="config.type == 'requestHeader'">
|
||||
<td>请求报头 *</td>
|
||||
<td>
|
||||
<input type="text" name="requestHeaderName" v-model="config.requestHeaderName" maxlength="100" ref="requestHeaderInput"/>
|
||||
<p class="comment">请输入包含有客户端IP的请求报头,需要注意大小写,常见的有<code-label>X-Forwarded-For</code-label>、<code-label>X-Real-IP</code-label>、<code-label>X-Client-IP</code-label>等。</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- read from variable -->
|
||||
<tr v-show="config.type == 'variable'">
|
||||
<td>读取IP变量值 *</td>
|
||||
<td>
|
||||
<input type="hidden" v-model="config.value" maxlength="100"/>
|
||||
<div v-if="optionValue == ''" style="margin-top: 1em">
|
||||
<input type="text" v-model="config.value" maxlength="100"/>
|
||||
<p class="comment">通过此变量获取用户的IP地址。具体可用的请求变量列表可参考官方网站文档。</p>
|
||||
</div>
|
||||
<input type="text" name="value" v-model="config.value" maxlength="100" ref="variableInput"/>
|
||||
<p class="comment">通过此变量获取用户的IP地址。具体可用的请求变量列表可参考官方网站文档;比如通过报头传递IP的情形,可以使用<code-label>\${header.你的自定义报头}</code-label>(类似于<code-label>\${header.X-Forwarded-For}</code-label>,需要注意大小写规范)。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -12598,7 +12669,7 @@ Vue.component("http-access-log-search-box", {
|
||||
<a class="ui label basic" :class="{disabled: keyword.length == 0}" @click.prevent="cleanKeyword"><i class="icon remove small"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field"><tip-icon content="一些特殊的关键词:<br/>单个状态码:status:200<br/>状态码范围:status:500-504<br/>查询IP:ip:192.168.1.100<br/>查询URL:https://goedge.cn/docs<br/>查询路径部分:requestPath:/hello/world<br/>查询协议版本:proto:HTTP/1.1<br/>协议:scheme:http<br/>请求方法:method:POST"></tip-icon></div>
|
||||
<div class="ui field"><tip-icon content="一些特殊的关键词:<br/>单个状态码:status:200<br/>状态码范围:status:500-504<br/>查询IP:ip:192.168.1.100<br/>查询URL:https://goedge.cn/docs<br/>查询路径部分:requestPath:/hello/world<br/>查询协议版本:proto:HTTP/1.1<br/>协议:scheme:http<br/>请求方法:method:POST<br/>请求来源:referer:example.com"></tip-icon></div>
|
||||
</div>
|
||||
<div class="ui fields inline" style="margin-top: 0.5em">
|
||||
<div class="ui field">
|
||||
@@ -12996,7 +13067,7 @@ Vue.component("http-webp-config-box", {
|
||||
quality: 50,
|
||||
minLength: {count: 0, "unit": "kb"},
|
||||
maxLength: {count: 0, "unit": "kb"},
|
||||
mimeTypes: ["image/png", "image/jpeg", "image/bmp", "image/x-ico", "image/gif"],
|
||||
mimeTypes: ["image/png", "image/jpeg", "image/bmp", "image/x-ico"],
|
||||
extensions: [".png", ".jpeg", ".jpg", ".bmp", ".ico"],
|
||||
conds: null
|
||||
}
|
||||
@@ -13062,7 +13133,7 @@ Vue.component("http-webp-config-box", {
|
||||
<input type="checkbox" value="1" v-model="config.isOn"/>
|
||||
<label></label>
|
||||
</div>
|
||||
<p class="comment">选中后表示开启自动WebP压缩<span v-if="vRequireCache">;只有满足缓存条件的图片内容才会被转换</span>。</p>
|
||||
<p class="comment">选中后表示开启自动WebP压缩;图片的宽和高均不能超过16383像素<span v-if="vRequireCache">;只有满足缓存条件的图片内容才会被转换</span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -13296,6 +13367,44 @@ Vue.component("http-oss-bucket-params", {
|
||||
</tbody>`
|
||||
})
|
||||
|
||||
Vue.component("http-request-scripts-config-box", {
|
||||
props: ["vRequestScriptsConfig", "v-is-location"],
|
||||
data: function () {
|
||||
let config = this.vRequestScriptsConfig
|
||||
if (config == null) {
|
||||
config = {}
|
||||
}
|
||||
return {
|
||||
config: config
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeInitGroup: function (group) {
|
||||
this.config.initGroup = group
|
||||
this.$forceUpdate()
|
||||
},
|
||||
changeRequestGroup: function (group) {
|
||||
this.config.requestGroup = group
|
||||
this.$forceUpdate()
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<input type="hidden" name="requestScriptsJSON" :value="JSON.stringify(config)"/>
|
||||
<div class="margin"></div>
|
||||
<h4 style="margin-bottom: 0">请求初始化</h4>
|
||||
<p class="comment">在请求刚初始化时调用,此时自定义报头等尚未生效。</p>
|
||||
<div>
|
||||
<script-group-config-box :v-group="config.initGroup" @change="changeInitGroup" :v-is-location="vIsLocation"></script-group-config-box>
|
||||
</div>
|
||||
<h4 style="margin-bottom: 0">准备发送请求</h4>
|
||||
<p class="comment">在准备执行请求或者转发请求之前调用,此时自定义报头、源站等已准备好。</p>
|
||||
<div>
|
||||
<script-group-config-box :v-group="config.requestGroup" @change="changeRequestGroup" :v-is-location="vIsLocation"></script-group-config-box>
|
||||
</div>
|
||||
<div class="margin"></div>
|
||||
</div>`
|
||||
})
|
||||
|
||||
Vue.component("http-request-cond-view", {
|
||||
props: ["v-cond"],
|
||||
data: function () {
|
||||
@@ -14923,7 +15032,8 @@ Vue.component("http-firewall-captcha-options", {
|
||||
return {
|
||||
options: options,
|
||||
isEditing: false,
|
||||
summary: ""
|
||||
summary: "",
|
||||
uiBodyWarning: ""
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -14967,6 +15077,13 @@ Vue.component("http-firewall-captcha-options", {
|
||||
},
|
||||
"options.uiIsOn": function (v) {
|
||||
this.updateSummary()
|
||||
},
|
||||
"options.uiBody": function (v) {
|
||||
if (/<form(>|\s).+\$\{body}.*<\/form>/s.test(v)) {
|
||||
this.uiBodyWarning = "页面模板中不能使用<form></form>标签包裹\${body}变量,否则将导致验证码表单无法提交。"
|
||||
} else {
|
||||
this.uiBodyWarning = ""
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -15101,7 +15218,7 @@ Vue.component("http-firewall-captcha-options", {
|
||||
<td class="color-border">页面模板</td>
|
||||
<td>
|
||||
<textarea spellcheck="false" rows="2" v-model="options.uiBody"></textarea>
|
||||
<p class="comment"><span v-if="options.uiBody.length > 0 && options.uiBody.indexOf('\${body}') < 0 " class="red">模板中必须包含\${body}表示验证码表单!</span>整个页面的模板,支持HTML,其中必须使用<code-label>\${body}</code-label>变量代表验证码表单,否则将无法正常显示验证码。</p>
|
||||
<p class="comment"><span v-if="uiBodyWarning.length > 0" class="red">警告:{{uiBodyWarning}}</span><span v-if="options.uiBody.length > 0 && options.uiBody.indexOf('\${body}') < 0 " class="red">模板中必须包含\${body}表示验证码表单!</span>整个页面的模板,支持HTML,其中必须使用<code-label>\${body}</code-label>变量代表验证码表单,否则将无法正常显示验证码。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -15677,10 +15794,13 @@ Vue.component("ip-list-table", {
|
||||
<keyword :v-word="keyword">{{item.ipFrom}}</keyword> <span> <span class="small red" v-if="item.isRead != null && !item.isRead"> New </span> <a :href="'/servers/iplists?ip=' + item.ipFrom" v-if="vShowSearchButton" title="搜索此IP"><span><i class="icon search small" style="color: #ccc"></i></span></a></span>
|
||||
<span v-if="item.ipTo.length > 0"> - <keyword :v-word="keyword">{{item.ipTo}}</keyword></span></span>
|
||||
<span v-else class="disabled">*</span>
|
||||
|
||||
<div v-if="item.region != null && item.region.length > 0">
|
||||
<span class="grey small">{{item.region}}</span>
|
||||
<span v-if="item.isp != null && item.isp.length > 0 && item.isp != '内网IP'" class="grey small"><span class="disabled">|</span> {{item.isp}}</span>
|
||||
</div>
|
||||
<div v-else-if="item.isp != null && item.isp.length > 0 && item.isp != '内网IP'"><span class="grey small">{{item.isp}}</span></div>
|
||||
|
||||
<div v-if="item.createdTime != null">
|
||||
<span class="small grey">添加于 {{item.createdTime}}
|
||||
<span v-if="item.list != null && item.list.id > 0">
|
||||
@@ -16292,13 +16412,19 @@ Vue.component("menu-item", {
|
||||
|
||||
// 使用Icon的链接方式
|
||||
Vue.component("link-icon", {
|
||||
props: ["href", "title", "target"],
|
||||
props: ["href", "title", "target", "size"],
|
||||
data: function () {
|
||||
let realSize = this.size
|
||||
if (realSize == null || realSize.length == 0) {
|
||||
realSize = "small"
|
||||
}
|
||||
|
||||
return {
|
||||
vTitle: (this.title == null) ? "打开链接" : this.title
|
||||
vTitle: (this.title == null) ? "打开链接" : this.title,
|
||||
realSize: realSize
|
||||
}
|
||||
},
|
||||
template: `<span><slot></slot> <a :href="href" :title="vTitle" class="link grey" :target="target"><i class="icon linkify small"></i></a></span>`
|
||||
template: `<span><slot></slot> <a :href="href" :title="vTitle" class="link grey" :target="target"><i class="icon linkify" :class="realSize"></i></a></span>`
|
||||
})
|
||||
|
||||
// 带有下划虚线的连接
|
||||
@@ -17799,7 +17925,7 @@ Vue.component("dot", {
|
||||
})
|
||||
|
||||
Vue.component("time-duration-box", {
|
||||
props: ["name", "v-name", "v-value", "v-count", "v-unit"],
|
||||
props: ["v-name", "v-value", "v-count", "v-unit", "placeholder", "v-min-unit", "maxlength"],
|
||||
mounted: function () {
|
||||
this.change()
|
||||
},
|
||||
@@ -17815,17 +17941,52 @@ Vue.component("time-duration-box", {
|
||||
v["count"] = -1
|
||||
}
|
||||
|
||||
let realName = ""
|
||||
if (typeof this.name == "string" && this.name.length > 0) {
|
||||
realName = this.name
|
||||
} else if (typeof this.vName == "string" && this.vName.length > 0) {
|
||||
realName = this.vName
|
||||
let minUnit = this.vMinUnit
|
||||
let units = [
|
||||
{
|
||||
code: "ms",
|
||||
name: "毫秒"
|
||||
},
|
||||
{
|
||||
code: "second",
|
||||
name: "秒"
|
||||
},
|
||||
{
|
||||
code: "minute",
|
||||
name: "分钟"
|
||||
},
|
||||
{
|
||||
code: "hour",
|
||||
name: "小时"
|
||||
},
|
||||
{
|
||||
code: "day",
|
||||
name: "天"
|
||||
}
|
||||
]
|
||||
let minUnitIndex = -1
|
||||
if (minUnit != null && typeof minUnit == "string" && minUnit.length > 0) {
|
||||
for (let i = 0; i < units.length; i++) {
|
||||
if (units[i].code == minUnit) {
|
||||
minUnitIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (minUnitIndex > -1) {
|
||||
units = units.slice(minUnitIndex)
|
||||
}
|
||||
|
||||
let maxLength = parseInt(this.maxlength)
|
||||
if (typeof maxLength != "number") {
|
||||
maxLength = 10
|
||||
}
|
||||
|
||||
return {
|
||||
duration: v,
|
||||
countString: (v.count >= 0) ? v.count.toString() : "",
|
||||
realName: realName
|
||||
units: units,
|
||||
realMaxLength: maxLength
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -17848,23 +18009,41 @@ Vue.component("time-duration-box", {
|
||||
}
|
||||
},
|
||||
template: `<div class="ui fields inline" style="padding-bottom: 0; margin-bottom: 0">
|
||||
<input type="hidden" :name="realName" :value="JSON.stringify(duration)"/>
|
||||
<input type="hidden" :name="vName" :value="JSON.stringify(duration)"/>
|
||||
<div class="ui field">
|
||||
<input type="text" v-model="countString" maxlength="11" size="11" @keypress.enter.prevent="1"/>
|
||||
<input type="text" v-model="countString" :maxlength="realMaxLength" :size="realMaxLength" :placeholder="placeholder" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" v-model="duration.unit" @change="change">
|
||||
<option value="ms">毫秒</option>
|
||||
<option value="second">秒</option>
|
||||
<option value="minute">分钟</option>
|
||||
<option value="hour">小时</option>
|
||||
<option value="day">天</option>
|
||||
<option value="week">周</option>
|
||||
<option v-for="unit in units" :value="unit.code">{{unit.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
|
||||
Vue.component("time-duration-text", {
|
||||
props: ["v-value"],
|
||||
methods: {
|
||||
unitName: function (unit) {
|
||||
switch (unit) {
|
||||
case "ms":
|
||||
return "毫秒"
|
||||
case "second":
|
||||
return "秒"
|
||||
case "minute":
|
||||
return "分钟"
|
||||
case "hour":
|
||||
return "小时"
|
||||
case "day":
|
||||
return "天"
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `<span>
|
||||
{{vValue.count}} {{unitName(vValue.unit)}}
|
||||
</span>`
|
||||
})
|
||||
|
||||
Vue.component("not-found-box", {
|
||||
props: ["message"],
|
||||
template: `<div style="text-align: center; margin-top: 5em;">
|
||||
@@ -17952,7 +18131,9 @@ Vue.component("url-patterns-box", {
|
||||
isAdding: false,
|
||||
|
||||
addingPattern: {"type": "wildcard", "pattern": ""},
|
||||
editingIndex: -1
|
||||
editingIndex: -1,
|
||||
|
||||
patternIsInvalid: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -18013,6 +18194,27 @@ Vue.component("url-patterns-box", {
|
||||
},
|
||||
notifyChange: function () {
|
||||
this.$emit("input", this.patterns)
|
||||
},
|
||||
changePattern: function () {
|
||||
this.patternIsInvalid = false
|
||||
let pattern = this.addingPattern.pattern
|
||||
switch (this.addingPattern.type) {
|
||||
case "wildcard":
|
||||
if (pattern.indexOf("?") >= 0) {
|
||||
this.patternIsInvalid = true
|
||||
}
|
||||
break
|
||||
case "regexp":
|
||||
if (pattern.indexOf("?") >= 0) {
|
||||
let pieces = pattern.split("?")
|
||||
for (let i = 0; i < pieces.length - 1; i++) {
|
||||
if (pieces[i].length == 0 || pieces[i][pieces[i].length - 1] != "\\") {
|
||||
this.patternIsInvalid = true
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
@@ -18032,14 +18234,15 @@ Vue.component("url-patterns-box", {
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" :placeholder="(addingPattern.type == 'wildcard') ? '可以使用星号(*)通配符,不区分大小写' : '可以使用正则表达式,不区分大小写'" v-model="addingPattern.pattern" size="36" ref="patternInput" @keyup.enter="confirm()" @keypress.enter.prevent="1" spellcheck="false"/>
|
||||
<input type="text" :placeholder="(addingPattern.type == 'wildcard') ? '可以使用星号(*)通配符,不区分大小写' : '可以使用正则表达式,不区分大小写'" v-model="addingPattern.pattern" @input="changePattern" size="36" ref="patternInput" @keyup.enter="confirm()" @keypress.enter.prevent="1" spellcheck="false"/>
|
||||
<p class="comment" v-if="patternIsInvalid"><span class="red" style="font-weight: normal"><span v-if="addingPattern.type == 'wildcard'">通配符</span><span v-if="addingPattern.type == 'regexp'">正则表达式</span>中不能包含问号(?)及问号以后的内容。</span></p>
|
||||
</div>
|
||||
<div class="ui field" style="padding-left: 0">
|
||||
<tip-icon content="通配符示例:<br/>单个路径开头:/hello/world/*<br/>单个路径结尾:*/hello/world<br/>包含某个路径:*/article/*<br/>某个域名下的所有URL:*example.com/*" v-if="addingPattern.type == 'wildcard'"></tip-icon>
|
||||
<tip-icon content="正则表达式示例:<br/>单个路径开头:^/hello/world<br/>单个路径结尾:/hello/world$<br/>包含某个路径:/article/<br/>匹配某个数字路径:/article/(\\d+)<br/>某个域名下的所有URL:^(http|https)://example.com/" v-if="addingPattern.type == 'regexp'"></tip-icon>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button tiny" type="button" @click.prevent="confirm">确定</button><a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
||||
<button class="ui button tiny" :class="{disabled:this.patternIsInvalid}" type="button" @click.prevent="confirm">确定</button><a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -18156,7 +18359,7 @@ Vue.component("digit-input", {
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `<input type="text" v-model="realValue" :maxlength="realMaxLength" :size="realSize" :class="{error: !this.isValid}" :placeholder="placeholder"/>`
|
||||
template: `<input type="text" v-model="realValue" :maxlength="realMaxLength" :size="realSize" :class="{error: !this.isValid}" :placeholder="placeholder" autocomplete="off"/>`
|
||||
})
|
||||
|
||||
Vue.component("keyword", {
|
||||
@@ -20481,6 +20684,9 @@ Vue.component("dns-route-selector", {
|
||||
this.routes.$removeIf(function (k, v) {
|
||||
return v.code + "@" + v.domainId == route.code + "@" + route.domainId
|
||||
})
|
||||
},
|
||||
clearKeyword: function () {
|
||||
this.keyword = ""
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -20514,16 +20720,22 @@ Vue.component("dns-route-selector", {
|
||||
<tr>
|
||||
<td class="title">所有线路</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" v-model="routeCode">
|
||||
<option value="" v-if="keyword.length == 0">[请选择]</option>
|
||||
<option v-for="route in searchingRoutes" :value="route.code + '@' + route.domainId">{{route.name}}({{route.code}}/{{route.domainName}})</option>
|
||||
</select>
|
||||
<span v-if="keyword.length > 0 && searchingRoutes.length == 0">没有和关键词“{{keyword}}”匹配的线路</span>
|
||||
<span v-show="keyword.length == 0 || searchingRoutes.length > 0">
|
||||
<select class="ui dropdown" v-model="routeCode">
|
||||
<option value="" v-if="keyword.length == 0">[请选择]</option>
|
||||
<option v-for="route in searchingRoutes" :value="route.code + '@' + route.domainId">{{route.name}}({{route.code}}/{{route.domainName}})</option>
|
||||
</select>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>搜索</td>
|
||||
<td>搜索线路</td>
|
||||
<td>
|
||||
<input type="text" placeholder="搜索..." size="10" style="width: 10em" v-model="keyword" ref="keywordRef" @keyup.enter="confirm" @keypress.enter.prevent="1"/>
|
||||
<div class="ui input" :class="{'right labeled':keyword.length > 0}">
|
||||
<input type="text" placeholder="线路名称或代号..." size="10" style="width: 10em" v-model="keyword" ref="keywordRef" @keyup.enter="confirm" @keypress.enter.prevent="1"/>
|
||||
<a class="ui label" v-if="keyword.length > 0" @click.prevent="clearKeyword" href=""><i class="icon remove small blue"></i></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -20987,7 +21199,7 @@ Vue.component("grant-selector", {
|
||||
</div>`
|
||||
})
|
||||
|
||||
window.REQUEST_COND_COMPONENTS = [{"type":"url-extension","name":"文件扩展名","description":"根据URL中的文件路径扩展名进行过滤","component":"http-cond-url-extension","paramsTitle":"扩展名列表","isRequest":true,"caseInsensitive":false},{"type":"url-eq-index","name":"首页","description":"检查URL路径是为\"/\"","component":"http-cond-url-eq-index","paramsTitle":"URL完整路径","isRequest":true,"caseInsensitive":false},{"type":"url-all","name":"全站","description":"全站所有URL","component":"http-cond-url-all","paramsTitle":"URL完整路径","isRequest":true,"caseInsensitive":false},{"type":"url-prefix","name":"URL前缀","description":"根据URL中的文件路径前缀进行过滤","component":"http-cond-url-prefix","paramsTitle":"URL前缀","isRequest":true,"caseInsensitive":true},{"type":"url-eq","name":"URL完整路径","description":"检查URL中的文件路径是否一致","component":"http-cond-url-eq","paramsTitle":"URL完整路径","isRequest":true,"caseInsensitive":true},{"type":"url-regexp","name":"URL正则匹配","description":"使用正则表达式检查URL中的文件路径是否一致","component":"http-cond-url-regexp","paramsTitle":"正则表达式","isRequest":true,"caseInsensitive":true},{"type":"url-wildcard-match","name":"URL通配符","description":"使用通配符检查URL中的文件路径是否一致","component":"http-cond-url-wildcard-match","paramsTitle":"通配符","isRequest":true,"caseInsensitive":true},{"type":"user-agent-regexp","name":"User-Agent正则匹配","description":"使用正则表达式检查User-Agent中是否含有某些浏览器和系统标识","component":"http-cond-user-agent-regexp","paramsTitle":"正则表达式","isRequest":true,"caseInsensitive":true},{"type":"params","name":"参数匹配","description":"根据参数值进行匹配","component":"http-cond-params","paramsTitle":"参数配置","isRequest":true,"caseInsensitive":false},{"type":"url-not-extension","name":"排除:URL扩展名","description":"根据URL中的文件路径扩展名进行过滤","component":"http-cond-url-not-extension","paramsTitle":"扩展名列表","isRequest":true,"caseInsensitive":false},{"type":"url-not-prefix","name":"排除:URL前缀","description":"根据URL中的文件路径前缀进行过滤","component":"http-cond-url-not-prefix","paramsTitle":"URL前缀","isRequest":true,"caseInsensitive":true},{"type":"url-not-eq","name":"排除:URL完整路径","description":"检查URL中的文件路径是否一致","component":"http-cond-url-not-eq","paramsTitle":"URL完整路径","isRequest":true,"caseInsensitive":true},{"type":"url-not-regexp","name":"排除:URL正则匹配","description":"使用正则表达式检查URL中的文件路径是否一致,如果一致,则不匹配","component":"http-cond-url-not-regexp","paramsTitle":"正则表达式","isRequest":true,"caseInsensitive":true},{"type":"user-agent-not-regexp","name":"排除:User-Agent正则匹配","description":"使用正则表达式检查User-Agent中是否含有某些浏览器和系统标识,如果含有,则不匹配","component":"http-cond-user-agent-not-regexp","paramsTitle":"正则表达式","isRequest":true,"caseInsensitive":true},{"type":"mime-type","name":"内容MimeType","description":"根据服务器返回的内容的MimeType进行过滤。注意:当用于缓存条件时,此条件需要结合别的请求条件使用。","component":"http-cond-mime-type","paramsTitle":"MimeType列表","isRequest":false,"caseInsensitive":false}]
|
||||
window.REQUEST_COND_COMPONENTS = [{"type":"url-extension","name":"文件扩展名","description":"根据URL中的文件路径扩展名进行过滤","component":"http-cond-url-extension","paramsTitle":"扩展名列表","isRequest":true,"caseInsensitive":false},{"type":"url-eq-index","name":"首页","description":"检查URL路径是为\"/\"","component":"http-cond-url-eq-index","paramsTitle":"URL完整路径","isRequest":true,"caseInsensitive":false},{"type":"url-all","name":"全站","description":"全站所有URL","component":"http-cond-url-all","paramsTitle":"URL完整路径","isRequest":true,"caseInsensitive":false},{"type":"url-prefix","name":"URL目录前缀","description":"根据URL中的文件路径前缀进行过滤","component":"http-cond-url-prefix","paramsTitle":"URL目录前缀","isRequest":true,"caseInsensitive":true},{"type":"url-eq","name":"URL完整路径","description":"检查URL中的文件路径是否一致","component":"http-cond-url-eq","paramsTitle":"URL完整路径","isRequest":true,"caseInsensitive":true},{"type":"url-regexp","name":"URL正则匹配","description":"使用正则表达式检查URL中的文件路径是否一致","component":"http-cond-url-regexp","paramsTitle":"正则表达式","isRequest":true,"caseInsensitive":true},{"type":"url-wildcard-match","name":"URL通配符","description":"使用通配符检查URL中的文件路径是否一致","component":"http-cond-url-wildcard-match","paramsTitle":"通配符","isRequest":true,"caseInsensitive":true},{"type":"user-agent-regexp","name":"User-Agent正则匹配","description":"使用正则表达式检查User-Agent中是否含有某些浏览器和系统标识","component":"http-cond-user-agent-regexp","paramsTitle":"正则表达式","isRequest":true,"caseInsensitive":true},{"type":"params","name":"参数匹配","description":"根据参数值进行匹配","component":"http-cond-params","paramsTitle":"参数配置","isRequest":true,"caseInsensitive":false},{"type":"url-not-extension","name":"排除:URL扩展名","description":"根据URL中的文件路径扩展名进行过滤","component":"http-cond-url-not-extension","paramsTitle":"扩展名列表","isRequest":true,"caseInsensitive":false},{"type":"url-not-prefix","name":"排除:URL前缀","description":"根据URL中的文件路径前缀进行过滤","component":"http-cond-url-not-prefix","paramsTitle":"URL前缀","isRequest":true,"caseInsensitive":true},{"type":"url-not-eq","name":"排除:URL完整路径","description":"检查URL中的文件路径是否一致","component":"http-cond-url-not-eq","paramsTitle":"URL完整路径","isRequest":true,"caseInsensitive":true},{"type":"url-not-regexp","name":"排除:URL正则匹配","description":"使用正则表达式检查URL中的文件路径是否一致,如果一致,则不匹配","component":"http-cond-url-not-regexp","paramsTitle":"正则表达式","isRequest":true,"caseInsensitive":true},{"type":"user-agent-not-regexp","name":"排除:User-Agent正则匹配","description":"使用正则表达式检查User-Agent中是否含有某些浏览器和系统标识,如果含有,则不匹配","component":"http-cond-user-agent-not-regexp","paramsTitle":"正则表达式","isRequest":true,"caseInsensitive":true},{"type":"mime-type","name":"内容MimeType","description":"根据服务器返回的内容的MimeType进行过滤。注意:当用于缓存条件时,此条件需要结合别的请求条件使用。","component":"http-cond-mime-type","paramsTitle":"MimeType列表","isRequest":false,"caseInsensitive":false}]
|
||||
|
||||
window.REQUEST_COND_OPERATORS = [{"description":"判断是否正则表达式匹配","name":"正则表达式匹配","op":"regexp"},{"description":"判断是否正则表达式不匹配","name":"正则表达式不匹配","op":"not regexp"},{"description":"判断是否和指定的通配符匹配","name":"通配符匹配","op":"wildcard match"},{"description":"判断是否和指定的通配符不匹配","name":"通配符不匹配","op":"wildcard not match"},{"description":"使用字符串对比参数值是否相等于某个值","name":"字符串等于","op":"eq"},{"description":"参数值包含某个前缀","name":"字符串前缀","op":"prefix"},{"description":"参数值包含某个后缀","name":"字符串后缀","op":"suffix"},{"description":"参数值包含另外一个字符串","name":"字符串包含","op":"contains"},{"description":"参数值不包含另外一个字符串","name":"字符串不包含","op":"not contains"},{"description":"使用字符串对比参数值是否不相等于某个值","name":"字符串不等于","op":"not"},{"description":"判断参数值在某个列表中","name":"在列表中","op":"in"},{"description":"判断参数值不在某个列表中","name":"不在列表中","op":"not in"},{"description":"判断小写的扩展名(不带点)在某个列表中","name":"扩展名","op":"file ext"},{"description":"判断MimeType在某个列表中,支持类似于image/*的语法","name":"MimeType","op":"mime type"},{"description":"判断版本号在某个范围内,格式为version1,version2","name":"版本号范围","op":"version range"},{"description":"将参数转换为整数数字后进行对比","name":"整数等于","op":"eq int"},{"description":"将参数转换为可以有小数的浮点数字进行对比","name":"浮点数等于","op":"eq float"},{"description":"将参数转换为数字进行对比","name":"数字大于","op":"gt"},{"description":"将参数转换为数字进行对比","name":"数字大于等于","op":"gte"},{"description":"将参数转换为数字进行对比","name":"数字小于","op":"lt"},{"description":"将参数转换为数字进行对比","name":"数字小于等于","op":"lte"},{"description":"对整数参数值取模,除数为10,对比值为余数","name":"整数取模10","op":"mod 10"},{"description":"对整数参数值取模,除数为100,对比值为余数","name":"整数取模100","op":"mod 100"},{"description":"对整数参数值取模,对比值格式为:除数,余数,比如10,1","name":"整数取模","op":"mod"},{"description":"将参数转换为IP进行对比","name":"IP等于","op":"eq ip"},{"description":"将参数转换为IP进行对比","name":"IP大于","op":"gt ip"},{"description":"将参数转换为IP进行对比","name":"IP大于等于","op":"gte ip"},{"description":"将参数转换为IP进行对比","name":"IP小于","op":"lt ip"},{"description":"将参数转换为IP进行对比","name":"IP小于等于","op":"lte ip"},{"description":"IP在某个范围之内,范围格式可以是英文逗号分隔的\u003ccode-label\u003e开始IP,结束IP\u003c/code-label\u003e,比如\u003ccode-label\u003e192.168.1.100,192.168.2.200\u003c/code-label\u003e,或者CIDR格式的ip/bits,比如\u003ccode-label\u003e192.168.2.1/24\u003c/code-label\u003e","name":"IP范围","op":"ip range"},{"description":"对IP参数值取模,除数为10,对比值为余数","name":"IP取模10","op":"ip mod 10"},{"description":"对IP参数值取模,除数为100,对比值为余数","name":"IP取模100","op":"ip mod 100"},{"description":"对IP参数值取模,对比值格式为:除数,余数,比如10,1","name":"IP取模","op":"ip mod"}]
|
||||
|
||||
|
||||
@@ -59,5 +59,5 @@ Vue.component("digit-input", {
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `<input type="text" v-model="realValue" :maxlength="realMaxLength" :size="realSize" :class="{error: !this.isValid}" :placeholder="placeholder"/>`
|
||||
template: `<input type="text" v-model="realValue" :maxlength="realMaxLength" :size="realSize" :class="{error: !this.isValid}" :placeholder="placeholder" autocomplete="off"/>`
|
||||
})
|
||||
@@ -1,12 +1,18 @@
|
||||
// 使用Icon的链接方式
|
||||
Vue.component("link-icon", {
|
||||
props: ["href", "title", "target"],
|
||||
props: ["href", "title", "target", "size"],
|
||||
data: function () {
|
||||
let realSize = this.size
|
||||
if (realSize == null || realSize.length == 0) {
|
||||
realSize = "small"
|
||||
}
|
||||
|
||||
return {
|
||||
vTitle: (this.title == null) ? "打开链接" : this.title
|
||||
vTitle: (this.title == null) ? "打开链接" : this.title,
|
||||
realSize: realSize
|
||||
}
|
||||
},
|
||||
template: `<span><slot></slot> <a :href="href" :title="vTitle" class="link grey" :target="target"><i class="icon linkify small"></i></a></span>`
|
||||
template: `<span><slot></slot> <a :href="href" :title="vTitle" class="link grey" :target="target"><i class="icon linkify" :class="realSize"></i></a></span>`
|
||||
})
|
||||
|
||||
// 带有下划虚线的连接
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Vue.component("time-duration-box", {
|
||||
props: ["name", "v-name", "v-value", "v-count", "v-unit"],
|
||||
props: ["v-name", "v-value", "v-count", "v-unit", "placeholder", "v-min-unit", "maxlength"],
|
||||
mounted: function () {
|
||||
this.change()
|
||||
},
|
||||
@@ -15,17 +15,52 @@ Vue.component("time-duration-box", {
|
||||
v["count"] = -1
|
||||
}
|
||||
|
||||
let realName = ""
|
||||
if (typeof this.name == "string" && this.name.length > 0) {
|
||||
realName = this.name
|
||||
} else if (typeof this.vName == "string" && this.vName.length > 0) {
|
||||
realName = this.vName
|
||||
let minUnit = this.vMinUnit
|
||||
let units = [
|
||||
{
|
||||
code: "ms",
|
||||
name: "毫秒"
|
||||
},
|
||||
{
|
||||
code: "second",
|
||||
name: "秒"
|
||||
},
|
||||
{
|
||||
code: "minute",
|
||||
name: "分钟"
|
||||
},
|
||||
{
|
||||
code: "hour",
|
||||
name: "小时"
|
||||
},
|
||||
{
|
||||
code: "day",
|
||||
name: "天"
|
||||
}
|
||||
]
|
||||
let minUnitIndex = -1
|
||||
if (minUnit != null && typeof minUnit == "string" && minUnit.length > 0) {
|
||||
for (let i = 0; i < units.length; i++) {
|
||||
if (units[i].code == minUnit) {
|
||||
minUnitIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (minUnitIndex > -1) {
|
||||
units = units.slice(minUnitIndex)
|
||||
}
|
||||
|
||||
let maxLength = parseInt(this.maxlength)
|
||||
if (typeof maxLength != "number") {
|
||||
maxLength = 10
|
||||
}
|
||||
|
||||
return {
|
||||
duration: v,
|
||||
countString: (v.count >= 0) ? v.count.toString() : "",
|
||||
realName: realName
|
||||
units: units,
|
||||
realMaxLength: maxLength
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -48,19 +83,37 @@ Vue.component("time-duration-box", {
|
||||
}
|
||||
},
|
||||
template: `<div class="ui fields inline" style="padding-bottom: 0; margin-bottom: 0">
|
||||
<input type="hidden" :name="realName" :value="JSON.stringify(duration)"/>
|
||||
<input type="hidden" :name="vName" :value="JSON.stringify(duration)"/>
|
||||
<div class="ui field">
|
||||
<input type="text" v-model="countString" maxlength="11" size="11" @keypress.enter.prevent="1"/>
|
||||
<input type="text" v-model="countString" :maxlength="realMaxLength" :size="realMaxLength" :placeholder="placeholder" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" v-model="duration.unit" @change="change">
|
||||
<option value="ms">毫秒</option>
|
||||
<option value="second">秒</option>
|
||||
<option value="minute">分钟</option>
|
||||
<option value="hour">小时</option>
|
||||
<option value="day">天</option>
|
||||
<option value="week">周</option>
|
||||
<option v-for="unit in units" :value="unit.code">{{unit.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
|
||||
Vue.component("time-duration-text", {
|
||||
props: ["v-value"],
|
||||
methods: {
|
||||
unitName: function (unit) {
|
||||
switch (unit) {
|
||||
case "ms":
|
||||
return "毫秒"
|
||||
case "second":
|
||||
return "秒"
|
||||
case "minute":
|
||||
return "分钟"
|
||||
case "hour":
|
||||
return "小时"
|
||||
case "day":
|
||||
return "天"
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `<span>
|
||||
{{vValue.count}} {{unitName(vValue.unit)}}
|
||||
</span>`
|
||||
})
|
||||
@@ -10,7 +10,9 @@ Vue.component("url-patterns-box", {
|
||||
isAdding: false,
|
||||
|
||||
addingPattern: {"type": "wildcard", "pattern": ""},
|
||||
editingIndex: -1
|
||||
editingIndex: -1,
|
||||
|
||||
patternIsInvalid: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -71,6 +73,27 @@ Vue.component("url-patterns-box", {
|
||||
},
|
||||
notifyChange: function () {
|
||||
this.$emit("input", this.patterns)
|
||||
},
|
||||
changePattern: function () {
|
||||
this.patternIsInvalid = false
|
||||
let pattern = this.addingPattern.pattern
|
||||
switch (this.addingPattern.type) {
|
||||
case "wildcard":
|
||||
if (pattern.indexOf("?") >= 0) {
|
||||
this.patternIsInvalid = true
|
||||
}
|
||||
break
|
||||
case "regexp":
|
||||
if (pattern.indexOf("?") >= 0) {
|
||||
let pieces = pattern.split("?")
|
||||
for (let i = 0; i < pieces.length - 1; i++) {
|
||||
if (pieces[i].length == 0 || pieces[i][pieces[i].length - 1] != "\\") {
|
||||
this.patternIsInvalid = true
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
@@ -90,14 +113,15 @@ Vue.component("url-patterns-box", {
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" :placeholder="(addingPattern.type == 'wildcard') ? '可以使用星号(*)通配符,不区分大小写' : '可以使用正则表达式,不区分大小写'" v-model="addingPattern.pattern" size="36" ref="patternInput" @keyup.enter="confirm()" @keypress.enter.prevent="1" spellcheck="false"/>
|
||||
<input type="text" :placeholder="(addingPattern.type == 'wildcard') ? '可以使用星号(*)通配符,不区分大小写' : '可以使用正则表达式,不区分大小写'" v-model="addingPattern.pattern" @input="changePattern" size="36" ref="patternInput" @keyup.enter="confirm()" @keypress.enter.prevent="1" spellcheck="false"/>
|
||||
<p class="comment" v-if="patternIsInvalid"><span class="red" style="font-weight: normal"><span v-if="addingPattern.type == 'wildcard'">通配符</span><span v-if="addingPattern.type == 'regexp'">正则表达式</span>中不能包含问号(?)及问号以后的内容。</span></p>
|
||||
</div>
|
||||
<div class="ui field" style="padding-left: 0">
|
||||
<tip-icon content="通配符示例:<br/>单个路径开头:/hello/world/*<br/>单个路径结尾:*/hello/world<br/>包含某个路径:*/article/*<br/>某个域名下的所有URL:*example.com/*" v-if="addingPattern.type == 'wildcard'"></tip-icon>
|
||||
<tip-icon content="正则表达式示例:<br/>单个路径开头:^/hello/world<br/>单个路径结尾:/hello/world$<br/>包含某个路径:/article/<br/>匹配某个数字路径:/article/(\\d+)<br/>某个域名下的所有URL:^(http|https)://example.com/" v-if="addingPattern.type == 'regexp'"></tip-icon>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button tiny" type="button" @click.prevent="confirm">确定</button><a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
||||
<button class="ui button tiny" :class="{disabled:this.patternIsInvalid}" type="button" @click.prevent="confirm">确定</button><a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -70,6 +70,9 @@ Vue.component("dns-route-selector", {
|
||||
this.routes.$removeIf(function (k, v) {
|
||||
return v.code + "@" + v.domainId == route.code + "@" + route.domainId
|
||||
})
|
||||
},
|
||||
clearKeyword: function () {
|
||||
this.keyword = ""
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -103,16 +106,22 @@ Vue.component("dns-route-selector", {
|
||||
<tr>
|
||||
<td class="title">所有线路</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" v-model="routeCode">
|
||||
<option value="" v-if="keyword.length == 0">[请选择]</option>
|
||||
<option v-for="route in searchingRoutes" :value="route.code + '@' + route.domainId">{{route.name}}({{route.code}}/{{route.domainName}})</option>
|
||||
</select>
|
||||
<span v-if="keyword.length > 0 && searchingRoutes.length == 0">没有和关键词“{{keyword}}”匹配的线路</span>
|
||||
<span v-show="keyword.length == 0 || searchingRoutes.length > 0">
|
||||
<select class="ui dropdown" v-model="routeCode">
|
||||
<option value="" v-if="keyword.length == 0">[请选择]</option>
|
||||
<option v-for="route in searchingRoutes" :value="route.code + '@' + route.domainId">{{route.name}}({{route.code}}/{{route.domainName}})</option>
|
||||
</select>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>搜索</td>
|
||||
<td>搜索线路</td>
|
||||
<td>
|
||||
<input type="text" placeholder="搜索..." size="10" style="width: 10em" v-model="keyword" ref="keywordRef" @keyup.enter="confirm" @keypress.enter.prevent="1"/>
|
||||
<div class="ui input" :class="{'right labeled':keyword.length > 0}">
|
||||
<input type="text" placeholder="线路名称或代号..." size="10" style="width: 10em" v-model="keyword" ref="keywordRef" @keyup.enter="confirm" @keypress.enter.prevent="1"/>
|
||||
<a class="ui label" v-if="keyword.length > 0" @click.prevent="clearKeyword" href=""><i class="icon remove small blue"></i></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -118,10 +118,13 @@ Vue.component("ip-list-table", {
|
||||
<keyword :v-word="keyword">{{item.ipFrom}}</keyword> <span> <span class="small red" v-if="item.isRead != null && !item.isRead"> New </span> <a :href="'/servers/iplists?ip=' + item.ipFrom" v-if="vShowSearchButton" title="搜索此IP"><span><i class="icon search small" style="color: #ccc"></i></span></a></span>
|
||||
<span v-if="item.ipTo.length > 0"> - <keyword :v-word="keyword">{{item.ipTo}}</keyword></span></span>
|
||||
<span v-else class="disabled">*</span>
|
||||
|
||||
<div v-if="item.region != null && item.region.length > 0">
|
||||
<span class="grey small">{{item.region}}</span>
|
||||
<span v-if="item.isp != null && item.isp.length > 0 && item.isp != '内网IP'" class="grey small"><span class="disabled">|</span> {{item.isp}}</span>
|
||||
</div>
|
||||
<div v-else-if="item.isp != null && item.isp.length > 0 && item.isp != '内网IP'"><span class="grey small">{{item.isp}}</span></div>
|
||||
|
||||
<div v-if="item.createdTime != null">
|
||||
<span class="small grey">添加于 {{item.createdTime}}
|
||||
<span v-if="item.list != null && item.list.id > 0">
|
||||
|
||||
@@ -82,7 +82,7 @@ Vue.component("http-access-log-search-box", {
|
||||
<a class="ui label basic" :class="{disabled: keyword.length == 0}" @click.prevent="cleanKeyword"><i class="icon remove small"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field"><tip-icon content="一些特殊的关键词:<br/>单个状态码:status:200<br/>状态码范围:status:500-504<br/>查询IP:ip:192.168.1.100<br/>查询URL:https://goedge.cn/docs<br/>查询路径部分:requestPath:/hello/world<br/>查询协议版本:proto:HTTP/1.1<br/>协议:scheme:http<br/>请求方法:method:POST"></tip-icon></div>
|
||||
<div class="ui field"><tip-icon content="一些特殊的关键词:<br/>单个状态码:status:200<br/>状态码范围:status:500-504<br/>查询IP:ip:192.168.1.100<br/>查询URL:https://goedge.cn/docs<br/>查询路径部分:requestPath:/hello/world<br/>查询协议版本:proto:HTTP/1.1<br/>协议:scheme:http<br/>请求方法:method:POST<br/>请求来源:referer:example.com"></tip-icon></div>
|
||||
</div>
|
||||
<div class="ui fields inline" style="margin-top: 0.5em">
|
||||
<div class="ui field">
|
||||
|
||||
@@ -19,7 +19,7 @@ Vue.component("http-cache-ref-box", {
|
||||
isOn: true,
|
||||
cachePolicyId: 0,
|
||||
key: "${scheme}://${host}${requestPath}${isArgs}${args}",
|
||||
life: {count: 2, unit: "hour"},
|
||||
life: {count: 1, unit: "day"},
|
||||
status: [200],
|
||||
maxSize: {count: 128, unit: "mb"},
|
||||
minSize: {count: 0, unit: "kb"},
|
||||
@@ -176,13 +176,13 @@ Vue.component("http-cache-ref-box", {
|
||||
},
|
||||
template: `<tbody>
|
||||
<tr v-if="condCategory == 'simple'">
|
||||
<td class="title">条件类型 *</td>
|
||||
<td class="title">缓存对象 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="condType" v-model="condType" @change="changeCondType(condType, false)">
|
||||
<option value="url-extension">文件扩展名</option>
|
||||
<option value="url-eq-index">首页</option>
|
||||
<option value="url-all">全站</option>
|
||||
<option value="url-prefix">URL前缀</option>
|
||||
<option value="url-prefix">URL目录前缀</option>
|
||||
<option value="url-eq">URL完整路径</option>
|
||||
<option value="url-wildcard-match">URL通配符</option>
|
||||
<option value="url-regexp">URL正则匹配</option>
|
||||
@@ -220,7 +220,7 @@ Vue.component("http-cache-ref-box", {
|
||||
<tr v-show="!vIsReverse">
|
||||
<td>缓存有效期 *</td>
|
||||
<td>
|
||||
<time-duration-box :v-value="ref.life" @change="changeLife"></time-duration-box>
|
||||
<time-duration-box :v-value="ref.life" @change="changeLife" :v-min-unit="'minute'" maxlength="4"></time-duration-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="!vIsReverse">
|
||||
@@ -231,15 +231,15 @@ Vue.component("http-cache-ref-box", {
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="!vIsReverse">
|
||||
<td colspan="2"><more-options-indicator @change="changeOptionsVisible"></more-options-indicator></td>
|
||||
</tr>
|
||||
<tr v-show="moreOptionsVisible && !vIsReverse">
|
||||
<td>缓存Key *</td>
|
||||
<td>
|
||||
<input type="text" v-model="ref.key" @input="changeKey(ref.key)"/>
|
||||
<p class="comment">用来区分不同缓存内容的唯一Key。<request-variables-describer ref="variablesDescriber"></request-variables-describer>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="!vIsReverse">
|
||||
<td colspan="2"><more-options-indicator @change="changeOptionsVisible"></more-options-indicator></td>
|
||||
</tr>
|
||||
<tr v-show="moreOptionsVisible && !vIsReverse">
|
||||
<td>请求方法限制</td>
|
||||
<td>
|
||||
@@ -309,7 +309,7 @@ Vue.component("http-cache-ref-box", {
|
||||
<input type="checkbox" value="1" v-model="ref.skipSetCookie"/>
|
||||
<label></label>
|
||||
</div>
|
||||
<p class="comment">选中后,当响应的Header中有Set-Cookie时不缓存响应内容。</p>
|
||||
<p class="comment">选中后,当响应的报头中有Set-Cookie时不缓存响应内容,防止动态内容被缓存。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="moreOptionsVisible && !vIsReverse">
|
||||
@@ -319,7 +319,7 @@ Vue.component("http-cache-ref-box", {
|
||||
<input type="checkbox" name="enableRequestCachePragma" value="1" v-model="ref.enableRequestCachePragma"/>
|
||||
<label></label>
|
||||
</div>
|
||||
<p class="comment">选中后,当请求的Header中含有Pragma: no-cache或Cache-Control: no-cache时,会跳过缓存直接读取源内容。</p>
|
||||
<p class="comment">选中后,当请求的报头中含有Pragma: no-cache或Cache-Control: no-cache时,会跳过缓存直接读取源内容,一般仅用于调试。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="moreOptionsVisible && !vIsReverse">
|
||||
|
||||
@@ -54,11 +54,15 @@ Vue.component("http-firewall-actions-box", {
|
||||
}
|
||||
|
||||
var defaultPageBody = `<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<title>403 Forbidden</title>
|
||||
\t<style>
|
||||
\t\taddress { line-height: 1.8; }
|
||||
\t</style>
|
||||
<body>
|
||||
<h1>403 Forbidden</h1>
|
||||
<address>Request ID: \${requestId}.</address>
|
||||
<address>Connection: \${remoteAddr} (Client) -> \${serverAddr} (Server)</address>
|
||||
<address>Request ID: \${requestId}</address>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
@@ -495,9 +499,12 @@ Vue.component("http-firewall-actions-box", {
|
||||
if (isNaN(timeout)) {
|
||||
timeout = 0
|
||||
}
|
||||
if (this.recordIPListId <= 0) {
|
||||
if (this.recordIPListId < 0) {
|
||||
return
|
||||
}
|
||||
|
||||
// recordIPListId can be 0
|
||||
|
||||
this.actionOptions = {
|
||||
type: this.recordIPType,
|
||||
level: this.recordIPLevel,
|
||||
@@ -673,7 +680,7 @@ Vue.component("http-firewall-actions-box", {
|
||||
<span v-if="config.code == 'post_307' && config.options.life > 0">:有效期{{config.options.life}}秒</span>
|
||||
|
||||
<!-- record_ip -->
|
||||
<span v-if="config.code == 'record_ip'">:{{config.options.ipListName}}</span>
|
||||
<span v-if="config.code == 'record_ip'">:<span :class="{red: config.options.ipListIsDeleted}">{{config.options.ipListName}}</span></span>
|
||||
|
||||
<!-- tag -->
|
||||
<span v-if="config.code == 'tag'">:{{config.options.tags.join(", ")}}</span>
|
||||
@@ -845,7 +852,7 @@ Vue.component("http-firewall-actions-box", {
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="actionCode == 'record_ip'">
|
||||
<td>选择IP名单 *</td>
|
||||
<td>选择IP名单</td>
|
||||
<td>
|
||||
<div v-if="recordIPListId > 0" class="ui label basic small">{{recordIPListName}} <a href="" @click.prevent="removeRecordIPList"><i class="icon remove small"></i></a></div>
|
||||
<button type="button" class="ui button tiny" @click.prevent="selectRecordIPList">+</button>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user