1.4.5.2
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
package actionutils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type ActionInterface interface {
|
||||
RPC() *rpc.RPCClient
|
||||
|
||||
AdminContext() context.Context
|
||||
|
||||
ViewData() maps.Map
|
||||
}
|
||||
22
EdgeAdmin/internal/web/actions/actionutils/csrf.go
Normal file
22
EdgeAdmin/internal/web/actions/actionutils/csrf.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package actionutils
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/csrf"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type CSRF struct {
|
||||
}
|
||||
|
||||
func (this *CSRF) BeforeAction(actionPtr actions.ActionWrapper, paramName string) (goNext bool) {
|
||||
action := actionPtr.Object()
|
||||
token := action.ParamString("csrfToken")
|
||||
if !csrf.Validate(token) {
|
||||
action.ResponseWriter.WriteHeader(http.StatusForbidden)
|
||||
action.WriteString("表单已失效,请刷新页面后重试(001)")
|
||||
return
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
44
EdgeAdmin/internal/web/actions/actionutils/menu.go
Normal file
44
EdgeAdmin/internal/web/actions/actionutils/menu.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package actionutils
|
||||
|
||||
// Menu 子菜单定义
|
||||
type Menu struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Items []*MenuItem `json:"items"`
|
||||
IsActive bool `json:"isActive"`
|
||||
AlwaysActive bool `json:"alwaysActive"`
|
||||
Index int `json:"index"`
|
||||
CountNormalItems int `json:"countNormalItems"`
|
||||
}
|
||||
|
||||
// NewMenu 获取新对象
|
||||
func NewMenu() *Menu {
|
||||
return &Menu{
|
||||
Items: []*MenuItem{},
|
||||
}
|
||||
}
|
||||
|
||||
// Add 添加菜单项
|
||||
func (this *Menu) Add(name string, subName string, url string, isActive bool) *MenuItem {
|
||||
item := &MenuItem{
|
||||
Name: name,
|
||||
SubName: subName,
|
||||
URL: url,
|
||||
IsActive: isActive,
|
||||
}
|
||||
this.CountNormalItems++
|
||||
this.Items = append(this.Items, item)
|
||||
|
||||
if isActive {
|
||||
this.IsActive = true
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
// AddSpecial 添加特殊菜单项,不计数
|
||||
func (this *Menu) AddSpecial(name string, subName string, url string, isActive bool) *MenuItem {
|
||||
item := this.Add(name, subName, url, isActive)
|
||||
this.CountNormalItems--
|
||||
return item
|
||||
}
|
||||
48
EdgeAdmin/internal/web/actions/actionutils/menu_group.go
Normal file
48
EdgeAdmin/internal/web/actions/actionutils/menu_group.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package actionutils
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
)
|
||||
|
||||
// MenuGroup 菜单分组
|
||||
type MenuGroup struct {
|
||||
Menus []*Menu `json:"menus"`
|
||||
AlwaysMenu *Menu `json:"alwaysMenu"`
|
||||
}
|
||||
|
||||
// NewMenuGroup 获取新菜单分组对象
|
||||
func NewMenuGroup() *MenuGroup {
|
||||
return &MenuGroup{
|
||||
Menus: []*Menu{},
|
||||
}
|
||||
}
|
||||
|
||||
// FindMenu 查找菜单,如果找不到则自动创建
|
||||
func (this *MenuGroup) FindMenu(menuId string, menuName string) *Menu {
|
||||
for _, m := range this.Menus {
|
||||
if m.Id == menuId {
|
||||
return m
|
||||
}
|
||||
}
|
||||
menu := NewMenu()
|
||||
menu.Id = menuId
|
||||
menu.Name = menuName
|
||||
menu.Items = []*MenuItem{}
|
||||
this.Menus = append(this.Menus, menu)
|
||||
return menu
|
||||
}
|
||||
|
||||
// Sort 排序
|
||||
func (this *MenuGroup) Sort() {
|
||||
lists.Sort(this.Menus, func(i int, j int) bool {
|
||||
menu1 := this.Menus[i]
|
||||
menu2 := this.Menus[j]
|
||||
return menu1.Index < menu2.Index
|
||||
})
|
||||
}
|
||||
|
||||
// SetSubMenu 设置子菜单
|
||||
func SetSubMenu(action actions.ActionWrapper, menu *MenuGroup) {
|
||||
action.Object().Data["teaSubMenus"] = menu
|
||||
}
|
||||
14
EdgeAdmin/internal/web/actions/actionutils/menu_item.go
Normal file
14
EdgeAdmin/internal/web/actions/actionutils/menu_item.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package actionutils
|
||||
|
||||
// MenuItem 菜单项
|
||||
type MenuItem struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
SubName string `json:"subName"` // 副标题
|
||||
SupName string `json:"supName"` // 头标
|
||||
URL string `json:"url"`
|
||||
IsActive bool `json:"isActive"`
|
||||
Icon string `json:"icon"`
|
||||
IsSortable bool `json:"isSortable"`
|
||||
SubColor string `json:"subColor"`
|
||||
}
|
||||
161
EdgeAdmin/internal/web/actions/actionutils/page.go
Normal file
161
EdgeAdmin/internal/web/actions/actionutils/page.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package actionutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"math"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Page struct {
|
||||
Offset int64 // 开始位置
|
||||
Size int64 // 每页显示数量
|
||||
Current int64 // 当前页码
|
||||
Max int64 // 最大页码
|
||||
Total int64 // 总数量
|
||||
|
||||
Path string
|
||||
Query url.Values
|
||||
}
|
||||
|
||||
func NewActionPage(actionPtr actions.ActionWrapper, total int64, size int64) *Page {
|
||||
action := actionPtr.Object()
|
||||
currentPage := action.ParamInt64("page")
|
||||
|
||||
paramSize := action.ParamInt64("pageSize")
|
||||
if paramSize > 0 {
|
||||
size = paramSize
|
||||
}
|
||||
|
||||
if size <= 0 {
|
||||
size = 10
|
||||
}
|
||||
|
||||
page := &Page{
|
||||
Current: currentPage,
|
||||
Total: total,
|
||||
Size: size,
|
||||
Path: action.Request.URL.Path,
|
||||
Query: action.Request.URL.Query(),
|
||||
}
|
||||
page.calculate()
|
||||
return page
|
||||
}
|
||||
|
||||
func (this *Page) calculate() {
|
||||
if this.Current < 1 {
|
||||
this.Current = 1
|
||||
}
|
||||
if this.Size <= 0 {
|
||||
this.Size = 10
|
||||
}
|
||||
|
||||
this.Offset = this.Size * (this.Current - 1)
|
||||
this.Max = int64(math.Ceil(float64(this.Total) / float64(this.Size)))
|
||||
}
|
||||
|
||||
func (this *Page) AsHTML() string {
|
||||
if this.Total <= this.Size {
|
||||
return ""
|
||||
}
|
||||
|
||||
result := []string{}
|
||||
|
||||
// 首页
|
||||
if this.Max > 0 {
|
||||
result = append(result, `<a href="`+this.composeURL(1)+`">首页</a>`)
|
||||
} else {
|
||||
result = append(result, `<a>首页</a>`)
|
||||
}
|
||||
|
||||
// 上一页
|
||||
if this.Current <= 1 {
|
||||
result = append(result, `<a>上一页</a>`)
|
||||
} else {
|
||||
result = append(result, `<a href="`+this.composeURL(this.Current-1)+`">上一页</a>`)
|
||||
}
|
||||
|
||||
// 中间页数
|
||||
before5 := this.max(this.Current-5, 1)
|
||||
after5 := this.min(before5+9, this.Max)
|
||||
|
||||
if before5 > 1 {
|
||||
result = append(result, `<a>...</a>`)
|
||||
}
|
||||
|
||||
for i := before5; i <= after5; i++ {
|
||||
if i == this.Current {
|
||||
result = append(result, `<a href="`+this.composeURL(i)+`" class="active">`+fmt.Sprintf("%d", i)+`</a>`)
|
||||
} else {
|
||||
result = append(result, `<a href="`+this.composeURL(i)+`">`+fmt.Sprintf("%d", i)+`</a>`)
|
||||
}
|
||||
}
|
||||
|
||||
if after5 < this.Max {
|
||||
result = append(result, `<a>...</a>`)
|
||||
}
|
||||
|
||||
// 下一页
|
||||
if this.Current >= this.Max {
|
||||
result = append(result, "<a>下一页</a>")
|
||||
} else {
|
||||
result = append(result, `<a href="`+this.composeURL(this.Current+1)+`">下一页</a>`)
|
||||
}
|
||||
|
||||
// 尾页
|
||||
if this.Max > 0 {
|
||||
result = append(result, `<a href="`+this.composeURL(this.Max)+`">尾页</a>`)
|
||||
} else {
|
||||
result = append(result, `<a>尾页</a>`)
|
||||
}
|
||||
|
||||
// 每页数
|
||||
result = append(result, `<select class="ui dropdown" style="padding-top:0;padding-bottom:0;margin-left:1em;color:#666" onchange="ChangePageSize(this.value)">
|
||||
<option value="10">[每页]</option>`+this.renderSizeOption(10)+
|
||||
this.renderSizeOption(20)+
|
||||
this.renderSizeOption(30)+
|
||||
this.renderSizeOption(40)+
|
||||
this.renderSizeOption(50)+
|
||||
this.renderSizeOption(60)+
|
||||
this.renderSizeOption(70)+
|
||||
this.renderSizeOption(80)+
|
||||
this.renderSizeOption(90)+
|
||||
this.renderSizeOption(100)+`
|
||||
</select>`)
|
||||
|
||||
return `<div class="page">` + strings.Join(result, "") + `</div>`
|
||||
}
|
||||
|
||||
// IsLastPage 判断是否为最后一页
|
||||
func (this *Page) IsLastPage() bool {
|
||||
return this.Current == this.Max
|
||||
}
|
||||
|
||||
func (this *Page) composeURL(page int64) string {
|
||||
this.Query["page"] = []string{fmt.Sprintf("%d", page)}
|
||||
return this.Path + "?" + this.Query.Encode()
|
||||
}
|
||||
|
||||
func (this *Page) min(i, j int64) int64 {
|
||||
if i < j {
|
||||
return i
|
||||
}
|
||||
return j
|
||||
}
|
||||
|
||||
func (this *Page) max(i, j int64) int64 {
|
||||
if i < j {
|
||||
return j
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func (this *Page) renderSizeOption(size int64) string {
|
||||
o := `<option value="` + fmt.Sprintf("%d", size) + `"`
|
||||
if size == this.Size {
|
||||
o += ` selected="selected"`
|
||||
}
|
||||
o += `>` + fmt.Sprintf("%d", size) + `条</option>`
|
||||
return o
|
||||
}
|
||||
40
EdgeAdmin/internal/web/actions/actionutils/page_test.go
Normal file
40
EdgeAdmin/internal/web/actions/actionutils/page_test.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package actionutils
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewActionPage(t *testing.T) {
|
||||
page := &Page{
|
||||
Current: 3,
|
||||
Total: 105,
|
||||
Size: 20,
|
||||
Path: "/hello",
|
||||
Query: url.Values{
|
||||
"a": []string{"b"},
|
||||
"c": []string{"d"},
|
||||
"page": []string{"3"},
|
||||
},
|
||||
}
|
||||
page.calculate()
|
||||
t.Log(page.AsHTML())
|
||||
//logs.PrintAsJSON(page, t)
|
||||
}
|
||||
|
||||
func TestNewActionPage2(t *testing.T) {
|
||||
page := &Page{
|
||||
Current: 3,
|
||||
Total: 105,
|
||||
Size: 10,
|
||||
Path: "/hello",
|
||||
Query: url.Values{
|
||||
"a": []string{"b"},
|
||||
"c": []string{"d"},
|
||||
"page": []string{"3"},
|
||||
},
|
||||
}
|
||||
page.calculate()
|
||||
t.Log(page.AsHTML())
|
||||
//logs.PrintAsJSON(page, t)
|
||||
}
|
||||
182
EdgeAdmin/internal/web/actions/actionutils/parent_action.go
Normal file
182
EdgeAdmin/internal/web/actions/actionutils/parent_action.go
Normal file
@@ -0,0 +1,182 @@
|
||||
package actionutils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/index/loginutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type ParentAction struct {
|
||||
actions.ActionObject
|
||||
|
||||
rpcClient *rpc.RPCClient
|
||||
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// Parent 可以调用自身的一个简便方法
|
||||
func (this *ParentAction) Parent() *ParentAction {
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *ParentAction) ErrorPage(err error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 日志
|
||||
this.CreateLog(oplogs.LevelError, codes.AdminCommon_LogSystemError, err.Error())
|
||||
|
||||
if this.Request.Method == http.MethodGet {
|
||||
FailPage(this, err)
|
||||
} else {
|
||||
Fail(this, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *ParentAction) ErrorText(err string) {
|
||||
this.ErrorPage(errors.New(err))
|
||||
}
|
||||
|
||||
func (this *ParentAction) NotFound(name string, itemId int64) {
|
||||
if itemId > 0 {
|
||||
this.ErrorPage(errors.New(name + " id: '" + strconv.FormatInt(itemId, 10) + "' is not found"))
|
||||
} else {
|
||||
this.ErrorPage(errors.New(name + " is not found"))
|
||||
}
|
||||
}
|
||||
|
||||
func (this *ParentAction) NewPage(total int64, size ...int64) *Page {
|
||||
if len(size) > 0 {
|
||||
return NewActionPage(this, total, size[0])
|
||||
}
|
||||
|
||||
var pageSize int64 = 10
|
||||
adminConfig, err := configloaders.LoadAdminUIConfig()
|
||||
if err == nil && adminConfig.DefaultPageSize > 0 {
|
||||
pageSize = int64(adminConfig.DefaultPageSize)
|
||||
}
|
||||
|
||||
return NewActionPage(this, total, pageSize)
|
||||
}
|
||||
|
||||
func (this *ParentAction) Nav(mainMenu string, tab string, firstMenu string) {
|
||||
this.Data["mainMenu"] = mainMenu
|
||||
this.Data["mainTab"] = tab
|
||||
this.Data["firstMenuItem"] = firstMenu
|
||||
}
|
||||
|
||||
func (this *ParentAction) FirstMenu(menuItem string) {
|
||||
this.Data["firstMenuItem"] = menuItem
|
||||
}
|
||||
|
||||
func (this *ParentAction) SecondMenu(menuItem string) {
|
||||
this.Data["secondMenuItem"] = menuItem
|
||||
}
|
||||
|
||||
func (this *ParentAction) TinyMenu(menuItem string) {
|
||||
this.Data["tinyMenuItem"] = menuItem
|
||||
}
|
||||
|
||||
func (this *ParentAction) AdminId() int64 {
|
||||
return this.Context.GetInt64(teaconst.SessionAdminId)
|
||||
}
|
||||
|
||||
func (this *ParentAction) CreateLog(level string, messageCode langs.MessageCode, args ...any) {
|
||||
var description = messageCode.For(this.LangCode())
|
||||
var desc = fmt.Sprintf(description, args...)
|
||||
if level == oplogs.LevelInfo {
|
||||
if this.Code != 200 {
|
||||
level = oplogs.LevelWarn
|
||||
if len(this.Message) > 0 {
|
||||
desc += " 失败:" + this.Message
|
||||
}
|
||||
}
|
||||
}
|
||||
err := dao.SharedLogDAO.CreateAdminLog(this.AdminContext(), level, this.Request.URL.Path, desc, loginutils.RemoteIP(&this.ActionObject), messageCode, args)
|
||||
if err != nil {
|
||||
utils.PrintError(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *ParentAction) CreateLogInfo(messageCode langs.MessageCode, args ...any) {
|
||||
this.CreateLog(oplogs.LevelInfo, messageCode, args...)
|
||||
}
|
||||
|
||||
// RPC 获取RPC
|
||||
func (this *ParentAction) RPC() *rpc.RPCClient {
|
||||
if this.rpcClient != nil {
|
||||
return this.rpcClient
|
||||
}
|
||||
|
||||
// 所有集群
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
logs.Fatal(err)
|
||||
return nil
|
||||
}
|
||||
this.rpcClient = rpcClient
|
||||
|
||||
return rpcClient
|
||||
}
|
||||
|
||||
// AdminContext 获取Context
|
||||
// 每个请求的context都必须是一个新的实例
|
||||
func (this *ParentAction) AdminContext() context.Context {
|
||||
if this.rpcClient == nil {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
logs.Fatal(err)
|
||||
return nil
|
||||
}
|
||||
this.rpcClient = rpcClient
|
||||
}
|
||||
this.ctx = this.rpcClient.Context(this.AdminId())
|
||||
return this.ctx
|
||||
}
|
||||
|
||||
// ViewData 视图里可以使用的数据
|
||||
func (this *ParentAction) ViewData() maps.Map {
|
||||
return this.Data
|
||||
}
|
||||
|
||||
func (this *ParentAction) LangCode() string {
|
||||
return configloaders.FindAdminLangForAction(this)
|
||||
}
|
||||
|
||||
func (this *ParentAction) Lang(messageCode langs.MessageCode, args ...any) string {
|
||||
return langs.Message(this.LangCode(), messageCode, args...)
|
||||
}
|
||||
|
||||
func (this *ParentAction) FailLang(messageCode langs.MessageCode, args ...any) {
|
||||
this.Fail(langs.Message(this.LangCode(), messageCode, args...))
|
||||
}
|
||||
|
||||
func (this *ParentAction) FailFieldLang(field string, messageCode langs.MessageCode, args ...any) {
|
||||
this.FailField(field, langs.Message(this.LangCode(), messageCode, args...))
|
||||
}
|
||||
|
||||
func (this *ParentAction) FilterHTTPFamily() bool {
|
||||
if this.Data.GetString("serverFamily") == "http" {
|
||||
return false
|
||||
}
|
||||
|
||||
this.ResponseWriter.WriteHeader(http.StatusNotFound)
|
||||
_, _ = this.ResponseWriter.Write([]byte("page not found"))
|
||||
|
||||
return true
|
||||
}
|
||||
54
EdgeAdmin/internal/web/actions/actionutils/tabbar.go
Normal file
54
EdgeAdmin/internal/web/actions/actionutils/tabbar.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package actionutils
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type TabItem struct {
|
||||
Name string `json:"name"`
|
||||
SubName string `json:"subName"`
|
||||
URL string `json:"url"`
|
||||
Icon string `json:"icon"`
|
||||
IsActive bool `json:"isActive"`
|
||||
IsRight bool `json:"isRight"`
|
||||
IsTitle bool `json:"isTitle"`
|
||||
IsDisabled bool `json:"isDisabled"`
|
||||
}
|
||||
|
||||
// Tabbar Tabbar定义
|
||||
type Tabbar struct {
|
||||
items []*TabItem
|
||||
}
|
||||
|
||||
// NewTabbar 获取新对象
|
||||
func NewTabbar() *Tabbar {
|
||||
return &Tabbar{
|
||||
items: []*TabItem{},
|
||||
}
|
||||
}
|
||||
|
||||
// Add 添加菜单项
|
||||
func (this *Tabbar) Add(name string, subName string, url string, icon string, active bool) *TabItem {
|
||||
var m = &TabItem{
|
||||
Name: name,
|
||||
SubName: subName,
|
||||
URL: url,
|
||||
Icon: icon,
|
||||
IsActive: active,
|
||||
IsRight: false,
|
||||
IsTitle: false,
|
||||
IsDisabled: false,
|
||||
}
|
||||
this.items = append(this.items, m)
|
||||
return m
|
||||
}
|
||||
|
||||
// Items 取得所有的Items
|
||||
func (this *Tabbar) Items() []*TabItem {
|
||||
return this.items
|
||||
}
|
||||
|
||||
// SetTabbar 设置子菜单
|
||||
func SetTabbar(action actions.ActionWrapper, tabbar *Tabbar) {
|
||||
action.Object().Data["teaTabbar"] = tabbar.Items()
|
||||
}
|
||||
208
EdgeAdmin/internal/web/actions/actionutils/utils.go
Normal file
208
EdgeAdmin/internal/web/actions/actionutils/utils.go
Normal file
@@ -0,0 +1,208 @@
|
||||
package actionutils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
rpcerrors "github.com/TeaOSLab/EdgeCommon/pkg/rpc/errors"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/gosock/pkg/gosock"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Fail 提示服务器错误信息
|
||||
func Fail(actionPtr actions.ActionWrapper, err error) {
|
||||
if err == nil {
|
||||
err = errors.New("unknown error")
|
||||
}
|
||||
|
||||
var langCode = configloaders.FindAdminLangForAction(actionPtr)
|
||||
var serverErrString = codes.AdminCommon_ServerError.For(langCode)
|
||||
|
||||
logs.Println("[" + reflect.TypeOf(actionPtr).String() + "]" + findStack(err.Error()))
|
||||
|
||||
_, _, isLocalAPI, issuesHTML := parseAPIErr(actionPtr, err)
|
||||
if isLocalAPI && len(issuesHTML) > 0 {
|
||||
actionPtr.Object().Fail(serverErrString + "(" + err.Error() + ";最近一次错误提示:" + issuesHTML + ")")
|
||||
} else {
|
||||
actionPtr.Object().Fail(serverErrString + "(" + err.Error() + ")")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// FailPage 提示页面错误信息
|
||||
func FailPage(actionPtr actions.ActionWrapper, err error) {
|
||||
if err == nil {
|
||||
err = errors.New("unknown error")
|
||||
}
|
||||
|
||||
var langCode = configloaders.FindAdminLangForAction(actionPtr)
|
||||
var serverErrString = codes.AdminCommon_ServerError.For(langCode)
|
||||
|
||||
logs.Println("[" + reflect.TypeOf(actionPtr).String() + "]" + findStack(err.Error()))
|
||||
|
||||
actionPtr.Object().ResponseWriter.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
if len(actionPtr.Object().Request.Header.Get("X-Requested-With")) > 0 {
|
||||
actionPtr.Object().WriteString(serverErrString)
|
||||
} else {
|
||||
apiNodeIsStarting, apiNodeProgress, _, issuesHTML := parseAPIErr(actionPtr, err)
|
||||
var html = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>正在处理...</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<style type="text/css">
|
||||
hr { border-top: 1px #ccc solid; }
|
||||
.red { color: red; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="background: #eee; border: 1px #ccc solid; padding: 10px; font-size: 12px; line-height: 1.8">
|
||||
`
|
||||
if apiNodeIsStarting { // API节点正在启动
|
||||
html += "<div class=\"red\">API节点正在启动,请耐心等待完成"
|
||||
|
||||
if len(apiNodeProgress) > 0 {
|
||||
html += ":" + apiNodeProgress + "(刷新当前页面查看最新状态)"
|
||||
}
|
||||
|
||||
html += "</div>"
|
||||
} else {
|
||||
html += serverErrString + `
|
||||
<div>可以通过查看 <strong><em>$安装目录/logs/run.log</em></strong> 日志文件查看具体的错误提示。</div>
|
||||
<hr/>
|
||||
<div class="red">Error: ` + err.Error() + `</div>`
|
||||
|
||||
if len(issuesHTML) > 0 {
|
||||
html += ` <hr/>
|
||||
<div class="red">` + issuesHTML + `</div>`
|
||||
}
|
||||
}
|
||||
|
||||
actionPtr.Object().WriteString(html + `
|
||||
</div>
|
||||
</body>
|
||||
</html>`)
|
||||
}
|
||||
}
|
||||
|
||||
// MatchPath 判断动作的文件路径是否相当
|
||||
func MatchPath(action *actions.ActionObject, path string) bool {
|
||||
return action.Request.URL.Path == path
|
||||
}
|
||||
|
||||
// FindParentAction 查找父级Action
|
||||
func FindParentAction(actionPtr actions.ActionWrapper) *ParentAction {
|
||||
action, ok := actionPtr.(interface {
|
||||
Parent() *ParentAction
|
||||
})
|
||||
if ok {
|
||||
return action.Parent()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func findStack(err string) string {
|
||||
_, currentFilename, _, currentOk := runtime.Caller(1)
|
||||
if currentOk {
|
||||
for i := 1; i < 32; i++ {
|
||||
_, filename, lineNo, ok := runtime.Caller(i)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
if filename == currentFilename || filepath.Base(filename) == "parent_action.go" {
|
||||
continue
|
||||
}
|
||||
|
||||
goPath := os.Getenv("GOPATH")
|
||||
if len(goPath) > 0 {
|
||||
absGoPath, err := filepath.Abs(goPath)
|
||||
if err == nil {
|
||||
filename = strings.TrimPrefix(filename, absGoPath)[1:]
|
||||
}
|
||||
} else if strings.Contains(filename, "src") {
|
||||
filename = filename[strings.Index(filename, "src"):]
|
||||
}
|
||||
|
||||
err += "\n\t\t" + filename + ":" + fmt.Sprintf("%d", lineNo)
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// 分析API节点的错误信息
|
||||
func parseAPIErr(action actions.ActionWrapper, err error) (apiNodeIsStarting bool, apiNodeProgress string, isLocalAPI bool, issuesHTML string) {
|
||||
// 当前API终端地址
|
||||
var apiEndpoints = []string{}
|
||||
apiConfig, apiConfigErr := configs.LoadAPIConfig()
|
||||
if apiConfigErr == nil && apiConfig != nil {
|
||||
apiEndpoints = append(apiEndpoints, apiConfig.RPCEndpoints...)
|
||||
}
|
||||
|
||||
var isRPCConnError bool
|
||||
_, isRPCConnError = rpcerrors.HumanError(err, apiEndpoints, Tea.ConfigFile(configs.ConfigFileName))
|
||||
if isRPCConnError {
|
||||
// API节点是否正在启动
|
||||
var sock = gosock.NewTmpSock("edge-api")
|
||||
reply, err := sock.SendTimeout(&gosock.Command{
|
||||
Code: "starting",
|
||||
Params: nil,
|
||||
}, 1*time.Second)
|
||||
if err == nil && reply != nil {
|
||||
var params = maps.NewMap(reply.Params)
|
||||
if params.GetBool("isStarting") {
|
||||
apiNodeIsStarting = true
|
||||
|
||||
var progressMap = params.GetMap("progress")
|
||||
apiNodeProgress = progressMap.GetString("description")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 本地的一些错误提示
|
||||
if isRPCConnError {
|
||||
host, _, hostErr := net.SplitHostPort(action.Object().Request.Host)
|
||||
if hostErr == nil {
|
||||
for _, endpoint := range apiEndpoints {
|
||||
if strings.HasPrefix(endpoint, "http://"+host) || strings.HasPrefix(endpoint, "https://"+host) || strings.HasPrefix(endpoint, host) {
|
||||
isLocalAPI = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isLocalAPI {
|
||||
// 读取本地API节点的issues
|
||||
issuesData, issuesErr := os.ReadFile(Tea.Root + "/edge-api/logs/issues.log")
|
||||
if issuesErr == nil {
|
||||
var issueMaps = []maps.Map{}
|
||||
issuesErr = json.Unmarshal(issuesData, &issueMaps)
|
||||
if issuesErr == nil && len(issueMaps) > 0 {
|
||||
var issueMap = issueMaps[0]
|
||||
issuesHTML = "本地API节点启动错误:" + issueMap.GetString("message") + ",处理建议:" + issueMap.GetString("suggestion")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
12
EdgeAdmin/internal/web/actions/default/about/init.go
Normal file
12
EdgeAdmin/internal/web/actions/default/about/init.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package about
|
||||
|
||||
import "github.com/iwind/TeaGo"
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Prefix("/about").
|
||||
Get("/qq", new(QqAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
15
EdgeAdmin/internal/web/actions/default/about/qq.go
Normal file
15
EdgeAdmin/internal/web/actions/default/about/qq.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package about
|
||||
|
||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
|
||||
type QqAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *QqAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *QqAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accesskeys
|
||||
|
||||
import (
|
||||
"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"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct {
|
||||
AdminId int64
|
||||
}) {
|
||||
this.Data["adminId"] = params.AdminId
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
AdminId int64
|
||||
Description string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("description", params.Description).
|
||||
Require("请输入备注")
|
||||
|
||||
accessKeyIdResp, err := this.RPC().UserAccessKeyRPC().CreateUserAccessKey(this.AdminContext(), &pb.CreateUserAccessKeyRequest{
|
||||
AdminId: params.AdminId,
|
||||
Description: params.Description,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
defer this.CreateLogInfo(codes.UserAccessKey_LogCreateUserAccessKey, accessKeyIdResp.UserAccessKeyId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package accesskeys
|
||||
|
||||
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 {
|
||||
AccessKeyId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.UserAccessKey_LogDeleteUserAccessKey, params.AccessKeyId)
|
||||
|
||||
_, err := this.RPC().UserAccessKeyRPC().DeleteUserAccessKey(this.AdminContext(), &pb.DeleteUserAccessKeyRequest{UserAccessKeyId: params.AccessKeyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package accesskeys
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/admins/adminutils"
|
||||
"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("", "", "accessKey")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
AdminId int64
|
||||
}) {
|
||||
err := adminutils.InitAdmin(this.Parent(), params.AdminId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
accessKeysResp, err := this.RPC().UserAccessKeyRPC().FindAllEnabledUserAccessKeys(this.AdminContext(), &pb.FindAllEnabledUserAccessKeysRequest{AdminId: params.AdminId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
accessKeyMaps := []maps.Map{}
|
||||
for _, accessKey := range accessKeysResp.UserAccessKeys {
|
||||
var accessedTime string
|
||||
if accessKey.AccessedAt > 0 {
|
||||
accessedTime = timeutil.FormatTime("Y-m-d H:i:s", accessKey.AccessedAt)
|
||||
}
|
||||
accessKeyMaps = append(accessKeyMaps, maps.Map{
|
||||
"id": accessKey.Id,
|
||||
"isOn": accessKey.IsOn,
|
||||
"uniqueId": accessKey.UniqueId,
|
||||
"secret": accessKey.Secret,
|
||||
"description": accessKey.Description,
|
||||
"accessedTime": accessedTime,
|
||||
})
|
||||
}
|
||||
this.Data["accessKeys"] = accessKeyMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package accesskeys
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type UpdateIsOnAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateIsOnAction) RunPost(params struct {
|
||||
AccessKeyId int64
|
||||
IsOn bool
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.UserAccessKey_LogUpdateUserAccessKeyIsOn, params.AccessKeyId)
|
||||
|
||||
_, err := this.RPC().UserAccessKeyRPC().UpdateUserAccessKeyIsOn(this.AdminContext(), &pb.UpdateUserAccessKeyIsOnRequest{
|
||||
UserAccessKeyId: params.AccessKeyId,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
85
EdgeAdmin/internal/web/actions/default/admins/admin.go
Normal file
85
EdgeAdmin/internal/web/actions/default/admins/admin.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package admins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type AdminAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *AdminAction) Init() {
|
||||
this.Nav("", "", "index")
|
||||
}
|
||||
|
||||
func (this *AdminAction) RunGet(params struct {
|
||||
AdminId int64
|
||||
}) {
|
||||
adminResp, err := this.RPC().AdminRPC().FindEnabledAdmin(this.AdminContext(), &pb.FindEnabledAdminRequest{AdminId: params.AdminId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
admin := adminResp.Admin
|
||||
if admin == nil {
|
||||
this.NotFound("admin", params.AdminId)
|
||||
return
|
||||
}
|
||||
|
||||
// AccessKey数量
|
||||
countAccessKeyResp, err := this.RPC().UserAccessKeyRPC().CountAllEnabledUserAccessKeys(this.AdminContext(), &pb.CountAllEnabledUserAccessKeysRequest{AdminId: params.AdminId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countAccessKeys := countAccessKeyResp.Count
|
||||
|
||||
this.Data["admin"] = maps.Map{
|
||||
"id": admin.Id,
|
||||
"fullname": admin.Fullname,
|
||||
"username": admin.Username,
|
||||
"isOn": admin.IsOn,
|
||||
"isSuper": admin.IsSuper,
|
||||
"canLogin": admin.CanLogin,
|
||||
"hasWeakPassword": admin.HasWeakPassword,
|
||||
"countAccessKeys": countAccessKeys,
|
||||
}
|
||||
|
||||
// 权限
|
||||
moduleMaps := []maps.Map{}
|
||||
for _, m := range configloaders.AllModuleMaps(this.LangCode()) {
|
||||
code := m.GetString("code")
|
||||
isChecked := false
|
||||
for _, module := range admin.Modules {
|
||||
if module.Code == code {
|
||||
isChecked = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if isChecked {
|
||||
moduleMaps = append(moduleMaps, m)
|
||||
}
|
||||
}
|
||||
this.Data["modules"] = moduleMaps
|
||||
|
||||
// OTP
|
||||
this.Data["otp"] = nil
|
||||
if admin.OtpLogin != nil && admin.OtpLogin.IsOn {
|
||||
loginParams := maps.Map{}
|
||||
err = json.Unmarshal(admin.OtpLogin.ParamsJSON, &loginParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["otp"] = maps.Map{
|
||||
"isOn": true,
|
||||
"params": loginParams,
|
||||
}
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package adminutils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// InitAdmin 查找管理员基本信息
|
||||
func InitAdmin(p *actionutils.ParentAction, adminId int64) error {
|
||||
// 管理员信息
|
||||
resp, err := p.RPC().AdminRPC().FindEnabledAdmin(p.AdminContext(), &pb.FindEnabledAdminRequest{AdminId: adminId})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Admin == nil {
|
||||
return errors.New("not found admin")
|
||||
}
|
||||
var admin = resp.Admin
|
||||
|
||||
// AccessKey数量
|
||||
countAccessKeysResp, err := p.RPC().UserAccessKeyRPC().CountAllEnabledUserAccessKeys(p.AdminContext(), &pb.CountAllEnabledUserAccessKeysRequest{
|
||||
AdminId: adminId,
|
||||
UserId: 0,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Data["admin"] = maps.Map{
|
||||
"id": admin.Id,
|
||||
"username": admin.Username,
|
||||
"fullname": admin.Fullname,
|
||||
"countAccessKeys": countAccessKeysResp.Count,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
128
EdgeAdmin/internal/web/actions/default/admins/createPopup.go
Normal file
128
EdgeAdmin/internal/web/actions/default/admins/createPopup.go
Normal file
@@ -0,0 +1,128 @@
|
||||
package admins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"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/systemconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/xlzd/gotp"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct{}) {
|
||||
this.Data["modules"] = configloaders.AllModuleMaps(this.LangCode())
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Fullname string
|
||||
Username string
|
||||
Pass1 string
|
||||
Pass2 string
|
||||
ModuleCodes []string
|
||||
IsSuper bool
|
||||
CanLogin bool
|
||||
|
||||
// OTP
|
||||
OtpOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("fullname", params.Fullname).
|
||||
Require("请输入系统用户全名")
|
||||
|
||||
params.Must.
|
||||
Field("username", params.Username).
|
||||
Require("请输入登录用户名").
|
||||
Match(`^[a-zA-Z0-9_]+$`, "用户名中只能包含英文、数字或下划线")
|
||||
|
||||
existsResp, err := this.RPC().AdminRPC().CheckAdminUsername(this.AdminContext(), &pb.CheckAdminUsernameRequest{
|
||||
AdminId: 0,
|
||||
Username: params.Username,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if existsResp.Exists {
|
||||
this.FailField("username", "此用户名已经被别的系统用户使用,请换一个")
|
||||
}
|
||||
|
||||
params.Must.
|
||||
Field("pass1", params.Pass1).
|
||||
Require("请输入登录密码").
|
||||
Field("pass2", params.Pass2).
|
||||
Require("请输入确认登录密码")
|
||||
if params.Pass1 != params.Pass2 {
|
||||
this.FailField("pass2", "两次输入的密码不一致")
|
||||
}
|
||||
|
||||
modules := []*systemconfigs.AdminModule{}
|
||||
for _, code := range params.ModuleCodes {
|
||||
modules = append(modules, &systemconfigs.AdminModule{
|
||||
Code: code,
|
||||
AllowAll: true,
|
||||
Actions: nil, // TODO 后期再开放细粒度控制
|
||||
})
|
||||
}
|
||||
modulesJSON, err := json.Marshal(modules)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().AdminRPC().CreateAdmin(this.AdminContext(), &pb.CreateAdminRequest{
|
||||
Username: params.Username,
|
||||
Password: params.Pass1,
|
||||
Fullname: params.Fullname,
|
||||
ModulesJSON: modulesJSON,
|
||||
IsSuper: params.IsSuper,
|
||||
CanLogin: params.CanLogin,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// OTP
|
||||
if params.OtpOn {
|
||||
_, err = this.RPC().LoginRPC().UpdateLogin(this.AdminContext(), &pb.UpdateLoginRequest{Login: &pb.Login{
|
||||
Id: 0,
|
||||
Type: "otp",
|
||||
ParamsJSON: maps.Map{
|
||||
"secret": gotp.RandomSecret(16), // TODO 改成可以设置secret长度
|
||||
}.AsJSON(),
|
||||
IsOn: true,
|
||||
AdminId: createResp.AdminId,
|
||||
UserId: 0,
|
||||
}})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
defer this.CreateLogInfo(codes.Admin_LogCreateAdmin, createResp.AdminId)
|
||||
|
||||
// 通知更改
|
||||
err = configloaders.NotifyAdminModuleMappingChange()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
33
EdgeAdmin/internal/web/actions/default/admins/delete.go
Normal file
33
EdgeAdmin/internal/web/actions/default/admins/delete.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package admins
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"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 {
|
||||
AdminId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.Admin_LogDeleteAdmin, params.AdminId)
|
||||
|
||||
_, err := this.RPC().AdminRPC().DeleteAdmin(this.AdminContext(), &pb.DeleteAdminRequest{AdminId: params.AdminId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 通知更改
|
||||
err = configloaders.NotifyAdminModuleMappingChange()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
63
EdgeAdmin/internal/web/actions/default/admins/index.go
Normal file
63
EdgeAdmin/internal/web/actions/default/admins/index.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package admins
|
||||
|
||||
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("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
Keyword string
|
||||
HasWeakPassword bool
|
||||
}) {
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["hasWeakPassword"] = params.HasWeakPassword
|
||||
|
||||
countResp, err := this.RPC().AdminRPC().CountAllEnabledAdmins(this.AdminContext(), &pb.CountAllEnabledAdminsRequest{
|
||||
Keyword: params.Keyword,
|
||||
HasWeakPassword: params.HasWeakPassword,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var page = this.NewPage(countResp.Count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
adminsResp, err := this.RPC().AdminRPC().ListEnabledAdmins(this.AdminContext(), &pb.ListEnabledAdminsRequest{
|
||||
Keyword: params.Keyword,
|
||||
HasWeakPassword: params.HasWeakPassword,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var adminMaps = []maps.Map{}
|
||||
for _, admin := range adminsResp.Admins {
|
||||
adminMaps = append(adminMaps, maps.Map{
|
||||
"id": admin.Id,
|
||||
"isOn": admin.IsOn,
|
||||
"isSuper": admin.IsSuper,
|
||||
"username": admin.Username,
|
||||
"fullname": admin.Fullname,
|
||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", admin.CreatedAt),
|
||||
"otpLoginIsOn": admin.OtpLogin != nil && admin.OtpLogin.IsOn,
|
||||
"canLogin": admin.CanLogin,
|
||||
"hasWeakPassword": admin.HasWeakPassword,
|
||||
})
|
||||
}
|
||||
this.Data["admins"] = adminMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
32
EdgeAdmin/internal/web/actions/default/admins/init.go
Normal file
32
EdgeAdmin/internal/web/actions/default/admins/init.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package admins
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/admins/accesskeys"
|
||||
"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").
|
||||
Prefix("/admins").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
Get("/admin", new(AdminAction)).
|
||||
Get("/otpQrcode", new(OtpQrcodeAction)).
|
||||
Post("/options", new(OptionsAction)).
|
||||
|
||||
// AccessKeys
|
||||
Prefix("/admins/accesskeys").
|
||||
Get("", new(accesskeys.IndexAction)).
|
||||
GetPost("/createPopup", new(accesskeys.CreatePopupAction)).
|
||||
Post("/delete", new(accesskeys.DeleteAction)).
|
||||
Post("/updateIsOn", new(accesskeys.UpdateIsOnAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
40
EdgeAdmin/internal/web/actions/default/admins/options.go
Normal file
40
EdgeAdmin/internal/web/actions/default/admins/options.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package admins
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// 系统用户选项
|
||||
// 组件中需要用到的系统用户选项
|
||||
type OptionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *OptionsAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *OptionsAction) RunPost(params struct{}) {
|
||||
// TODO 实现关键词搜索
|
||||
adminsResp, err := this.RPC().AdminRPC().ListEnabledAdmins(this.AdminContext(), &pb.ListEnabledAdminsRequest{
|
||||
Offset: 0,
|
||||
Size: 1000,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
adminMaps := []maps.Map{}
|
||||
for _, admin := range adminsResp.Admins {
|
||||
adminMaps = append(adminMaps, maps.Map{
|
||||
"id": admin.Id,
|
||||
"name": admin.Fullname,
|
||||
"username": admin.Username,
|
||||
})
|
||||
}
|
||||
this.Data["admins"] = adminMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
81
EdgeAdmin/internal/web/actions/default/admins/otpQrcode.go
Normal file
81
EdgeAdmin/internal/web/actions/default/admins/otpQrcode.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package admins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/otputils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"github.com/skip2/go-qrcode"
|
||||
"github.com/xlzd/gotp"
|
||||
)
|
||||
|
||||
type OtpQrcodeAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *OtpQrcodeAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *OtpQrcodeAction) RunGet(params struct {
|
||||
AdminId int64
|
||||
Download bool
|
||||
}) {
|
||||
loginResp, err := this.RPC().LoginRPC().FindEnabledLogin(this.AdminContext(), &pb.FindEnabledLoginRequest{
|
||||
AdminId: params.AdminId,
|
||||
Type: "otp",
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var login = loginResp.Login
|
||||
if login == nil || !login.IsOn {
|
||||
this.NotFound("adminLogin", params.AdminId)
|
||||
return
|
||||
}
|
||||
|
||||
var loginParams = maps.Map{}
|
||||
err = json.Unmarshal(login.ParamsJSON, &loginParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var secret = loginParams.GetString("secret")
|
||||
|
||||
// 当前用户信息
|
||||
adminResp, err := this.RPC().AdminRPC().FindEnabledAdmin(this.AdminContext(), &pb.FindEnabledAdminRequest{AdminId: params.AdminId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var admin = adminResp.Admin
|
||||
if admin == nil {
|
||||
this.NotFound("admin", params.AdminId)
|
||||
return
|
||||
}
|
||||
|
||||
uiConfig, err := configloaders.LoadAdminUIConfig()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var url = gotp.NewDefaultTOTP(secret).ProvisioningUri(admin.Username, uiConfig.AdminSystemName)
|
||||
|
||||
data, err := qrcode.Encode(otputils.FixIssuer(url), qrcode.Medium, 256)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if params.Download {
|
||||
var filename = "OTP-ADMIN-" + admin.Username + ".png"
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\""+filename+"\";")
|
||||
}
|
||||
this.AddHeader("Content-Type", "image/png")
|
||||
this.AddHeader("Content-Length", types.String(len(data)))
|
||||
_, _ = this.Write(data)
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
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"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct{}) {
|
||||
// node clusters
|
||||
nodeClustersResp, err := this.RPC().NodeClusterRPC().FindAllEnabledNodeClusters(this.AdminContext(), &pb.FindAllEnabledNodeClustersRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var nodeClusterMaps = []maps.Map{}
|
||||
for _, nodeCluster := range nodeClustersResp.NodeClusters {
|
||||
nodeClusterMaps = append(nodeClusterMaps, maps.Map{
|
||||
"id": nodeCluster.Id,
|
||||
"name": nodeCluster.Name,
|
||||
})
|
||||
}
|
||||
this.Data["nodeClusters"] = nodeClusterMaps
|
||||
|
||||
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
|
||||
|
||||
NodeClusterIds []int64
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("adminId", params.AdminId).
|
||||
Gt(0, "请选择系统用户").
|
||||
Field("instanceId", params.InstanceId).
|
||||
Gt(0, "请选择媒介")
|
||||
|
||||
var 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,
|
||||
NodeClusterIds: params.NodeClusterIds,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
defer this.CreateLogInfo(codes.MessageRecipient_LogCreateMessageRecipient, resp.MessageRecipientId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
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()
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Name string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入分组名称")
|
||||
|
||||
_, err := this.RPC().MessageRecipientGroupRPC().CreateMessageRecipientGroup(this.AdminContext(), &pb.CreateMessageRecipientGroupRequest{Name: params.Name})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
GroupId int64
|
||||
}) {
|
||||
_, err := this.RPC().MessageRecipientGroupRPC().DeleteMessageRecipientGroup(this.AdminContext(), &pb.DeleteMessageRecipientGroupRequest{MessageRecipientGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "group")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
groupsResp, err := this.RPC().MessageRecipientGroupRPC().FindAllEnabledMessageRecipientGroups(this.AdminContext(), &pb.FindAllEnabledMessageRecipientGroupsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
groupMaps := []maps.Map{}
|
||||
for _, group := range groupsResp.MessageRecipientGroups {
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
"isOn": group.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeAdmin)).
|
||||
Data("teaMenu", "admins").
|
||||
Data("teaSubMenu", "recipients").
|
||||
Prefix("/admins/recipients/groups").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
GetPost("/updatePopup", new(UpdatePopupAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
Get("/selectPopup", new(SelectPopupAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type SelectPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) RunGet(params struct {
|
||||
GroupIds string
|
||||
}) {
|
||||
selectedGroupIds := utils.SplitNumbers(params.GroupIds)
|
||||
|
||||
groupsResp, err := this.RPC().MessageRecipientGroupRPC().FindAllEnabledMessageRecipientGroups(this.AdminContext(), &pb.FindAllEnabledMessageRecipientGroupsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
groupMaps := []maps.Map{}
|
||||
for _, group := range groupsResp.MessageRecipientGroups {
|
||||
if lists.ContainsInt64(selectedGroupIds, group.Id) {
|
||||
continue
|
||||
}
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
"isOn": group.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
GroupId int64
|
||||
}) {
|
||||
groupResp, err := this.RPC().MessageRecipientGroupRPC().FindEnabledMessageRecipientGroup(this.AdminContext(), &pb.FindEnabledMessageRecipientGroupRequest{MessageRecipientGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
group := groupResp.MessageRecipientGroup
|
||||
if group == nil {
|
||||
this.NotFound("messageRecipientGroup", params.GroupId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["group"] = maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
"isOn": group.IsOn,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
GroupId int64
|
||||
Name string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入分组名称")
|
||||
|
||||
_, err := this.RPC().MessageRecipientGroupRPC().UpdateMessageRecipientGroup(this.AdminContext(), &pb.UpdateMessageRecipientGroupRequest{
|
||||
MessageRecipientGroupId: params.GroupId,
|
||||
Name: params.Name,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
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()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package recipients
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeAdmin)).
|
||||
Data("teaMenu", "admins").
|
||||
Data("teaSubMenu", "recipients").
|
||||
Prefix("/admins/recipients").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
Post("/mediaOptions", new(MediaOptionsAction)).
|
||||
Get("/recipient", new(RecipientAction)).
|
||||
GetPost("/test", new(TestAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
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"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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
|
||||
TelegramProxyScheme string
|
||||
TelegramProxyHost 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":
|
||||
// token
|
||||
params.Must.
|
||||
Field("telegramToken", params.TelegramToken).
|
||||
Require("请输入机器人Token").
|
||||
Match(`^\w+:[\w-_]+$`, "机器人Token格式错误,请修正")
|
||||
|
||||
options["token"] = params.TelegramToken
|
||||
|
||||
// proxy
|
||||
var telegramScheme = params.TelegramProxyScheme
|
||||
var telegramProxyHost = params.TelegramProxyHost
|
||||
|
||||
if len(telegramScheme) > 0 && len(telegramProxyHost) > 0 {
|
||||
// 检查是否为url
|
||||
if regexp.MustCompile(`^\w+://`).MatchString(telegramProxyHost) {
|
||||
u, err := url.Parse(telegramProxyHost)
|
||||
if err == nil {
|
||||
telegramScheme = u.Scheme
|
||||
telegramProxyHost = u.Host
|
||||
}
|
||||
}
|
||||
|
||||
var slashIndex = strings.Index(telegramProxyHost, "/")
|
||||
if slashIndex >= 0 {
|
||||
telegramProxyHost = telegramProxyHost[:slashIndex]
|
||||
}
|
||||
|
||||
options["proxyURL"] = telegramScheme + "://" + telegramProxyHost
|
||||
}
|
||||
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()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
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()
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
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()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeAdmin)).
|
||||
Data("teaMenu", "admins").
|
||||
Data("teaSubMenu", "instances").
|
||||
Prefix("/admins/recipients/instances").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
Get("/instance", new(InstanceAction)).
|
||||
GetPost("/test", new(TestAction)).
|
||||
Post("/options", new(OptionsAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
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"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
var instance = instanceResp.MessageMediaInstance
|
||||
if instance == nil || instance.MessageMedia == nil {
|
||||
this.NotFound("messageMediaInstance", params.InstanceId)
|
||||
return
|
||||
}
|
||||
|
||||
// 参数
|
||||
var mediaParams = maps.Map{}
|
||||
if len(instance.ParamsJSON) > 0 {
|
||||
err = json.Unmarshal(instance.ParamsJSON, &mediaParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 隐藏密码
|
||||
if mediaParams.Has("password") {
|
||||
var password = mediaParams.Get("password")
|
||||
if password != nil {
|
||||
passwordString, ok := password.(string)
|
||||
if ok {
|
||||
mediaParams["password"] = strings.Repeat("*", len(passwordString))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 频率
|
||||
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()
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// OptionsAction 媒介类型选项
|
||||
type OptionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *OptionsAction) RunPost(params struct{}) {
|
||||
resp, err := this.RPC().MessageMediaInstanceRPC().ListEnabledMessageMediaInstances(this.AdminContext(), &pb.ListEnabledMessageMediaInstancesRequest{
|
||||
Offset: 0,
|
||||
Size: 1000,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
instanceMaps := []maps.Map{}
|
||||
for _, instance := range resp.MessageMediaInstances {
|
||||
instanceMaps = append(instanceMaps, maps.Map{
|
||||
"id": instance.Id,
|
||||
"name": instance.Name,
|
||||
"description": instance.Description,
|
||||
"media": maps.Map{
|
||||
"type": instance.MessageMedia.Type,
|
||||
"name": instance.MessageMedia.Name,
|
||||
"userDescription": instance.MessageMedia.UserDescription,
|
||||
},
|
||||
})
|
||||
}
|
||||
this.Data["instances"] = instanceMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type TestAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TestAction) Init() {
|
||||
this.Nav("", "", "test")
|
||||
}
|
||||
|
||||
func (this *TestAction) RunGet(params struct {
|
||||
InstanceId int64
|
||||
}) {
|
||||
instanceResp, err := this.RPC().MessageMediaInstanceRPC().FindEnabledMessageMediaInstance(this.AdminContext(), &pb.FindEnabledMessageMediaInstanceRequest{MessageMediaInstanceId: params.InstanceId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
instance := instanceResp.MessageMediaInstance
|
||||
if instance == nil || instance.MessageMedia == nil {
|
||||
this.NotFound("messageMediaInstance", params.InstanceId)
|
||||
return
|
||||
}
|
||||
|
||||
mediaParams := maps.Map{}
|
||||
if len(instance.ParamsJSON) > 0 {
|
||||
err = json.Unmarshal(instance.ParamsJSON, &mediaParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["instance"] = maps.Map{
|
||||
"id": instance.Id,
|
||||
"isOn": instance.IsOn,
|
||||
"media": maps.Map{
|
||||
"type": instance.MessageMedia.Type,
|
||||
"name": instance.MessageMedia.Name,
|
||||
"userDescription": instance.MessageMedia.UserDescription,
|
||||
},
|
||||
"description": instance.Description,
|
||||
"params": mediaParams,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *TestAction) RunPost(params struct {
|
||||
InstanceId int64
|
||||
Subject string
|
||||
Body string
|
||||
User string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("instanceId", params.InstanceId).
|
||||
Gt(0, "请选择正确的媒介")
|
||||
|
||||
resp, err := this.RPC().MessageTaskRPC().SendMessageTask(this.AdminContext(), &pb.SendMessageTaskRequest{
|
||||
MessageMediaInstanceId: params.InstanceId,
|
||||
User: params.User,
|
||||
Subject: params.Subject,
|
||||
Body: params.Body,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["result"] = maps.Map{
|
||||
"isOk": resp.IsOk,
|
||||
"error": resp.Error,
|
||||
"response": resp.Response,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
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"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
var instance = instanceResp.MessageMediaInstance
|
||||
if instance == nil || instance.MessageMedia == nil {
|
||||
this.NotFound("messageMediaInstance", params.InstanceId)
|
||||
return
|
||||
}
|
||||
|
||||
var mediaParams = maps.Map{}
|
||||
if len(instance.ParamsJSON) > 0 {
|
||||
err = json.Unmarshal(instance.ParamsJSON, &mediaParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// telegram parameters
|
||||
this.Data["telegramProxyScheme"] = "socks5"
|
||||
this.Data["telegramProxyHost"] = ""
|
||||
if instance.MessageMedia != nil && instance.MessageMedia.Type == "telegram" {
|
||||
var proxyURL = mediaParams.GetString("proxyURL")
|
||||
var reg = regexp.MustCompile(`^(\w+)://(.+)$`)
|
||||
if reg.MatchString(proxyURL) {
|
||||
var matches = reg.FindStringSubmatch(proxyURL)
|
||||
if len(matches) > 2 {
|
||||
this.Data["telegramProxyScheme"] = matches[1]
|
||||
this.Data["telegramProxyHost"] = matches[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
TelegramProxyScheme string
|
||||
TelegramProxyHost 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").
|
||||
Match(`^\w+:[\w-_]+$`, "机器人Token格式错误,请修正")
|
||||
options["token"] = params.TelegramToken
|
||||
|
||||
// proxy
|
||||
var telegramScheme = params.TelegramProxyScheme
|
||||
var telegramProxyHost = params.TelegramProxyHost
|
||||
|
||||
if len(telegramScheme) > 0 && len(telegramProxyHost) > 0 {
|
||||
// 检查是否为url
|
||||
if regexp.MustCompile(`^\w+://`).MatchString(telegramProxyHost) {
|
||||
u, err := url.Parse(telegramProxyHost)
|
||||
if err == nil {
|
||||
telegramScheme = u.Scheme
|
||||
telegramProxyHost = u.Host
|
||||
}
|
||||
}
|
||||
|
||||
var slashIndex = strings.Index(telegramProxyHost, "/")
|
||||
if slashIndex >= 0 {
|
||||
telegramProxyHost = telegramProxyHost[:slashIndex]
|
||||
}
|
||||
|
||||
options["proxyURL"] = telegramScheme + "://" + telegramProxyHost
|
||||
}
|
||||
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()
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "log")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
countResp, err := this.RPC().MessageTaskLogRPC().CountMessageTaskLogs(this.AdminContext(), &pb.CountMessageTaskLogsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var 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
|
||||
}
|
||||
|
||||
var 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()
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
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)).
|
||||
Post("/updateTaskStatus", new(UpdateTaskStatusAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package logs
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type UpdateTaskStatusAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateTaskStatusAction) RunPost(params struct {
|
||||
TaskId int64
|
||||
Status int32
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.MessageTask_LogUpdateMessageTaskStatus, params.TaskId, pb.UpdateMessageTaskStatusRequest_MessageTaskStatusNone)
|
||||
|
||||
_, err := this.RPC().MessageTaskRPC().UpdateMessageTaskStatus(this.AdminContext(), &pb.UpdateMessageTaskStatusRequest{
|
||||
MessageTaskId: params.TaskId,
|
||||
Status: pb.UpdateMessageTaskStatusRequest_Status(params.Status),
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package recipients
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
// 媒介类型选项
|
||||
type MediaOptionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *MediaOptionsAction) RunPost(params struct{}) {
|
||||
resp, err := this.RPC().MessageMediaRPC().FindAllMessageMedias(this.AdminContext(), &pb.FindAllMessageMediasRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
mediaMaps := []maps.Map{}
|
||||
for _, media := range resp.MessageMedias {
|
||||
mediaMaps = append(mediaMaps, maps.Map{
|
||||
"id": media.Id,
|
||||
"type": media.Type,
|
||||
"name": media.Name,
|
||||
"description": media.Description,
|
||||
})
|
||||
}
|
||||
this.Data["medias"] = mediaMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package receivers
|
||||
|
||||
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 {
|
||||
ReceiverId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.MessageReceiver_LogDeleteReceiver, params.ReceiverId)
|
||||
|
||||
_, err := this.RPC().MessageReceiverRPC().DeleteMessageReceiver(this.AdminContext(), &pb.DeleteMessageReceiverRequest{MessageReceiverId: params.ReceiverId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package receivers
|
||||
|
||||
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").
|
||||
Prefix("/admins/recipients/receivers").
|
||||
Post("/delete", new(DeleteAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package recipients
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
var recipient = recipientResp.MessageRecipient
|
||||
if recipient == nil || recipient.Admin == nil || recipient.MessageMediaInstance == nil {
|
||||
this.NotFound("messageRecipient", params.RecipientId)
|
||||
return
|
||||
}
|
||||
|
||||
// 已关联的接收者
|
||||
receiversResp, err := this.RPC().MessageReceiverRPC().FindAllEnabledMessageReceiversWithMessageRecipientId(this.AdminContext(), &pb.FindAllEnabledMessageReceiversWithMessageRecipientIdRequest{
|
||||
MessageRecipientId: params.RecipientId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// node clusters
|
||||
var nodeClusterMaps = []maps.Map{}
|
||||
for _, receiver := range receiversResp.MessageReceivers {
|
||||
if receiver.Role == nodeconfigs.NodeRoleNode && receiver.ClusterId > 0 && receiver.NodeId == 0 && receiver.ServerId == 0 {
|
||||
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: receiver.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var cluster = clusterResp.NodeCluster
|
||||
if cluster != nil {
|
||||
nodeClusterMaps = append(nodeClusterMaps, maps.Map{
|
||||
"receiverId": receiver.Id,
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["nodeClusters"] = nodeClusterMaps
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// 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()
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// 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()
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
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()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type TaskInfoAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TaskInfoAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *TaskInfoAction) RunPost(params struct {
|
||||
TaskId int64
|
||||
}) {
|
||||
resp, err := this.RPC().MessageTaskRPC().FindEnabledMessageTask(this.AdminContext(), &pb.FindEnabledMessageTaskRequest{MessageTaskId: params.TaskId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if resp.MessageTask == nil {
|
||||
this.NotFound("messageTask", params.TaskId)
|
||||
return
|
||||
}
|
||||
|
||||
result := resp.MessageTask.Result
|
||||
this.Data["status"] = resp.MessageTask.Status
|
||||
this.Data["result"] = maps.Map{
|
||||
"isOk": result.IsOk,
|
||||
"response": result.Response,
|
||||
"error": result.Error,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
114
EdgeAdmin/internal/web/actions/default/admins/recipients/test.go
Normal file
114
EdgeAdmin/internal/web/actions/default/admins/recipients/test.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package recipients
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type TestAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *TestAction) Init() {
|
||||
this.Nav("", "", "test")
|
||||
}
|
||||
|
||||
func (this *TestAction) RunGet(params struct {
|
||||
RecipientId int64
|
||||
}) {
|
||||
recipientResp, err := this.RPC().MessageRecipientRPC().FindEnabledMessageRecipient(this.AdminContext(), &pb.FindEnabledMessageRecipientRequest{MessageRecipientId: params.RecipientId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
recipient := recipientResp.MessageRecipient
|
||||
if recipient == nil || recipient.Admin == nil || recipient.MessageMediaInstance == nil {
|
||||
this.NotFound("messageRecipient", params.RecipientId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["recipient"] = maps.Map{
|
||||
"id": recipient.Id,
|
||||
"admin": maps.Map{
|
||||
"id": recipient.Admin.Id,
|
||||
"fullname": recipient.Admin.Fullname,
|
||||
"username": recipient.Admin.Username,
|
||||
},
|
||||
"instance": maps.Map{
|
||||
"id": recipient.MessageMediaInstance.Id,
|
||||
"name": recipient.MessageMediaInstance.Name,
|
||||
"description": recipient.MessageMediaInstance.Description,
|
||||
},
|
||||
"user": recipient.User,
|
||||
}
|
||||
|
||||
instanceResp, err := this.RPC().MessageMediaInstanceRPC().FindEnabledMessageMediaInstance(this.AdminContext(), &pb.FindEnabledMessageMediaInstanceRequest{MessageMediaInstanceId: recipient.MessageMediaInstance.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
instance := instanceResp.MessageMediaInstance
|
||||
if instance == nil || instance.MessageMedia == nil {
|
||||
this.NotFound("messageMediaInstance", recipient.MessageMediaInstance.Id)
|
||||
return
|
||||
}
|
||||
|
||||
mediaParams := maps.Map{}
|
||||
if len(instance.ParamsJSON) > 0 {
|
||||
err = json.Unmarshal(instance.ParamsJSON, &mediaParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["instance"] = maps.Map{
|
||||
"id": instance.Id,
|
||||
"isOn": instance.IsOn,
|
||||
"media": maps.Map{
|
||||
"type": instance.MessageMedia.Type,
|
||||
"name": instance.MessageMedia.Name,
|
||||
"userDescription": instance.MessageMedia.UserDescription,
|
||||
},
|
||||
"description": instance.Description,
|
||||
"params": mediaParams,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *TestAction) RunPost(params struct {
|
||||
InstanceId int64
|
||||
Subject string
|
||||
Body string
|
||||
User string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("instanceId", params.InstanceId).
|
||||
Gt(0, "请选择正确的媒介")
|
||||
|
||||
resp, err := this.RPC().MessageTaskRPC().SendMessageTask(this.AdminContext(), &pb.SendMessageTaskRequest{
|
||||
MessageMediaInstanceId: params.InstanceId,
|
||||
User: params.User,
|
||||
Subject: params.Subject,
|
||||
Body: params.Body,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["result"] = maps.Map{
|
||||
"isOk": resp.IsOk,
|
||||
"error": resp.Error,
|
||||
"response": resp.Response,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
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/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"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
|
||||
}
|
||||
var 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,
|
||||
}
|
||||
|
||||
// receivers
|
||||
var nodeClusterIds []int64
|
||||
|
||||
receiversResp, err := this.RPC().MessageReceiverRPC().FindAllEnabledMessageReceiversWithMessageRecipientId(this.AdminContext(), &pb.FindAllEnabledMessageReceiversWithMessageRecipientIdRequest{MessageRecipientId: params.RecipientId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, receiver := range receiversResp.MessageReceivers {
|
||||
if receiver.Role == nodeconfigs.NodeRoleNode {
|
||||
if receiver.ClusterId > 0 && receiver.NodeId == 0 && receiver.ServerId == 0 {
|
||||
nodeClusterIds = append(nodeClusterIds, receiver.ClusterId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// node clusters
|
||||
nodeClustersResp, err := this.RPC().NodeClusterRPC().FindAllEnabledNodeClusters(this.AdminContext(), &pb.FindAllEnabledNodeClustersRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var nodeClusterMaps = []maps.Map{}
|
||||
for _, nodeCluster := range nodeClustersResp.NodeClusters {
|
||||
nodeClusterMaps = append(nodeClusterMaps, maps.Map{
|
||||
"id": nodeCluster.Id,
|
||||
"name": nodeCluster.Name,
|
||||
"isChecked": lists.ContainsInt64(nodeClusterIds, nodeCluster.Id),
|
||||
})
|
||||
}
|
||||
this.Data["nodeClusters"] = nodeClusterMaps
|
||||
|
||||
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
|
||||
|
||||
NodeClusterIds []int64
|
||||
|
||||
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,
|
||||
NodeClusterIds: params.NodeClusterIds,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
215
EdgeAdmin/internal/web/actions/default/admins/update.go
Normal file
215
EdgeAdmin/internal/web/actions/default/admins/update.go
Normal file
@@ -0,0 +1,215 @@
|
||||
package admins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"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/systemconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/xlzd/gotp"
|
||||
)
|
||||
|
||||
type UpdateAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateAction) Init() {
|
||||
this.Nav("", "", "update")
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunGet(params struct {
|
||||
AdminId int64
|
||||
}) {
|
||||
adminResp, err := this.RPC().AdminRPC().FindEnabledAdmin(this.AdminContext(), &pb.FindEnabledAdminRequest{AdminId: params.AdminId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var admin = adminResp.Admin
|
||||
if admin == nil {
|
||||
this.NotFound("admin", params.AdminId)
|
||||
return
|
||||
}
|
||||
|
||||
// OTP认证
|
||||
var otpLoginIsOn = false
|
||||
if admin.OtpLogin != nil {
|
||||
otpLoginIsOn = admin.OtpLogin.IsOn
|
||||
}
|
||||
|
||||
// AccessKey数量
|
||||
countAccessKeyResp, err := this.RPC().UserAccessKeyRPC().CountAllEnabledUserAccessKeys(this.AdminContext(), &pb.CountAllEnabledUserAccessKeysRequest{AdminId: params.AdminId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countAccessKeys = countAccessKeyResp.Count
|
||||
|
||||
this.Data["admin"] = maps.Map{
|
||||
"id": admin.Id,
|
||||
"fullname": admin.Fullname,
|
||||
"username": admin.Username,
|
||||
"isOn": admin.IsOn,
|
||||
"isSuper": admin.IsSuper,
|
||||
"canLogin": admin.CanLogin,
|
||||
"otpLoginIsOn": otpLoginIsOn,
|
||||
"countAccessKeys": countAccessKeys,
|
||||
}
|
||||
|
||||
// 权限
|
||||
var moduleMaps = configloaders.AllModuleMaps(this.LangCode())
|
||||
for _, m := range moduleMaps {
|
||||
code := m.GetString("code")
|
||||
isChecked := false
|
||||
for _, module := range admin.Modules {
|
||||
if module.Code == code {
|
||||
isChecked = true
|
||||
break
|
||||
}
|
||||
}
|
||||
m["isChecked"] = isChecked
|
||||
}
|
||||
this.Data["modules"] = moduleMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
AdminId int64
|
||||
|
||||
Fullname string
|
||||
Username string
|
||||
Pass1 string
|
||||
Pass2 string
|
||||
ModuleCodes []string
|
||||
IsOn bool
|
||||
IsSuper bool
|
||||
CanLogin bool
|
||||
|
||||
// OTP
|
||||
OtpOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.Admin_LogUpdateAdmin, params.AdminId)
|
||||
|
||||
params.Must.
|
||||
Field("fullname", params.Fullname).
|
||||
Require("请输入系统用户全名")
|
||||
|
||||
params.Must.
|
||||
Field("username", params.Username).
|
||||
Require("请输入登录用户名").
|
||||
Match(`^[a-zA-Z0-9_]+$`, "用户名中只能包含英文、数字或下划线")
|
||||
|
||||
existsResp, err := this.RPC().AdminRPC().CheckAdminUsername(this.AdminContext(), &pb.CheckAdminUsernameRequest{
|
||||
AdminId: params.AdminId,
|
||||
Username: params.Username,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if existsResp.Exists {
|
||||
this.FailField("username", "此用户名已经被别的系统用户使用,请换一个")
|
||||
}
|
||||
|
||||
if len(params.Pass1) > 0 {
|
||||
params.Must.
|
||||
Field("pass1", params.Pass1).
|
||||
Require("请输入登录密码").
|
||||
Field("pass2", params.Pass2).
|
||||
Require("请输入确认登录密码")
|
||||
if params.Pass1 != params.Pass2 {
|
||||
this.FailField("pass2", "两次输入的密码不一致")
|
||||
}
|
||||
}
|
||||
|
||||
modules := []*systemconfigs.AdminModule{}
|
||||
for _, code := range params.ModuleCodes {
|
||||
modules = append(modules, &systemconfigs.AdminModule{
|
||||
Code: code,
|
||||
AllowAll: true,
|
||||
Actions: nil, // TODO 后期再开放细粒度控制
|
||||
})
|
||||
}
|
||||
modulesJSON, err := json.Marshal(modules)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().AdminRPC().UpdateAdmin(this.AdminContext(), &pb.UpdateAdminRequest{
|
||||
AdminId: params.AdminId,
|
||||
Username: params.Username,
|
||||
Password: params.Pass1,
|
||||
Fullname: params.Fullname,
|
||||
ModulesJSON: modulesJSON,
|
||||
IsSuper: params.IsSuper,
|
||||
IsOn: params.IsOn,
|
||||
CanLogin: params.CanLogin,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 修改OTP
|
||||
otpLoginResp, err := this.RPC().LoginRPC().FindEnabledLogin(this.AdminContext(), &pb.FindEnabledLoginRequest{
|
||||
AdminId: params.AdminId,
|
||||
Type: "otp",
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
{
|
||||
otpLogin := otpLoginResp.Login
|
||||
if params.OtpOn {
|
||||
if otpLogin == nil {
|
||||
otpLogin = &pb.Login{
|
||||
Id: 0,
|
||||
Type: "otp",
|
||||
ParamsJSON: maps.Map{
|
||||
"secret": gotp.RandomSecret(16), // TODO 改成可以设置secret长度
|
||||
}.AsJSON(),
|
||||
IsOn: true,
|
||||
AdminId: params.AdminId,
|
||||
UserId: 0,
|
||||
}
|
||||
} else {
|
||||
// 如果已经有了,就覆盖,这样可以保留既有的参数
|
||||
otpLogin.IsOn = true
|
||||
}
|
||||
|
||||
_, err = this.RPC().LoginRPC().UpdateLogin(this.AdminContext(), &pb.UpdateLoginRequest{Login: otpLogin})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
_, err = this.RPC().LoginRPC().UpdateLogin(this.AdminContext(), &pb.UpdateLoginRequest{Login: &pb.Login{
|
||||
Type: "otp",
|
||||
IsOn: false,
|
||||
AdminId: params.AdminId,
|
||||
}})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 通知更改
|
||||
err = configloaders.NotifyAdminModuleMappingChange()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package antiddos
|
||||
|
||||
import (
|
||||
"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/userconfigs"
|
||||
"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{}) {
|
||||
// 线路选项
|
||||
networkResp, err := this.RPC().ADNetworkRPC().FindAllADNetworks(this.AdminContext(), &pb.FindAllADNetworkRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var networkMaps = []maps.Map{}
|
||||
for _, network := range networkResp.AdNetworks {
|
||||
networkMaps = append(networkMaps, maps.Map{
|
||||
"id": network.Id,
|
||||
"name": network.Name,
|
||||
"isOn": network.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["networks"] = networkMaps
|
||||
|
||||
// 带宽单位
|
||||
this.Data["protectionUnitOptions"] = []maps.Map{
|
||||
{
|
||||
"code": userconfigs.ADPackageSizeUnitGb,
|
||||
"name": "Gbps",
|
||||
},
|
||||
{
|
||||
"code": userconfigs.ADPackageSizeUnitTb,
|
||||
"name": "Tbps",
|
||||
},
|
||||
}
|
||||
this.Data["serverUnitOptions"] = []maps.Map{
|
||||
{
|
||||
"code": userconfigs.ADPackageSizeUnitMb,
|
||||
"name": "Mbps",
|
||||
},
|
||||
{
|
||||
"code": userconfigs.ADPackageSizeUnitGb,
|
||||
"name": "Gbps",
|
||||
},
|
||||
{
|
||||
"code": userconfigs.ADPackageSizeUnitTb,
|
||||
"name": "Tbps",
|
||||
},
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
NetworkId int64
|
||||
ProtectionBandwidthSize int32
|
||||
ProtectionBandwidthUnit string
|
||||
ServerBandwidthSize int32
|
||||
ServerBandwidthUnit string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var packageId int64
|
||||
defer func() {
|
||||
this.CreateLogInfo(codes.ADPackage_LogCreateADPackage, packageId)
|
||||
}()
|
||||
|
||||
if params.NetworkId <= 0 {
|
||||
this.Fail("请选择所属线路")
|
||||
return
|
||||
}
|
||||
if params.ProtectionBandwidthSize <= 0 || len(params.ProtectionBandwidthUnit) == 0 {
|
||||
this.FailField("protectionBandwidthSize", "请输入防护带宽")
|
||||
return
|
||||
}
|
||||
if params.ServerBandwidthSize <= 0 || len(params.ServerBandwidthUnit) == 0 {
|
||||
this.FailField("serverBandwidthSize", "请输入业务带宽")
|
||||
return
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().ADPackageRPC().CreateADPackage(this.AdminContext(), &pb.CreateADPackageRequest{
|
||||
AdNetworkId: params.NetworkId,
|
||||
ProtectionBandwidthSize: params.ProtectionBandwidthSize,
|
||||
ProtectionBandwidthUnit: params.ProtectionBandwidthUnit,
|
||||
ServerBandwidthSize: params.ServerBandwidthSize,
|
||||
ServerBandwidthUnit: params.ServerBandwidthUnit,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
packageId = createResp.AdPackageId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package antiddos
|
||||
|
||||
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 {
|
||||
PackageId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ADPackage_LogDeleteADPackage, params.PackageId)
|
||||
|
||||
_, err := this.RPC().ADPackageRPC().DeleteADPackage(this.AdminContext(), &pb.DeleteADPackageRequest{AdPackageId: params.PackageId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package antiddos
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
NetworkId int64
|
||||
}) {
|
||||
this.Data["networkId"] = params.NetworkId
|
||||
|
||||
countResp, err := this.RPC().ADPackageRPC().CountADPackages(this.AdminContext(), &pb.CountADPackagesRequest{
|
||||
AdNetworkId: params.NetworkId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
var page = this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
packagesResp, err := this.RPC().ADPackageRPC().ListADPackages(this.AdminContext(), &pb.ListADPackagesRequest{
|
||||
AdNetworkId: params.NetworkId,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var packageMaps = []maps.Map{}
|
||||
for _, p := range packagesResp.AdPackages {
|
||||
// 线路
|
||||
var networkMap = maps.Map{
|
||||
"id": 0,
|
||||
"name": "",
|
||||
"isOn": false,
|
||||
}
|
||||
if p.AdNetwork != nil {
|
||||
networkMap = maps.Map{
|
||||
"id": p.AdNetwork.Id,
|
||||
"name": p.AdNetwork.Name,
|
||||
"isOn": p.AdNetwork.IsOn,
|
||||
}
|
||||
}
|
||||
|
||||
// 价格项数量
|
||||
countPricesResp, err := this.RPC().ADPackagePriceRPC().CountADPackagePrices(this.AdminContext(), &pb.CountADPackagePricesRequest{AdPackageId: p.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countPrices = countPricesResp.Count
|
||||
|
||||
// 实例数量
|
||||
countInstancesResp, err := this.RPC().ADPackageInstanceRPC().CountADPackageInstances(this.AdminContext(), &pb.CountADPackageInstancesRequest{AdPackageId: p.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countInstances = countInstancesResp.Count
|
||||
|
||||
packageMaps = append(packageMaps, maps.Map{
|
||||
"id": p.Id,
|
||||
"isOn": p.IsOn,
|
||||
"protectionBandwidthSize": p.ProtectionBandwidthSize,
|
||||
"protectionBandwidthUnit": p.ProtectionBandwidthUnit,
|
||||
"serverBandwidthSize": p.ServerBandwidthSize,
|
||||
"serverBandwidthUnit": p.ServerBandwidthUnit,
|
||||
"network": networkMap,
|
||||
"countPrices": countPrices,
|
||||
"countInstances": countInstances,
|
||||
})
|
||||
}
|
||||
this.Data["packages"] = packageMaps
|
||||
|
||||
// 所有线路
|
||||
networkResp, err := this.RPC().ADNetworkRPC().FindAllADNetworks(this.AdminContext(), &pb.FindAllADNetworkRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var networkMaps = []maps.Map{}
|
||||
for _, network := range networkResp.AdNetworks {
|
||||
networkMaps = append(networkMaps, maps.Map{
|
||||
"id": network.Id,
|
||||
"name": network.Name,
|
||||
"isOn": network.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["networks"] = networkMaps
|
||||
|
||||
// 价格项总数量
|
||||
periodsResp, err := this.RPC().ADPackagePeriodRPC().FindAllAvailableADPackagePeriods(this.AdminContext(), &pb.FindAllAvailableADPackagePeriodsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["totalPriceItems"] = len(periodsResp.AdPackagePeriods)
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
//go:build plus
|
||||
|
||||
package antiddos
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/plus"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/anti-ddos/instances"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/anti-ddos/instances/instance"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/anti-ddos/networks"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/anti-ddos/networks/network"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/anti-ddos/periods"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/anti-ddos/periods/period"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/anti-ddos/user-instances"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(plus.NewHelper(plus.ComponentCodeAntiDDoS)).
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNode)).
|
||||
Data("teaMenu", "clusters").
|
||||
Data("teaSubMenu", "antiDDoS").
|
||||
|
||||
// 高防产品
|
||||
Prefix("/clusters/anti-ddos").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
GetPost("/updatePopup", new(UpdatePopupAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
GetPost("/updatePricesPopup", new(UpdatePricesPopupAction)).
|
||||
Post("/updatePrice", new(UpdatePriceAction)).
|
||||
|
||||
// 实例
|
||||
Prefix("/clusters/anti-ddos/instances").
|
||||
Get("", new(instances.IndexAction)).
|
||||
GetPost("/createPopup", new(instances.CreatePopupAction)).
|
||||
GetPost("/instance/updatePopup", new(instance.UpdatePopupAction)).
|
||||
Post("/instance/delete", new(instance.DeleteAction)).
|
||||
|
||||
// 高防线路
|
||||
Prefix("/clusters/anti-ddos/networks").
|
||||
Get("", new(networks.IndexAction)).
|
||||
GetPost("/createPopup", new(networks.CreatePopupAction)).
|
||||
GetPost("/network/updatePopup", new(network.UpdatePopupAction)).
|
||||
Post("/network/delete", new(network.DeleteAction)).
|
||||
|
||||
// 高防实例有效期
|
||||
Prefix("/clusters/anti-ddos/periods").
|
||||
Get("", new(periods.IndexAction)).
|
||||
GetPost("/createPopup", new(periods.CreatePopupAction)).
|
||||
|
||||
// 高防实例有效期详情
|
||||
Prefix("/clusters/anti-ddos/periods/period").
|
||||
GetPost("/updatePopup", new(period.UpdatePopupAction)).
|
||||
Post("/delete", new(period.DeleteAction)).
|
||||
|
||||
// 用户高防实例
|
||||
Prefix("/clusters/anti-ddos/user-instances").
|
||||
Get("", new(userinstances.IndexAction)).
|
||||
GetPost("/createPopup", new(userinstances.CreatePopupAction)).
|
||||
Post("/price", new(userinstances.PriceAction)).
|
||||
Post("/delete", new(userinstances.DeleteAction)).
|
||||
GetPost("/renewPopup", new(userinstances.RenewPopupAction)).
|
||||
GetPost("/updateObjectsPopup", new(userinstances.UpdateObjectsPopupAction)).
|
||||
Post("/userServers", new(userinstances.UserServersAction)).
|
||||
|
||||
//
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
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"
|
||||
"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 {
|
||||
NetworkId int64
|
||||
PackageId int64
|
||||
}) {
|
||||
// 两个参数只能二选一
|
||||
if params.PackageId > 0 {
|
||||
params.NetworkId = 0
|
||||
}
|
||||
|
||||
// 产品
|
||||
this.Data["packageId"] = params.PackageId
|
||||
this.Data["packageSummary"] = ""
|
||||
if params.PackageId > 0 {
|
||||
packageResp, err := this.RPC().ADPackageRPC().FindADPackage(this.AdminContext(), &pb.FindADPackageRequest{AdPackageId: params.PackageId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if packageResp.AdPackage == nil {
|
||||
this.NotFound("adPackage", params.PackageId)
|
||||
return
|
||||
}
|
||||
this.Data["packageSummary"] = packageResp.AdPackage.Summary
|
||||
}
|
||||
|
||||
// 线路
|
||||
this.Data["networkId"] = params.NetworkId
|
||||
networksResp, err := this.RPC().ADNetworkRPC().FindAllAvailableADNetworks(this.AdminContext(), &pb.FindAllAvailableADNetworksRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var networkMaps = []maps.Map{}
|
||||
for _, network := range networksResp.AdNetworks {
|
||||
networkMaps = append(networkMaps, maps.Map{
|
||||
"id": network.Id,
|
||||
"name": network.Name,
|
||||
})
|
||||
}
|
||||
this.Data["networks"] = networkMaps
|
||||
|
||||
// 所有产品
|
||||
this.Data["packages"] = []maps.Map{}
|
||||
var packageMaps = []maps.Map{}
|
||||
var offset int64 = 0
|
||||
var size int64 = 20
|
||||
for {
|
||||
// 这里查询所有线路
|
||||
packageResp, err := this.RPC().ADPackageRPC().ListADPackages(this.AdminContext(), &pb.ListADPackagesRequest{
|
||||
Offset: offset,
|
||||
Size: size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(packageResp.AdPackages) == 0 {
|
||||
break
|
||||
}
|
||||
for _, p := range packageResp.AdPackages {
|
||||
packageMaps = append(packageMaps, maps.Map{
|
||||
"id": p.Id,
|
||||
"networkId": p.AdNetworkId,
|
||||
"summary": p.Summary,
|
||||
})
|
||||
}
|
||||
offset += size
|
||||
}
|
||||
this.Data["packages"] = packageMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
PackageId int64
|
||||
ClusterId int64
|
||||
NodeIds []int64
|
||||
IpAddresses []string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var createdInstanceId int64
|
||||
defer func() {
|
||||
this.CreateLogInfo(codes.ADPackageInstance_LogCreateADPackageInstance, createdInstanceId)
|
||||
}()
|
||||
|
||||
if params.PackageId <= 0 {
|
||||
this.Fail("请选择所属高防产品")
|
||||
return
|
||||
}
|
||||
|
||||
if params.ClusterId <= 0 {
|
||||
this.Fail("请选择要部署的集群")
|
||||
return
|
||||
}
|
||||
|
||||
if len(params.IpAddresses) == 0 {
|
||||
this.Fail("请输入高防IP地址")
|
||||
return
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().ADPackageInstanceRPC().CreateADPackageInstance(this.AdminContext(), &pb.CreateADPackageInstanceRequest{
|
||||
AdPackageId: params.PackageId,
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeIds: params.NodeIds,
|
||||
IpAddresses: params.IpAddresses,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
createdInstanceId = createResp.AdPackageInstanceId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
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 {
|
||||
NetworkId int64
|
||||
PackageId int64
|
||||
UserId int64
|
||||
Ip string
|
||||
|
||||
SelectedPackageId int64
|
||||
}) {
|
||||
this.Data["networkId"] = params.NetworkId
|
||||
this.Data["packageId"] = params.PackageId
|
||||
this.Data["ip"] = params.Ip
|
||||
|
||||
this.Data["selectedPackageId"] = params.SelectedPackageId
|
||||
|
||||
var networkId = params.NetworkId
|
||||
var packageId = params.PackageId
|
||||
|
||||
var selectedPackageMap = maps.Map{
|
||||
"id": 0,
|
||||
"summary": "",
|
||||
}
|
||||
if params.SelectedPackageId > 0 {
|
||||
packageId = params.SelectedPackageId
|
||||
packageResp, err := this.RPC().ADPackageRPC().FindADPackage(this.AdminContext(), &pb.FindADPackageRequest{
|
||||
AdPackageId: params.SelectedPackageId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var adPackage = packageResp.AdPackage
|
||||
if adPackage == nil {
|
||||
this.NotFound("adPackage", params.SelectedPackageId)
|
||||
return
|
||||
}
|
||||
|
||||
selectedPackageMap = maps.Map{
|
||||
"id": adPackage.Id,
|
||||
"summary": adPackage.Summary,
|
||||
}
|
||||
}
|
||||
this.Data["selectedPackage"] = selectedPackageMap
|
||||
|
||||
countResp, err := this.RPC().ADPackageInstanceRPC().CountADPackageInstances(this.AdminContext(), &pb.CountADPackageInstancesRequest{
|
||||
AdNetworkId: networkId,
|
||||
AdPackageId: packageId,
|
||||
UserId: params.UserId,
|
||||
Ip: params.Ip,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var page = this.NewPage(countResp.Count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
listResp, err := this.RPC().ADPackageInstanceRPC().ListADPackageInstances(this.AdminContext(), &pb.ListADPackageInstancesRequest{
|
||||
AdNetworkId: networkId,
|
||||
AdPackageId: packageId,
|
||||
UserId: params.UserId,
|
||||
Ip: params.Ip,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var instanceMaps = []maps.Map{}
|
||||
for _, instance := range listResp.AdPackageInstances {
|
||||
// network
|
||||
var networkMap = maps.Map{
|
||||
"id": 0,
|
||||
"name": "",
|
||||
}
|
||||
|
||||
// package
|
||||
var packageMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
|
||||
if instance.AdPackage != nil {
|
||||
packageMap = maps.Map{
|
||||
"id": instance.AdPackage.Id,
|
||||
"protectionBandwidthSize": instance.AdPackage.ProtectionBandwidthSize,
|
||||
"protectionBandwidthUnit": instance.AdPackage.ProtectionBandwidthUnit,
|
||||
"serverBandwidthSize": instance.AdPackage.ServerBandwidthSize,
|
||||
"serverBandwidthUnit": instance.AdPackage.ServerBandwidthUnit,
|
||||
}
|
||||
|
||||
if instance.AdPackage.AdNetwork != nil {
|
||||
networkMap = maps.Map{
|
||||
"id": instance.AdPackage.AdNetwork.Id,
|
||||
"name": instance.AdPackage.AdNetwork.Name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 集群
|
||||
var clusterMap = maps.Map{
|
||||
"id": 0,
|
||||
"name": "",
|
||||
}
|
||||
if instance.NodeCluster != nil {
|
||||
clusterMap = maps.Map{
|
||||
"id": instance.NodeCluster.Id,
|
||||
"name": instance.NodeCluster.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// IP地址
|
||||
if instance.IpAddresses == nil {
|
||||
instance.IpAddresses = []string{}
|
||||
}
|
||||
|
||||
// user
|
||||
var userMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
if instance.User != nil {
|
||||
userMap = maps.Map{
|
||||
"id": instance.User.Id,
|
||||
"fullname": instance.User.Fullname,
|
||||
"username": instance.User.Username,
|
||||
}
|
||||
}
|
||||
|
||||
var userDayTo = instance.UserDayTo
|
||||
if len(userDayTo) == 8 {
|
||||
userDayTo = userDayTo[:4] + "-" + userDayTo[4:6] + "-" + userDayTo[6:]
|
||||
}
|
||||
|
||||
instanceMaps = append(instanceMaps, maps.Map{
|
||||
"id": instance.Id,
|
||||
"isOn": instance.IsOn,
|
||||
"network": networkMap,
|
||||
"package": packageMap,
|
||||
"cluster": clusterMap,
|
||||
"ipAddresses": instance.IpAddresses,
|
||||
"userDayTo": userDayTo,
|
||||
"user": userMap,
|
||||
})
|
||||
}
|
||||
this.Data["instances"] = instanceMaps
|
||||
|
||||
// 所有线路
|
||||
var networkMaps = []maps.Map{}
|
||||
networksResp, err := this.RPC().ADNetworkRPC().FindAllAvailableADNetworks(this.AdminContext(), &pb.FindAllAvailableADNetworksRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, network := range networksResp.AdNetworks {
|
||||
networkMaps = append(networkMaps, maps.Map{
|
||||
"id": network.Id,
|
||||
"name": network.Name,
|
||||
})
|
||||
}
|
||||
this.Data["networks"] = networkMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package instance
|
||||
|
||||
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.ADPackageInstance_LogDeleteADPackageInstance, params.InstanceId)
|
||||
|
||||
_, err := this.RPC().ADPackageInstanceRPC().DeleteADPackageInstance(this.AdminContext(), &pb.DeleteADPackageInstanceRequest{AdPackageInstanceId: params.InstanceId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package instance
|
||||
|
||||
import (
|
||||
"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 UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
InstanceId int64
|
||||
}) {
|
||||
this.Data["instanceId"] = params.InstanceId
|
||||
|
||||
instanceResp, err := this.RPC().ADPackageInstanceRPC().FindADPackageInstance(this.AdminContext(), &pb.FindADPackageInstanceRequest{AdPackageInstanceId: params.InstanceId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var instance = instanceResp.AdPackageInstance
|
||||
if instance == nil {
|
||||
this.NotFound("adPackageInstance", params.InstanceId)
|
||||
return
|
||||
}
|
||||
|
||||
var ipAddresses = instance.IpAddresses
|
||||
if ipAddresses == nil {
|
||||
ipAddresses = []string{}
|
||||
}
|
||||
|
||||
// network
|
||||
var networkMap = maps.Map{
|
||||
"id": 0,
|
||||
"name": "",
|
||||
}
|
||||
|
||||
// package
|
||||
var packageMap = maps.Map{
|
||||
"id": 0,
|
||||
"summary": "",
|
||||
}
|
||||
|
||||
if instance.AdPackage != nil {
|
||||
packageMap = maps.Map{
|
||||
"id": instance.AdPackage.Id,
|
||||
"protectionBandwidthSize": instance.AdPackage.ProtectionBandwidthSize,
|
||||
"protectionBandwidthUnit": instance.AdPackage.ProtectionBandwidthUnit,
|
||||
"serverBandwidthSize": instance.AdPackage.ServerBandwidthSize,
|
||||
"serverBandwidthUnit": instance.AdPackage.ServerBandwidthUnit,
|
||||
"summary": instance.AdPackage.Summary,
|
||||
}
|
||||
|
||||
if instance.AdPackage.AdNetwork != nil {
|
||||
networkMap = maps.Map{
|
||||
"id": instance.AdPackage.AdNetwork.Id,
|
||||
"name": instance.AdPackage.AdNetwork.Name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["instance"] = maps.Map{
|
||||
"id": instance.Id,
|
||||
"clusterId": instance.NodeClusterId,
|
||||
"ipAddresses": ipAddresses,
|
||||
"isOn": instance.IsOn,
|
||||
"network": networkMap,
|
||||
"package": packageMap,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
InstanceId int64
|
||||
ClusterId int64
|
||||
NodeIds []int64
|
||||
IpAddresses []string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ADPackageInstance_LogUpdateADPackageInstance, params.InstanceId)
|
||||
|
||||
if params.ClusterId <= 0 {
|
||||
this.Fail("请选择要部署的集群")
|
||||
return
|
||||
}
|
||||
|
||||
if len(params.IpAddresses) == 0 {
|
||||
this.Fail("请输入高防IP地址")
|
||||
return
|
||||
}
|
||||
|
||||
_, err := this.RPC().ADPackageInstanceRPC().UpdateADPackageInstance(this.AdminContext(), &pb.UpdateADPackageInstanceRequest{
|
||||
AdPackageInstanceId: params.InstanceId,
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeIds: params.NodeIds,
|
||||
IpAddresses: params.IpAddresses,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package networks
|
||||
|
||||
import (
|
||||
"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"
|
||||
)
|
||||
|
||||
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
|
||||
Description string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var networkId int64
|
||||
defer func() {
|
||||
this.CreateLogInfo(codes.ADNetwork_LogCreateADNetwork, networkId)
|
||||
}()
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入线路名称")
|
||||
|
||||
createResp, err := this.RPC().ADNetworkRPC().CreateADNetwork(this.AdminContext(), &pb.CreateADNetworkRequest{
|
||||
Name: params.Name,
|
||||
Description: params.Description,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
networkId = createResp.AdNetworkId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package networks
|
||||
|
||||
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("", "", "network")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
networksResp, err := this.RPC().ADNetworkRPC().FindAllADNetworks(this.AdminContext(), &pb.FindAllADNetworkRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var networkMaps = []maps.Map{}
|
||||
for _, network := range networksResp.AdNetworks {
|
||||
networkMaps = append(networkMaps, maps.Map{
|
||||
"id": network.Id,
|
||||
"name": network.Name,
|
||||
"description": network.Description,
|
||||
"isOn": network.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["networks"] = networkMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package network
|
||||
|
||||
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 {
|
||||
NetworkId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ADNetwork_LogDeleteADNetwork)
|
||||
|
||||
_, err := this.RPC().ADNetworkRPC().DeleteADNetwork(this.AdminContext(), &pb.DeleteADNetworkRequest{AdNetworkId: params.NetworkId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"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 UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
NetworkId int64
|
||||
}) {
|
||||
networkResp, err := this.RPC().ADNetworkRPC().FindADNetwork(this.AdminContext(), &pb.FindADNetworkRequest{AdNetworkId: params.NetworkId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var network = networkResp.AdNetwork
|
||||
if network == nil {
|
||||
this.NotFound("adNetwork", params.NetworkId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["network"] = maps.Map{
|
||||
"id": network.Id,
|
||||
"name": network.Name,
|
||||
"description": network.Description,
|
||||
"isOn": network.IsOn,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
NetworkId int64
|
||||
Name string
|
||||
Description string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ADNetwork_LogUpdateADNetwork, params.NetworkId)
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入线路名称")
|
||||
|
||||
_, err := this.RPC().ADNetworkRPC().UpdateADNetwork(this.AdminContext(), &pb.UpdateADNetworkRequest{
|
||||
AdNetworkId: params.NetworkId,
|
||||
IsOn: params.IsOn,
|
||||
Name: params.Name,
|
||||
Description: params.Description,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package periods
|
||||
|
||||
import (
|
||||
"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"
|
||||
)
|
||||
|
||||
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 {
|
||||
Count int32
|
||||
Unit string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
var periodId int64
|
||||
|
||||
defer func() {
|
||||
this.CreateLogInfo(codes.ADPackagePeriod_LogCreateADPackagePeriod, periodId)
|
||||
}()
|
||||
|
||||
if params.Count <= 0 {
|
||||
this.FailField("count", "请输入有效期数量")
|
||||
}
|
||||
|
||||
createResp, err := this.RPC().ADPackagePeriodRPC().CreateADPackagePeriod(this.AdminContext(), &pb.CreateADPackagePeriodRequest{
|
||||
Count: params.Count,
|
||||
Unit: params.Unit,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
periodId = createResp.AdPackagePeriodId
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package periods
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "period")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
// 所有有效期
|
||||
periodsResp, err := this.RPC().ADPackagePeriodRPC().FindAllADPackagePeriods(this.AdminContext(), &pb.FindAllADPackagePeriodsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var periodMaps = []maps.Map{}
|
||||
for _, period := range periodsResp.AdPackagePeriods {
|
||||
periodMaps = append(periodMaps, maps.Map{
|
||||
"id": period.Id,
|
||||
"count": period.Count,
|
||||
"unit": period.Unit,
|
||||
"unitName": userconfigs.ADPackagePeriodUnitName(period.Unit),
|
||||
"isOn": period.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["periods"] = periodMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package period
|
||||
|
||||
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 {
|
||||
PeriodId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ADPackagePeriod_LogDeleteADPackagePeriod, params.PeriodId)
|
||||
|
||||
_, err := this.RPC().ADPackagePeriodRPC().DeleteADPackagePeriod(this.AdminContext(), &pb.DeleteADPackagePeriodRequest{AdPackagePeriodId: params.PeriodId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package period
|
||||
|
||||
import (
|
||||
"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/userconfigs"
|
||||
"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 {
|
||||
PeriodId int64
|
||||
}) {
|
||||
periodResp, err := this.RPC().ADPackagePeriodRPC().FindADPackagePeriod(this.AdminContext(), &pb.FindADPackagePeriodRequest{AdPackagePeriodId: params.PeriodId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var period = periodResp.AdPackagePeriod
|
||||
if period == nil {
|
||||
this.NotFound("adPackagePeriod", params.PeriodId)
|
||||
return
|
||||
}
|
||||
this.Data["period"] = maps.Map{
|
||||
"id": period.Id,
|
||||
"count": period.Count,
|
||||
"unitName": userconfigs.PricePeriodName(period.Unit),
|
||||
"isOn": period.IsOn,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
PeriodId int64
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ADPackagePeriod_LogUpdateADPackagePeriod, params.PeriodId)
|
||||
|
||||
_, err := this.RPC().ADPackagePeriodRPC().UpdateADPackagePeriod(this.AdminContext(), &pb.UpdateADPackagePeriodRequest{
|
||||
AdPackagePeriodId: params.PeriodId,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package antiddos
|
||||
|
||||
import (
|
||||
"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/userconfigs"
|
||||
"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 {
|
||||
PackageId int64
|
||||
}) {
|
||||
packageResp, err := this.RPC().ADPackageRPC().FindADPackage(this.AdminContext(), &pb.FindADPackageRequest{AdPackageId: params.PackageId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var adPackage = packageResp.AdPackage
|
||||
if adPackage == nil {
|
||||
this.NotFound("adPackage", params.PackageId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["package"] = maps.Map{
|
||||
"id": adPackage.Id,
|
||||
"isOn": adPackage.IsOn,
|
||||
"protectionBandwidthSize": adPackage.ProtectionBandwidthSize,
|
||||
"protectionBandwidthUnit": adPackage.ProtectionBandwidthUnit,
|
||||
"serverBandwidthSize": adPackage.ServerBandwidthSize,
|
||||
"serverBandwidthUnit": adPackage.ServerBandwidthUnit,
|
||||
"networkId": adPackage.AdNetworkId,
|
||||
}
|
||||
|
||||
// 线路选项
|
||||
networkResp, err := this.RPC().ADNetworkRPC().FindAllADNetworks(this.AdminContext(), &pb.FindAllADNetworkRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var networkMaps = []maps.Map{}
|
||||
for _, network := range networkResp.AdNetworks {
|
||||
networkMaps = append(networkMaps, maps.Map{
|
||||
"id": network.Id,
|
||||
"name": network.Name,
|
||||
"isOn": network.IsOn,
|
||||
})
|
||||
}
|
||||
this.Data["networks"] = networkMaps
|
||||
|
||||
// 带宽单位
|
||||
this.Data["protectionUnitOptions"] = []maps.Map{
|
||||
{
|
||||
"code": userconfigs.ADPackageSizeUnitGb,
|
||||
"name": "Gbps",
|
||||
},
|
||||
{
|
||||
"code": userconfigs.ADPackageSizeUnitTb,
|
||||
"name": "Tbps",
|
||||
},
|
||||
}
|
||||
this.Data["serverUnitOptions"] = []maps.Map{
|
||||
{
|
||||
"code": userconfigs.ADPackageSizeUnitMb,
|
||||
"name": "Mbps",
|
||||
},
|
||||
{
|
||||
"code": userconfigs.ADPackageSizeUnitGb,
|
||||
"name": "Gbps",
|
||||
},
|
||||
{
|
||||
"code": userconfigs.ADPackageSizeUnitTb,
|
||||
"name": "Tbps",
|
||||
},
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
PackageId int64
|
||||
NetworkId int64
|
||||
ProtectionBandwidthSize int32
|
||||
ProtectionBandwidthUnit string
|
||||
ServerBandwidthSize int32
|
||||
ServerBandwidthUnit string
|
||||
IsOn bool
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ADPackage_LogUpdateADPackage, params.PackageId)
|
||||
|
||||
if params.PackageId <= 0 {
|
||||
this.Fail("请选择要修改的高防产品")
|
||||
return
|
||||
}
|
||||
if params.NetworkId <= 0 {
|
||||
this.Fail("请选择所属线路")
|
||||
return
|
||||
}
|
||||
if params.ProtectionBandwidthSize <= 0 || len(params.ProtectionBandwidthUnit) == 0 {
|
||||
this.Fail("请输入防护带宽")
|
||||
return
|
||||
}
|
||||
if params.ServerBandwidthSize <= 0 || len(params.ServerBandwidthUnit) == 0 {
|
||||
this.Fail("请输入业务带宽")
|
||||
return
|
||||
}
|
||||
|
||||
_, err := this.RPC().ADPackageRPC().UpdateADPackage(this.AdminContext(), &pb.UpdateADPackageRequest{
|
||||
AdPackageId: params.PackageId,
|
||||
AdNetworkId: params.NetworkId,
|
||||
ProtectionBandwidthSize: params.ProtectionBandwidthSize,
|
||||
ProtectionBandwidthUnit: params.ProtectionBandwidthUnit,
|
||||
ServerBandwidthSize: params.ServerBandwidthSize,
|
||||
ServerBandwidthUnit: params.ServerBandwidthUnit,
|
||||
IsOn: params.IsOn,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package antiddos
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type UpdatePriceAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePriceAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePriceAction) RunPost(params struct {
|
||||
PackageId int64
|
||||
PeriodId int64
|
||||
Price float64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ADPackagePrice_LogUpdateADPackagePrice, params.PackageId, params.PeriodId)
|
||||
|
||||
_, err := this.RPC().ADPackagePriceRPC().UpdateADPackagePrice(this.AdminContext(), &pb.UpdateADPackagePriceRequest{
|
||||
AdPackageId: params.PackageId,
|
||||
AdPackagePeriodId: params.PeriodId,
|
||||
Price: params.Price,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package antiddos
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type UpdatePricesPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePricesPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePricesPopupAction) RunGet(params struct {
|
||||
PackageId int64
|
||||
}) {
|
||||
// 高防产品信息
|
||||
packageResp, err := this.RPC().ADPackageRPC().FindADPackage(this.AdminContext(), &pb.FindADPackageRequest{AdPackageId: params.PackageId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var p = packageResp.AdPackage
|
||||
if p == nil {
|
||||
this.NotFound("adPackage", params.PackageId)
|
||||
return
|
||||
}
|
||||
this.Data["package"] = maps.Map{
|
||||
"id": p.Id,
|
||||
"protectionBandwidthSize": p.ProtectionBandwidthSize,
|
||||
"protectionBandwidthUnit": p.ProtectionBandwidthUnit,
|
||||
"serverBandwidthSize": p.ServerBandwidthSize,
|
||||
"serverBandwidthUnit": p.ServerBandwidthUnit,
|
||||
}
|
||||
|
||||
// 有效期选项
|
||||
periodsResp, err := this.RPC().ADPackagePeriodRPC().FindAllAvailableADPackagePeriods(this.AdminContext(), &pb.FindAllAvailableADPackagePeriodsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var periodMaps = []maps.Map{}
|
||||
for _, period := range periodsResp.AdPackagePeriods {
|
||||
periodMaps = append(periodMaps, maps.Map{
|
||||
"id": period.Id,
|
||||
"count": period.Count,
|
||||
"unit": period.Unit,
|
||||
"name": types.String(period.Count) + userconfigs.ADPackagePeriodUnitName(period.Unit),
|
||||
})
|
||||
}
|
||||
this.Data["periods"] = periodMaps
|
||||
|
||||
// 所有价格
|
||||
pricesResp, err := this.RPC().ADPackagePriceRPC().FindADPackagePrices(this.AdminContext(), &pb.FindADPackagePricesRequest{AdPackageId: params.PackageId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var priceMap = map[string]float64{} // periodIdString => price
|
||||
for _, price := range pricesResp.AdPackagePrices {
|
||||
priceMap[types.String(price.AdPackagePeriodId)] = price.Price
|
||||
}
|
||||
|
||||
this.Data["prices"] = priceMap
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package userinstances
|
||||
|
||||
import (
|
||||
"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/userconfigs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct{}) {
|
||||
// 高防产品
|
||||
var allPackageMap = map[int64]*pb.ADPackage{} // packageId => *pb.ADPackage
|
||||
packagesResp, err := this.RPC().ADPackageRPC().FindAllIdleADPackages(this.AdminContext(), &pb.FindAllIdleADPackagesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, p := range packagesResp.AdPackages {
|
||||
allPackageMap[p.Id] = p
|
||||
}
|
||||
|
||||
// 价格
|
||||
pricesResp, err := this.RPC().ADPackagePriceRPC().FindAllADPackagePrices(this.AdminContext(), &pb.FindAllADPackagePricesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var priceMaps = []maps.Map{}
|
||||
for _, price := range pricesResp.AdPackagePrices {
|
||||
if price.Price > 0 {
|
||||
var packageId = price.AdPackageId
|
||||
var periodId = price.AdPackagePeriodId
|
||||
|
||||
p, ok := allPackageMap[packageId]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
var networkId = p.AdNetworkId
|
||||
var countIdleInstances = p.CountIdleADPackageInstances
|
||||
|
||||
if packageId > 0 && periodId > 0 && networkId > 0 && countIdleInstances > 0 {
|
||||
priceMaps = append(priceMaps, maps.Map{
|
||||
"networkId": networkId,
|
||||
"packageId": packageId,
|
||||
"protectionBandwidth": types.String(p.ProtectionBandwidthSize) + userconfigs.ADPackageSizeFullUnit(p.ProtectionBandwidthUnit),
|
||||
"serverBandwidth": types.String(p.ServerBandwidthSize) + userconfigs.ADPackageSizeFullUnit(p.ServerBandwidthUnit),
|
||||
"periodId": periodId,
|
||||
"price": price.Price,
|
||||
"maxInstances": countIdleInstances,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["prices"] = priceMaps
|
||||
|
||||
// 重新处理防护带宽和服务带宽
|
||||
var allProtectionBandwidthSizes = []string{}
|
||||
var allServerBandwidthSizes = []string{}
|
||||
for _, p := range packagesResp.AdPackages {
|
||||
var protectionSize = types.String(p.ProtectionBandwidthSize) + userconfigs.ADPackageSizeFullUnit(p.ProtectionBandwidthUnit)
|
||||
var serverSize = types.String(p.ServerBandwidthSize) + userconfigs.ADPackageSizeFullUnit(p.ServerBandwidthUnit)
|
||||
if !lists.ContainsString(allProtectionBandwidthSizes, protectionSize) {
|
||||
var found = false
|
||||
for _, price := range priceMaps {
|
||||
if types.String(price["protectionBandwidth"]) == protectionSize {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if found {
|
||||
allProtectionBandwidthSizes = append(allProtectionBandwidthSizes, protectionSize)
|
||||
}
|
||||
}
|
||||
if !lists.ContainsString(allServerBandwidthSizes, serverSize) {
|
||||
var found = false
|
||||
for _, price := range priceMaps {
|
||||
if types.String(price["serverBandwidth"]) == serverSize {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if found {
|
||||
allServerBandwidthSizes = append(allServerBandwidthSizes, serverSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["allProtectionBandwidthSizes"] = allProtectionBandwidthSizes
|
||||
this.Data["allServerBandwidthSizes"] = allServerBandwidthSizes
|
||||
|
||||
// 线路
|
||||
var networkMaps = []maps.Map{}
|
||||
networkResp, err := this.RPC().ADNetworkRPC().FindAllAvailableADNetworks(this.AdminContext(), &pb.FindAllAvailableADNetworksRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, network := range networkResp.AdNetworks {
|
||||
var found = false
|
||||
for _, price := range priceMaps {
|
||||
if types.Int64(price["networkId"]) == network.Id {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if found {
|
||||
networkMaps = append(networkMaps, maps.Map{
|
||||
"id": network.Id,
|
||||
"name": network.Name,
|
||||
"description": network.Description,
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["allNetworks"] = networkMaps
|
||||
|
||||
// 周期
|
||||
var periodMaps = []maps.Map{}
|
||||
periodResp, err := this.RPC().ADPackagePeriodRPC().FindAllAvailableADPackagePeriods(this.AdminContext(), &pb.FindAllAvailableADPackagePeriodsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, period := range periodResp.AdPackagePeriods {
|
||||
var found = false
|
||||
for _, price := range priceMaps {
|
||||
if types.Int64(price["periodId"]) == period.Id {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if found {
|
||||
periodMaps = append(periodMaps, maps.Map{
|
||||
"id": period.Id,
|
||||
"count": period.Count,
|
||||
"unit": period.Unit,
|
||||
"unitName": userconfigs.ADPackagePeriodUnitName(period.Unit),
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["allPeriods"] = periodMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
UserId int64
|
||||
PackageId int64
|
||||
PeriodId int64
|
||||
Count int32
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.ADPackagePrice_LogCreateADPackagePrice, params.UserId, params.PackageId, params.PeriodId, params.Count)
|
||||
|
||||
if params.UserId <= 0 {
|
||||
this.Fail("请选择用户")
|
||||
return
|
||||
}
|
||||
|
||||
if params.PackageId <= 0 {
|
||||
this.Fail("请选择高防产品")
|
||||
return
|
||||
}
|
||||
|
||||
if params.PeriodId <= 0 {
|
||||
this.Fail("请选择有效期")
|
||||
return
|
||||
}
|
||||
|
||||
if params.Count <= 0 {
|
||||
this.Fail("请选择实例数量")
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := this.RPC().ADPackagePriceRPC().FindADPackagePrice(this.AdminContext(), &pb.FindADPackagePriceRequest{
|
||||
AdPackageId: params.PackageId,
|
||||
AdPackagePeriodId: params.PeriodId,
|
||||
Count: params.Count,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if resp.Price == 0 {
|
||||
this.Fail("当前所选条件下的高防实例不可用")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = this.RPC().UserADInstanceRPC().CreateUserADInstance(this.AdminContext(), &pb.CreateUserADInstanceRequest{
|
||||
UserId: params.UserId,
|
||||
AdPackageId: params.PackageId,
|
||||
AdPackagePeriodId: params.PeriodId,
|
||||
Count: params.Count,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package userinstances
|
||||
|
||||
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 {
|
||||
UserInstanceId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.UserADInstance_LogDeleteUserADInstance, params.UserInstanceId)
|
||||
|
||||
_, err := this.RPC().UserADInstanceRPC().DeleteUserADInstance(this.AdminContext(), &pb.DeleteUserADInstanceRequest{UserADInstanceId: params.UserInstanceId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package userinstances
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/dateutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "userPackage")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
UserId int64
|
||||
NetworkId int64
|
||||
PeriodId int64
|
||||
}) {
|
||||
countResp, err := this.RPC().UserADInstanceRPC().CountUserADInstances(this.AdminContext(), &pb.CountUserADInstancesRequest{
|
||||
AdNetworkId: params.NetworkId,
|
||||
UserId: params.UserId,
|
||||
ExpiresDay: "",
|
||||
AdPackagePeriodId: params.PeriodId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
var page = this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
userInstancesResp, err := this.RPC().UserADInstanceRPC().ListUserADInstances(this.AdminContext(), &pb.ListUserADInstancesRequest{
|
||||
AdNetworkId: params.NetworkId,
|
||||
UserId: params.UserId,
|
||||
AdPackagePeriodId: params.PeriodId,
|
||||
ExpiresDay: "",
|
||||
AvailableOnly: false,
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var userInstanceMaps = []maps.Map{}
|
||||
for _, userInstance := range userInstancesResp.UserADInstances {
|
||||
// 用户
|
||||
var userMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
if userInstance.User != nil {
|
||||
userMap = maps.Map{
|
||||
"id": userInstance.User.Id,
|
||||
"fullname": userInstance.User.Fullname,
|
||||
"username": userInstance.User.Username,
|
||||
}
|
||||
}
|
||||
|
||||
// 实例
|
||||
var instanceMap = maps.Map{
|
||||
"id": 0,
|
||||
"userInstanceId": 0,
|
||||
}
|
||||
if userInstance.AdPackageInstance != nil {
|
||||
instanceMap = maps.Map{
|
||||
"id": userInstance.AdPackageInstance.Id,
|
||||
"userInstanceId": userInstance.AdPackageInstance.UserInstanceId,
|
||||
}
|
||||
}
|
||||
|
||||
// 产品
|
||||
var packageMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
if userInstance.AdPackageInstance != nil && userInstance.AdPackageInstance.AdPackage != nil {
|
||||
packageMap = maps.Map{
|
||||
"id": userInstance.AdPackageInstance.AdPackage.Id,
|
||||
"summary": userInstance.AdPackageInstance.AdPackage.Summary,
|
||||
}
|
||||
}
|
||||
|
||||
// 实例
|
||||
var ipAddresses = []string{}
|
||||
if userInstance.AdPackageInstance != nil && len(userInstance.AdPackageInstance.IpAddresses) > 0 {
|
||||
ipAddresses = userInstance.AdPackageInstance.IpAddresses
|
||||
}
|
||||
|
||||
userInstanceMaps = append(userInstanceMaps, maps.Map{
|
||||
"id": userInstance.Id,
|
||||
"dayFrom": dateutils.SplitYmd(userInstance.DayFrom),
|
||||
"dayTo": dateutils.SplitYmd(userInstance.DayTo),
|
||||
"user": userMap,
|
||||
"instance": instanceMap,
|
||||
"package": packageMap,
|
||||
"ipAddresses": ipAddresses,
|
||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", userInstance.CreatedAt),
|
||||
"periodCount": userInstance.AdPackagePeriodCount,
|
||||
"periodUnitName": userconfigs.ADPackagePeriodUnitName(userInstance.AdPackagePeriodUnit),
|
||||
"canDelete": userInstance.CanDelete,
|
||||
"isExpired": userInstance.DayTo < timeutil.Format("Ymd"),
|
||||
"isAvailable": userInstance.IsAvailable,
|
||||
"countObjects": userInstance.CountObjects,
|
||||
})
|
||||
}
|
||||
this.Data["userInstances"] = userInstanceMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package userinstances
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type PriceAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *PriceAction) RunPost(params struct {
|
||||
PackageId int64
|
||||
PeriodId int64
|
||||
Count int32
|
||||
}) {
|
||||
if params.PackageId <= 0 || params.PeriodId <= 0 || params.Count <= 0 {
|
||||
this.Data["price"] = 0
|
||||
this.Data["amount"] = 0
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
// 数量
|
||||
countInstancesResp, err := this.RPC().ADPackageInstanceRPC().CountIdleADPackageInstances(this.AdminContext(), &pb.CountIdleADPackageInstancesRequest{AdPackageId: params.PackageId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countInstances = types.Int32(countInstancesResp.Count)
|
||||
if countInstances < params.Count {
|
||||
this.Data["price"] = 0
|
||||
this.Data["amount"] = 0
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := this.RPC().ADPackagePriceRPC().FindADPackagePrice(this.AdminContext(), &pb.FindADPackagePriceRequest{
|
||||
AdPackageId: params.PackageId,
|
||||
AdPackagePeriodId: params.PeriodId,
|
||||
Count: params.Count,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["price"] = resp.Price
|
||||
this.Data["amount"] = resp.Amount
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package userinstances
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/dateutils"
|
||||
"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/userconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type RenewPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *RenewPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *RenewPopupAction) RunGet(params struct {
|
||||
UserInstanceId int64
|
||||
}) {
|
||||
userInstanceResp, err := this.RPC().UserADInstanceRPC().FindUserADInstance(this.AdminContext(), &pb.FindUserADInstanceRequest{UserADInstanceId: params.UserInstanceId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var userInstance = userInstanceResp.UserADInstance
|
||||
if userInstance == nil {
|
||||
this.NotFound("userInstance", params.UserInstanceId)
|
||||
return
|
||||
}
|
||||
|
||||
// 用户
|
||||
var userMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
if userInstance.User != nil {
|
||||
userMap = maps.Map{
|
||||
"id": userInstance.User.Id,
|
||||
"fullname": userInstance.User.Fullname,
|
||||
"username": userInstance.User.Username,
|
||||
}
|
||||
}
|
||||
|
||||
// 实例
|
||||
var instanceMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
if userInstance.AdPackageInstance != nil {
|
||||
if userInstance.AdPackageInstance.IpAddresses == nil {
|
||||
userInstance.AdPackageInstance.IpAddresses = []string{}
|
||||
}
|
||||
instanceMap = maps.Map{
|
||||
"id": userInstance.AdPackageInstance.Id,
|
||||
"ipAddresses": userInstance.AdPackageInstance.IpAddresses,
|
||||
}
|
||||
}
|
||||
|
||||
// 产品
|
||||
var packageMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
var packageId int64
|
||||
if userInstance.AdPackageInstance != nil && userInstance.AdPackageInstance.AdPackage != nil {
|
||||
packageId = userInstance.AdPackageInstance.AdPackage.Id
|
||||
packageMap = maps.Map{
|
||||
"id": userInstance.AdPackageInstance.AdPackage.Id,
|
||||
"summary": userInstance.AdPackageInstance.AdPackage.Summary,
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["userInstance"] = maps.Map{
|
||||
"id": userInstance.Id,
|
||||
"periodId": userInstance.AdPackagePeriodId,
|
||||
"dayTo": dateutils.SplitYmd(userInstance.DayTo),
|
||||
"today": timeutil.Format("Y-m-d"),
|
||||
"isExpired": len(userInstance.DayTo) == 0 || userInstance.DayTo < timeutil.Format("Ymd"),
|
||||
"isAvailable": userInstance.IsAvailable,
|
||||
"user": userMap,
|
||||
"instance": instanceMap,
|
||||
"package": packageMap,
|
||||
}
|
||||
|
||||
// 价格选项
|
||||
if packageId > 0 {
|
||||
pricesResp, err := this.RPC().ADPackagePriceRPC().FindADPackagePrices(this.AdminContext(), &pb.FindADPackagePricesRequest{AdPackageId: packageId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var priceMaps = []maps.Map{}
|
||||
var allValidPeriodIds = []int64{}
|
||||
for _, price := range pricesResp.AdPackagePrices {
|
||||
allValidPeriodIds = append(allValidPeriodIds, price.AdPackagePeriodId)
|
||||
priceMaps = append(priceMaps, maps.Map{
|
||||
"periodId": price.AdPackagePeriodId,
|
||||
"price": price.Price,
|
||||
})
|
||||
}
|
||||
this.Data["prices"] = priceMaps
|
||||
|
||||
// 有效期选项
|
||||
var periodMaps = []maps.Map{}
|
||||
periodResp, err := this.RPC().ADPackagePeriodRPC().FindAllAvailableADPackagePeriods(this.AdminContext(), &pb.FindAllAvailableADPackagePeriodsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, period := range periodResp.AdPackagePeriods {
|
||||
if !lists.ContainsInt64(allValidPeriodIds, period.Id) {
|
||||
continue
|
||||
}
|
||||
periodMaps = append(periodMaps, maps.Map{
|
||||
"id": period.Id,
|
||||
"count": period.Count,
|
||||
"unit": period.Unit,
|
||||
"unitName": userconfigs.ADPackagePeriodUnitName(period.Unit),
|
||||
})
|
||||
}
|
||||
this.Data["allPeriods"] = periodMaps
|
||||
} else {
|
||||
this.Data["allPeriods"] = []maps.Map{}
|
||||
this.Data["prices"] = []maps.Map{}
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *RenewPopupAction) RunPost(params struct {
|
||||
UserInstanceId int64
|
||||
PeriodId int64
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.UserADInstance_LogRenewUserADInstance, params.UserInstanceId)
|
||||
|
||||
_, err := this.RPC().UserADInstanceRPC().RenewUserADInstance(this.AdminContext(), &pb.RenewUserADInstanceRequest{
|
||||
UserADInstanceId: params.UserInstanceId,
|
||||
AdPackagePeriodId: params.PeriodId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package userinstances
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/dateutils"
|
||||
"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"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type UpdateObjectsPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdateObjectsPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdateObjectsPopupAction) RunGet(params struct {
|
||||
UserInstanceId int64
|
||||
}) {
|
||||
userInstanceResp, err := this.RPC().UserADInstanceRPC().FindUserADInstance(this.AdminContext(), &pb.FindUserADInstanceRequest{UserADInstanceId: params.UserInstanceId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var userInstance = userInstanceResp.UserADInstance
|
||||
if userInstance == nil {
|
||||
this.NotFound("userInstance", params.UserInstanceId)
|
||||
return
|
||||
}
|
||||
var objectMaps = []maps.Map{}
|
||||
if len(userInstance.ObjectsJSON) > 0 {
|
||||
err = json.Unmarshal(userInstance.ObjectsJSON, &objectMaps)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 用户
|
||||
var userMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
if userInstance.User != nil {
|
||||
userMap = maps.Map{
|
||||
"id": userInstance.User.Id,
|
||||
"fullname": userInstance.User.Fullname,
|
||||
"username": userInstance.User.Username,
|
||||
}
|
||||
}
|
||||
|
||||
// 实例
|
||||
var instanceMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
if userInstance.AdPackageInstance != nil {
|
||||
if userInstance.AdPackageInstance.IpAddresses == nil {
|
||||
userInstance.AdPackageInstance.IpAddresses = []string{}
|
||||
}
|
||||
instanceMap = maps.Map{
|
||||
"id": userInstance.AdPackageInstance.Id,
|
||||
"ipAddresses": userInstance.AdPackageInstance.IpAddresses,
|
||||
}
|
||||
}
|
||||
|
||||
// 产品
|
||||
var packageMap = maps.Map{
|
||||
"id": 0,
|
||||
}
|
||||
if userInstance.AdPackageInstance != nil && userInstance.AdPackageInstance.AdPackage != nil {
|
||||
packageMap = maps.Map{
|
||||
"id": userInstance.AdPackageInstance.AdPackage.Id,
|
||||
"summary": userInstance.AdPackageInstance.AdPackage.Summary,
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["userInstance"] = maps.Map{
|
||||
"id": userInstance.Id,
|
||||
"periodId": userInstance.AdPackagePeriodId,
|
||||
"isAvailable": userInstance.IsAvailable,
|
||||
"objects": objectMaps,
|
||||
"dayTo": dateutils.SplitYmd(userInstance.DayTo),
|
||||
"today": timeutil.Format("Y-m-d"),
|
||||
"isExpired": len(userInstance.DayTo) == 0 || userInstance.DayTo < timeutil.Format("Ymd"),
|
||||
"user": userMap,
|
||||
"instance": instanceMap,
|
||||
"package": packageMap,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdateObjectsPopupAction) RunPost(params struct {
|
||||
UserInstanceId int64
|
||||
ObjectCodesJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.UserADInstance_LogUpdateUserADInstanceObjects, params.UserInstanceId)
|
||||
|
||||
var objectCodes = []string{}
|
||||
if len(params.ObjectCodesJSON) > 0 {
|
||||
err := json.Unmarshal(params.ObjectCodesJSON, &objectCodes)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// TODO 检查有没有超出最大防护对象数量
|
||||
|
||||
_, err := this.RPC().UserADInstanceRPC().UpdateUserADInstanceObjects(this.AdminContext(), &pb.UpdateUserADInstanceObjectsRequest{
|
||||
UserADInstanceId: params.UserInstanceId,
|
||||
ObjectCodes: objectCodes,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package userinstances
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type UserServersAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UserServersAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UserServersAction) RunPost(params struct {
|
||||
UserId int64
|
||||
Page int32
|
||||
}) {
|
||||
var size int64 = 10
|
||||
|
||||
// 数量
|
||||
countResp, err := this.RPC().ServerRPC().CountAllEnabledServersMatch(this.AdminContext(), &pb.CountAllEnabledServersMatchRequest{
|
||||
UserId: params.UserId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
var page = this.NewPage(count, size)
|
||||
|
||||
// 列表
|
||||
serversResp, err := this.RPC().ServerRPC().ListEnabledServersMatch(this.AdminContext(), &pb.ListEnabledServersMatchRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
UserId: params.UserId,
|
||||
IgnoreServerNames: true,
|
||||
IgnoreSSLCerts: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
var serverMaps = []maps.Map{}
|
||||
for _, server := range serversResp.Servers {
|
||||
serverMaps = append(serverMaps, maps.Map{
|
||||
"id": server.Id,
|
||||
"name": server.Name,
|
||||
})
|
||||
}
|
||||
this.Data["servers"] = serverMaps
|
||||
this.Data["page"] = maps.Map{
|
||||
"max": page.Max,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package boards
|
||||
|
||||
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"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DomainStatsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DomainStatsAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
var hourFrom = timeutil.Format("YmdH", time.Now().Add(-23*time.Hour))
|
||||
var hourTo = timeutil.Format("YmdH")
|
||||
|
||||
resp, err := this.RPC().ServerDomainHourlyStatRPC().ListTopServerDomainStatsWithServerId(this.AdminContext(), &pb.ListTopServerDomainStatsWithServerIdRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
HourFrom: hourFrom,
|
||||
HourTo: hourTo,
|
||||
Size: 10,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 域名排行
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.DomainStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"serverId": stat.ServerId,
|
||||
"domain": stat.Domain,
|
||||
"countRequests": stat.CountRequests,
|
||||
"bytes": stat.Bytes,
|
||||
"countAttackRequests": stat.CountAttackRequests,
|
||||
"attackBytes": stat.AttackBytes,
|
||||
})
|
||||
}
|
||||
this.Data["topDomainStats"] = statMaps
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package boards
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "board", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
if !teaconst.IsPlus {
|
||||
this.Fail("only for commercial users")
|
||||
}
|
||||
|
||||
resp, err := this.RPC().ServerStatBoardRPC().ComposeServerStatNodeClusterBoard(this.AdminContext(), &pb.ComposeServerStatNodeClusterBoardRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["board"] = maps.Map{
|
||||
"countUsers": resp.CountUsers,
|
||||
"countActiveNodes": resp.CountActiveNodes,
|
||||
"countInactiveNodes": resp.CountInactiveNodes,
|
||||
"countServers": resp.CountServers,
|
||||
}
|
||||
|
||||
// 24小时流量趋势
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.HourlyTrafficStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"bytes": stat.Bytes,
|
||||
"cachedBytes": stat.CachedBytes,
|
||||
"countRequests": stat.CountRequests,
|
||||
"countCachedRequests": stat.CountCachedRequests,
|
||||
"countAttackRequests": stat.CountAttackRequests,
|
||||
"attackBytes": stat.AttackBytes,
|
||||
"day": stat.Hour[4:6] + "月" + stat.Hour[6:8] + "日",
|
||||
"hour": stat.Hour[8:],
|
||||
})
|
||||
}
|
||||
this.Data["hourlyStats"] = statMaps
|
||||
}
|
||||
|
||||
// 15天流量趋势
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.DailyTrafficStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"bytes": stat.Bytes,
|
||||
"cachedBytes": stat.CachedBytes,
|
||||
"countRequests": stat.CountRequests,
|
||||
"countCachedRequests": stat.CountCachedRequests,
|
||||
"countAttackRequests": stat.CountAttackRequests,
|
||||
"attackBytes": stat.AttackBytes,
|
||||
"day": stat.Day[4:6] + "月" + stat.Day[6:] + "日",
|
||||
})
|
||||
}
|
||||
this.Data["dailyStats"] = statMaps
|
||||
}
|
||||
|
||||
// 当月流量
|
||||
this.Data["monthlyTraffic"] = numberutils.FormatBytes(resp.MonthlyTrafficBytes)
|
||||
|
||||
// 今日流量
|
||||
this.Data["todayTraffic"] = numberutils.FormatBytes(resp.DailyTrafficBytes)
|
||||
|
||||
// 昨日流量
|
||||
this.Data["yesterdayTraffic"] = numberutils.FormatBytes(resp.LastDailyTrafficBytes)
|
||||
|
||||
// 节点排行
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.TopNodeStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"nodeId": stat.NodeId,
|
||||
"nodeName": stat.NodeName,
|
||||
"countRequests": stat.CountRequests,
|
||||
"bytes": stat.Bytes,
|
||||
})
|
||||
}
|
||||
this.Data["topNodeStats"] = statMaps
|
||||
}
|
||||
|
||||
// CPU
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.CpuNodeValues {
|
||||
var valueMap = maps.Map{}
|
||||
err = json.Unmarshal(stat.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||
"value": valueMap.GetFloat32("usage"),
|
||||
})
|
||||
}
|
||||
this.Data["cpuValues"] = statMaps
|
||||
}
|
||||
|
||||
// Memory
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.MemoryNodeValues {
|
||||
var valueMap = maps.Map{}
|
||||
err = json.Unmarshal(stat.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||
"value": valueMap.GetFloat32("usage"),
|
||||
})
|
||||
}
|
||||
this.Data["memoryValues"] = statMaps
|
||||
}
|
||||
|
||||
// Load
|
||||
{
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range resp.LoadNodeValues {
|
||||
var valueMap = maps.Map{}
|
||||
err = json.Unmarshal(stat.ValueJSON, &valueMap)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"time": timeutil.FormatTime("H:i", stat.CreatedAt),
|
||||
"value": valueMap.GetFloat32("load1m"),
|
||||
})
|
||||
}
|
||||
this.Data["loadValues"] = statMaps
|
||||
}
|
||||
|
||||
// 指标
|
||||
{
|
||||
var chartMaps = []maps.Map{}
|
||||
for _, chart := range resp.MetricDataCharts {
|
||||
var statMaps = []maps.Map{}
|
||||
for _, stat := range chart.MetricStats {
|
||||
statMaps = append(statMaps, maps.Map{
|
||||
"keys": stat.Keys,
|
||||
"time": stat.Time,
|
||||
"value": stat.Value,
|
||||
"count": stat.SumCount,
|
||||
"total": stat.SumTotal,
|
||||
})
|
||||
}
|
||||
chartMaps = append(chartMaps, maps.Map{
|
||||
"chart": maps.Map{
|
||||
"id": chart.MetricChart.Id,
|
||||
"name": chart.MetricChart.Name,
|
||||
"widthDiv": chart.MetricChart.WidthDiv,
|
||||
"isOn": chart.MetricChart.IsOn,
|
||||
"maxItems": chart.MetricChart.MaxItems,
|
||||
"type": chart.MetricChart.Type,
|
||||
},
|
||||
"item": maps.Map{
|
||||
"id": chart.MetricChart.MetricItem.Id,
|
||||
"name": chart.MetricChart.MetricItem.Name,
|
||||
"period": chart.MetricChart.MetricItem.Period,
|
||||
"periodUnit": chart.MetricChart.MetricItem.PeriodUnit,
|
||||
"valueType": serverconfigs.FindMetricValueType(chart.MetricChart.MetricItem.Category, chart.MetricChart.MetricItem.Value),
|
||||
"valueTypeName": serverconfigs.FindMetricValueName(chart.MetricChart.MetricItem.Category, chart.MetricChart.MetricItem.Value),
|
||||
"keys": chart.MetricChart.MetricItem.Keys,
|
||||
},
|
||||
"stats": statMaps,
|
||||
})
|
||||
}
|
||||
this.Data["metricCharts"] = chartMaps
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CreateBatchAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateBatchAction) Init() {
|
||||
this.Nav("", "node", "create")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *CreateBatchAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
leftMenuItems := []maps.Map{
|
||||
{
|
||||
"name": this.Lang(codes.NodeMenu_CreateSingleNode),
|
||||
"url": "/clusters/cluster/createNode?clusterId=" + strconv.FormatInt(params.ClusterId, 10),
|
||||
"isActive": false,
|
||||
},
|
||||
{
|
||||
"name": this.Lang(codes.NodeMenu_CreateMultipleNodes),
|
||||
"url": "/clusters/cluster/createBatch?clusterId=" + strconv.FormatInt(params.ClusterId, 10),
|
||||
"isActive": true,
|
||||
},
|
||||
}
|
||||
this.Data["leftMenuItems"] = leftMenuItems
|
||||
|
||||
// 限额
|
||||
maxNodes, leftNodes, err := this.findNodesQuota()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["quota"] = maps.Map{
|
||||
"maxNodes": maxNodes,
|
||||
"leftNodes": leftNodes,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateBatchAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
GroupId int64
|
||||
RegionId int64
|
||||
IpList string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
if params.ClusterId <= 0 {
|
||||
this.Fail("请选择正确的集群")
|
||||
}
|
||||
|
||||
// 校验
|
||||
// TODO 支持IP范围,比如:192.168.1.[100-105]
|
||||
realIPList := []string{}
|
||||
for _, ip := range strings.Split(params.IpList, "\n") {
|
||||
ip = strings.TrimSpace(ip)
|
||||
if len(ip) == 0 {
|
||||
continue
|
||||
}
|
||||
ip = strings.ReplaceAll(ip, " ", "")
|
||||
|
||||
if net.ParseIP(ip) == nil {
|
||||
this.Fail("发现错误的IP地址:" + ip)
|
||||
}
|
||||
|
||||
if lists.ContainsString(realIPList, ip) {
|
||||
continue
|
||||
}
|
||||
realIPList = append(realIPList, ip)
|
||||
}
|
||||
|
||||
// 保存
|
||||
for _, ip := range realIPList {
|
||||
resp, err := this.RPC().NodeRPC().CreateNode(this.AdminContext(), &pb.CreateNodeRequest{
|
||||
Name: ip,
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeGroupId: params.GroupId,
|
||||
NodeRegionId: params.RegionId,
|
||||
NodeLogin: nil,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
nodeId := resp.NodeId
|
||||
_, err = this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
|
||||
NodeId: nodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
Name: "IP地址",
|
||||
Ip: ip,
|
||||
CanAccess: true,
|
||||
IsUp: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.Node_LogCreateNodeBatch)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build !plus
|
||||
|
||||
package cluster
|
||||
|
||||
func (this *CreateBatchAction) findNodesQuota() (maxNodes int32, leftNodes int32, err error) {
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package cluster
|
||||
|
||||
import "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
|
||||
func (this *CreateBatchAction) findNodesQuota() (maxNodes int32, leftNodes int32, err error) {
|
||||
quotaResp, err := this.RPC().AuthorityKeyRPC().FindAuthorityQuota(this.AdminContext(), &pb.FindAuthorityQuotaRequest{})
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
leftNodes = quotaResp.MaxNodes - quotaResp.CountNodes
|
||||
if leftNodes < 0 {
|
||||
leftNodes = 0
|
||||
}
|
||||
|
||||
return quotaResp.MaxNodes, leftNodes, nil
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CreateNodeAction 创建节点
|
||||
type CreateNodeAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateNodeAction) Init() {
|
||||
this.Nav("", "node", "create")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *CreateNodeAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
if params.ClusterId <= 0 {
|
||||
this.RedirectURL("/clusters")
|
||||
return
|
||||
}
|
||||
|
||||
var leftMenuItems = []maps.Map{
|
||||
{
|
||||
"name": this.Lang(codes.NodeMenu_CreateSingleNode),
|
||||
"url": "/clusters/cluster/createNode?clusterId=" + strconv.FormatInt(params.ClusterId, 10),
|
||||
"isActive": true,
|
||||
},
|
||||
{
|
||||
"name": this.Lang(codes.NodeMenu_CreateMultipleNodes),
|
||||
"url": "/clusters/cluster/createBatch?clusterId=" + strconv.FormatInt(params.ClusterId, 10),
|
||||
"isActive": false,
|
||||
},
|
||||
}
|
||||
this.Data["leftMenuItems"] = leftMenuItems
|
||||
|
||||
// DNS线路
|
||||
clusterDNSResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var dnsRouteMaps = []maps.Map{}
|
||||
this.Data["dnsDomainId"] = 0
|
||||
if clusterDNSResp.Domain != nil {
|
||||
domainId := clusterDNSResp.Domain.Id
|
||||
this.Data["dnsDomainId"] = domainId
|
||||
if domainId > 0 {
|
||||
routesResp, err := this.RPC().DNSDomainRPC().FindAllDNSDomainRoutes(this.AdminContext(), &pb.FindAllDNSDomainRoutesRequest{DnsDomainId: domainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, route := range routesResp.Routes {
|
||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
||||
"domainId": domainId,
|
||||
"domainName": clusterDNSResp.Domain.Name,
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
this.Data["dnsRoutes"] = dnsRouteMaps
|
||||
|
||||
// API节点列表
|
||||
apiNodesResp, err := this.RPC().APINodeRPC().FindAllEnabledAPINodes(this.AdminContext(), &pb.FindAllEnabledAPINodesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var apiNodes = apiNodesResp.ApiNodes
|
||||
var apiEndpoints = []string{}
|
||||
for _, apiNode := range apiNodes {
|
||||
if !apiNode.IsOn {
|
||||
continue
|
||||
}
|
||||
apiEndpoints = append(apiEndpoints, apiNode.AccessAddrs...)
|
||||
}
|
||||
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
|
||||
|
||||
// 安装文件下载
|
||||
this.Data["installerFiles"] = clusterutils.ListInstallerFiles()
|
||||
|
||||
// 限额
|
||||
maxNodes, leftNodes, err := this.findNodesQuota()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["quota"] = maps.Map{
|
||||
"maxNodes": maxNodes,
|
||||
"leftNodes": leftNodes,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreateNodeAction) RunPost(params struct {
|
||||
Name string
|
||||
IpAddressesJSON []byte
|
||||
ClusterId int64
|
||||
GroupId int64
|
||||
RegionId int64
|
||||
GrantId int64
|
||||
SshHost string
|
||||
SshPort int
|
||||
|
||||
DnsDomainId int64
|
||||
DnsRoutesJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入节点名称")
|
||||
|
||||
if len(params.IpAddressesJSON) == 0 {
|
||||
this.Fail("请至少添加一个IP地址")
|
||||
}
|
||||
|
||||
// TODO 检查cluster
|
||||
if params.ClusterId <= 0 {
|
||||
this.Fail("请选择所在集群")
|
||||
}
|
||||
|
||||
// IP地址
|
||||
var ipAddresses = []maps.Map{}
|
||||
if len(params.IpAddressesJSON) > 0 {
|
||||
err := json.Unmarshal(params.IpAddressesJSON, &ipAddresses)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(ipAddresses) == 0 {
|
||||
// 检查Name中是否包含IP
|
||||
var ipv4Reg = regexp.MustCompile(`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`)
|
||||
var ipMatches = ipv4Reg.FindStringSubmatch(params.Name)
|
||||
if len(ipMatches) > 0 {
|
||||
var nodeIP = ipMatches[0]
|
||||
if net.ParseIP(nodeIP) != nil {
|
||||
ipAddresses = []maps.Map{
|
||||
{
|
||||
"ip": nodeIP,
|
||||
"canAccess": true,
|
||||
"isOn": true,
|
||||
"isUp": true,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(ipAddresses) == 0 {
|
||||
this.Fail("请至少输入一个IP地址")
|
||||
}
|
||||
}
|
||||
|
||||
var dnsRouteCodes = []string{}
|
||||
if len(params.DnsRoutesJSON) > 0 {
|
||||
err := json.Unmarshal(params.DnsRoutesJSON, &dnsRouteCodes)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// TODO 检查登录授权
|
||||
var loginInfo = &pb.NodeLogin{
|
||||
Id: 0,
|
||||
Name: "SSH",
|
||||
Type: "ssh",
|
||||
Params: maps.Map{
|
||||
"grantId": params.GrantId,
|
||||
"host": params.SshHost,
|
||||
"port": params.SshPort,
|
||||
}.AsJSON(),
|
||||
}
|
||||
|
||||
// 保存
|
||||
createResp, err := this.RPC().NodeRPC().CreateNode(this.AdminContext(), &pb.CreateNodeRequest{
|
||||
Name: params.Name,
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeGroupId: params.GroupId,
|
||||
NodeRegionId: params.RegionId,
|
||||
NodeLogin: loginInfo,
|
||||
DnsDomainId: params.DnsDomainId,
|
||||
DnsRoutes: dnsRouteCodes,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var nodeId = createResp.NodeId
|
||||
|
||||
// IP地址
|
||||
var resultIPAddresses = []string{}
|
||||
for _, addr := range ipAddresses {
|
||||
var resultAddrIds = []int64{}
|
||||
|
||||
addrId := addr.GetInt64("id")
|
||||
if addrId > 0 {
|
||||
resultAddrIds = append(resultAddrIds, addrId)
|
||||
_, err = this.RPC().NodeIPAddressRPC().UpdateNodeIPAddressNodeId(this.AdminContext(), &pb.UpdateNodeIPAddressNodeIdRequest{
|
||||
NodeIPAddressId: addrId,
|
||||
NodeId: nodeId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
resultIPAddresses = append(resultIPAddresses, addr.GetString("ip"))
|
||||
} else {
|
||||
var ipStrings = addr.GetString("ip")
|
||||
result, err := utils.ExtractIP(ipStrings)
|
||||
if err != nil {
|
||||
this.Fail("节点创建成功,但是保存IP失败:" + err.Error())
|
||||
}
|
||||
|
||||
resultIPAddresses = append(resultIPAddresses, result...)
|
||||
|
||||
if len(result) == 1 {
|
||||
// 单个创建
|
||||
createResp, err := this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
|
||||
NodeId: nodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
Name: addr.GetString("name"),
|
||||
Ip: result[0],
|
||||
CanAccess: addr.GetBool("canAccess"),
|
||||
IsUp: addr.GetBool("isUp"),
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
addrId = createResp.NodeIPAddressId
|
||||
resultAddrIds = append(resultAddrIds, addrId)
|
||||
} else if len(result) > 1 {
|
||||
// 批量创建
|
||||
createResp, err := this.RPC().NodeIPAddressRPC().CreateNodeIPAddresses(this.AdminContext(), &pb.CreateNodeIPAddressesRequest{
|
||||
NodeId: nodeId,
|
||||
Role: nodeconfigs.NodeRoleNode,
|
||||
Name: addr.GetString("name"),
|
||||
IpList: result,
|
||||
CanAccess: addr.GetBool("canAccess"),
|
||||
IsUp: addr.GetBool("isUp"),
|
||||
GroupValue: ipStrings,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
resultAddrIds = append(resultAddrIds, createResp.NodeIPAddressIds...)
|
||||
}
|
||||
}
|
||||
|
||||
// 阈值
|
||||
var thresholds = addr.GetSlice("thresholds")
|
||||
if len(thresholds) > 0 {
|
||||
thresholdsJSON, err := json.Marshal(thresholds)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, addrId := range resultAddrIds {
|
||||
_, err = this.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(this.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
|
||||
NodeIPAddressId: addrId,
|
||||
NodeIPAddressThresholdsJSON: thresholdsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.Node_LogCreateNode, nodeId)
|
||||
|
||||
// 响应数据
|
||||
this.Data["nodeId"] = nodeId
|
||||
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: nodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if nodeResp.Node != nil {
|
||||
var grantMap maps.Map = nil
|
||||
grantId := params.GrantId
|
||||
if grantId > 0 {
|
||||
grantResp, err := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{NodeGrantId: grantId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if grantResp.NodeGrant != nil && grantResp.NodeGrant.Id > 0 {
|
||||
grantMap = maps.Map{
|
||||
"id": grantResp.NodeGrant.Id,
|
||||
"name": grantResp.NodeGrant.Name,
|
||||
"method": grantResp.NodeGrant.Method,
|
||||
"methodName": grantutils.FindGrantMethodName(grantResp.NodeGrant.Method, this.LangCode()),
|
||||
"username": grantResp.NodeGrant.Username,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": nodeResp.Node.Id,
|
||||
"name": nodeResp.Node.Name,
|
||||
"uniqueId": nodeResp.Node.UniqueId,
|
||||
"secret": nodeResp.Node.Secret,
|
||||
"addresses": resultIPAddresses,
|
||||
"login": maps.Map{
|
||||
"id": 0,
|
||||
"name": "SSH",
|
||||
"type": "ssh",
|
||||
"params": maps.Map{
|
||||
"grantId": params.GrantId,
|
||||
"host": params.SshHost,
|
||||
"port": params.SshPort,
|
||||
},
|
||||
},
|
||||
"grant": grantMap,
|
||||
}
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"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 CreateNodeInstallAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreateNodeInstallAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
SshHost string
|
||||
SshPort int
|
||||
GrantId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
defer this.CreateLogInfo(codes.NodeSSH_LogUpdateNodeSSH, params.NodeId)
|
||||
|
||||
params.Must.
|
||||
Field("sshHost2", params.SshHost).
|
||||
Require("请填写SSH主机地址").
|
||||
Field("sshPort2", params.SshPort).
|
||||
Gt(0, "请填写SSH主机端口").
|
||||
Lt(65535, "SSH主机端口需要小于65535").
|
||||
Field("grantId", params.GrantId).
|
||||
Gt(0, "请选择SSH登录认证")
|
||||
|
||||
// 查询login
|
||||
nodeResp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var node = nodeResp.Node
|
||||
if node == nil {
|
||||
this.Fail("找不到要修改的节点")
|
||||
}
|
||||
var loginId int64
|
||||
if node.NodeLogin != nil {
|
||||
loginId = node.NodeLogin.Id
|
||||
}
|
||||
|
||||
// 修改节点信息
|
||||
_, err = this.RPC().NodeRPC().UpdateNodeLogin(this.AdminContext(), &pb.UpdateNodeLoginRequest{
|
||||
NodeId: params.NodeId,
|
||||
NodeLogin: &pb.NodeLogin{
|
||||
Id: loginId,
|
||||
Name: "SSH",
|
||||
Type: "ssh",
|
||||
Params: maps.Map{
|
||||
"grantId": params.GrantId,
|
||||
"host": params.SshHost,
|
||||
"port": params.SshPort,
|
||||
}.AsJSON(),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 开始安装
|
||||
_, err = this.RPC().NodeRPC().InstallNode(this.AdminContext(), &pb.InstallNodeRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.Fail("安装失败:" + err.Error())
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build !plus
|
||||
|
||||
package cluster
|
||||
|
||||
func (this *CreateNodeAction) findNodesQuota() (maxNodes int32, leftNodes int32, err error) {
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package cluster
|
||||
|
||||
import "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
|
||||
func (this *CreateNodeAction) findNodesQuota() (maxNodes int32, leftNodes int32, err error) {
|
||||
quotaResp, err := this.RPC().AuthorityKeyRPC().FindAuthorityQuota(this.AdminContext(), &pb.FindAuthorityQuotaRequest{})
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
leftNodes = quotaResp.MaxNodes - quotaResp.CountNodes
|
||||
if leftNodes < 0 {
|
||||
leftNodes = 0
|
||||
}
|
||||
|
||||
return quotaResp.MaxNodes, leftNodes, nil
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package cluster
|
||||
|
||||
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) Init() {
|
||||
this.Nav("", "delete", "index")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
// 检查有无服务正在使用
|
||||
countResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithNodeClusterId(this.AdminContext(), &pb.CountAllEnabledServersWithNodeClusterIdRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if countResp.Count > 0 {
|
||||
this.Fail("有代理服务正在使用此集群,请修改这些代理服务后再删除")
|
||||
}
|
||||
|
||||
// 删除
|
||||
_, err = this.RPC().NodeClusterRPC().DeleteNodeCluster(this.AdminContext(), &pb.DeleteNodeClusterRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.NodeCluster_LogDeleteCluster, params.ClusterId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type DownloadInstallerAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DownloadInstallerAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *DownloadInstallerAction) RunGet(params struct {
|
||||
Name string
|
||||
}) {
|
||||
if len(params.Name) == 0 {
|
||||
this.ResponseWriter.WriteHeader(http.StatusNotFound)
|
||||
this.WriteString("file not found")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查文件名
|
||||
// 以防止路径穿越等风险
|
||||
if !regexp.MustCompile(`^[a-zA-Z0-9.-]+$`).MatchString(params.Name) {
|
||||
this.ResponseWriter.WriteHeader(http.StatusNotFound)
|
||||
this.WriteString("file not found")
|
||||
return
|
||||
}
|
||||
|
||||
var zipFile = Tea.Root + "/edge-api/deploy/" + params.Name
|
||||
fp, err := os.OpenFile(zipFile, os.O_RDWR, 0444)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
this.ResponseWriter.WriteHeader(http.StatusNotFound)
|
||||
this.WriteString("file not found")
|
||||
return
|
||||
}
|
||||
|
||||
this.ResponseWriter.WriteHeader(http.StatusInternalServerError)
|
||||
this.WriteString("file can not be opened")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = fp.Close()
|
||||
}()
|
||||
|
||||
stat, err := fp.Stat()
|
||||
if err != nil {
|
||||
this.ResponseWriter.WriteHeader(http.StatusInternalServerError)
|
||||
this.WriteString("file can not be opened")
|
||||
return
|
||||
}
|
||||
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\""+params.Name+"\";")
|
||||
this.AddHeader("Content-Type", "application/zip")
|
||||
this.AddHeader("Content-Length", types.String(stat.Size()))
|
||||
_, _ = io.Copy(this.ResponseWriter, fp)
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"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 CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct{}) {
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
Name string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
if params.ClusterId <= 0 {
|
||||
this.Fail("请选择集群")
|
||||
}
|
||||
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入分组名称")
|
||||
createResp, err := this.RPC().NodeGroupRPC().CreateNodeGroup(this.AdminContext(), &pb.CreateNodeGroupRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
Name: params.Name,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["group"] = maps.Map{
|
||||
"id": createResp.NodeGroupId,
|
||||
"name": params.Name,
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.NodeGroup_LogCreateNodeGroup, createResp.NodeGroupId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package groups
|
||||
|
||||
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 {
|
||||
GroupId int64
|
||||
}) {
|
||||
// 检查是否正在使用
|
||||
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesWithNodeGroupId(this.AdminContext(), &pb.CountAllEnabledNodesWithNodeGroupIdRequest{NodeGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if countResp.Count > 0 {
|
||||
this.Fail("此分组正在被使用不能删除,请修改节点后再删除")
|
||||
}
|
||||
|
||||
_, err = this.RPC().NodeGroupRPC().DeleteNodeGroup(this.AdminContext(), &pb.DeleteNodeGroupRequest{NodeGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.NodeGroup_LogDeleteNodeGroup, params.GroupId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
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("", "node", "group")
|
||||
this.SecondMenu("nodes")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithNodeClusterIdRequest{
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
groupMaps := []maps.Map{}
|
||||
for _, group := range groupsResp.NodeGroups {
|
||||
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesWithNodeGroupId(this.AdminContext(), &pb.CountAllEnabledNodesWithNodeGroupIdRequest{NodeGroupId: group.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countNodes := countResp.Count
|
||||
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
"countNodes": countNodes,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type SelectPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithNodeClusterIdRequest{NodeClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
}
|
||||
|
||||
groupMaps := []maps.Map{}
|
||||
for _, group := range groupsResp.NodeGroups {
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) RunPost(params struct {
|
||||
GroupId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
if params.GroupId <= 0 {
|
||||
this.Fail("请选择要使用的分组")
|
||||
}
|
||||
|
||||
groupResp, err := this.RPC().NodeGroupRPC().FindEnabledNodeGroup(this.AdminContext(), &pb.FindEnabledNodeGroupRequest{NodeGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
group := groupResp.NodeGroup
|
||||
if group == nil {
|
||||
this.NotFound("nodeGroup", params.GroupId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["group"] = maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
type SortAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SortAction) RunPost(params struct {
|
||||
GroupIds []int64
|
||||
}) {
|
||||
_, err := this.RPC().NodeGroupRPC().UpdateNodeGroupOrders(this.AdminContext(), &pb.UpdateNodeGroupOrdersRequest{NodeGroupIds: params.GroupIds})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.NodeGroup_LogSortNodeGroups)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"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 UpdatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunGet(params struct {
|
||||
GroupId int64
|
||||
}) {
|
||||
groupResp, err := this.RPC().NodeGroupRPC().FindEnabledNodeGroup(this.AdminContext(), &pb.FindEnabledNodeGroupRequest{NodeGroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
group := groupResp.NodeGroup
|
||||
if group == nil {
|
||||
this.NotFound("nodeGroup", params.GroupId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["group"] = maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *UpdatePopupAction) RunPost(params struct {
|
||||
GroupId int64
|
||||
Name string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入分组名称")
|
||||
_, err := this.RPC().NodeGroupRPC().UpdateNodeGroup(this.AdminContext(), &pb.UpdateNodeGroupRequest{
|
||||
NodeGroupId: params.GroupId,
|
||||
Name: params.Name,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo(codes.NodeGroup_LogUpdateNodeGroup, params.GroupId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package cluster
|
||||
|
||||
import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
if teaconst.IsPlus {
|
||||
this.RedirectURL("/clusters/cluster/boards?clusterId=" + strconv.FormatInt(params.ClusterId, 10))
|
||||
} else {
|
||||
this.RedirectURL("/clusters/cluster/nodes?clusterId=" + strconv.FormatInt(params.ClusterId, 10))
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user