Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d4c80eedb | ||
|
|
af4bd950b7 | ||
|
|
f85f9b0920 | ||
|
|
89ea96c28e | ||
|
|
6f2e3f5f13 | ||
|
|
ee91e8312f |
@@ -9,7 +9,8 @@
|
||||
* `高扩展性` - 可以自由扩展新的节点,支持亿级数据
|
||||
|
||||
## 文档
|
||||
[点这里查看文档](http://edge.teaos.cn/docs)
|
||||
* [新手指南](https://edge.teaos.cn/docs/QuickStart/Index.md)
|
||||
* [文档](http://edge.teaos.cn/docs)
|
||||
|
||||
## 架构
|
||||

|
||||
@@ -23,4 +24,5 @@
|
||||
有什么问题和建议都可以加入QQ群 `659832182`。
|
||||
|
||||
## 感谢
|
||||
* 感谢[JetBrains公司](https://www.jetbrains.com/)提供免费的IDE开发Licence。
|
||||
* 感谢[JetBrains公司](https://www.jetbrains.com/)提供免费的IDE开发Licence。
|
||||
* 感谢[Gitee](https://gitee.com/)提供国内源代码托管平台
|
||||
@@ -1,7 +1,7 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "0.2.0"
|
||||
Version = "0.2.2"
|
||||
|
||||
ProductName = "Edge Admin"
|
||||
ProcessName = "edge-admin"
|
||||
|
||||
@@ -336,6 +336,10 @@ func (this *RPCClient) UserBillRPC() pb.UserBillServiceClient {
|
||||
return pb.NewUserBillServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) UserAccessKeyRPC() pb.UserAccessKeyServiceClient {
|
||||
return pb.NewUserAccessKeyServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
func (this *RPCClient) LoginRPC() pb.LoginServiceClient {
|
||||
return pb.NewLoginServiceClient(this.pickConn())
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ func (this *LocationHelper) createMenus(serverIdString string, locationIdString
|
||||
"name": "HTTP Header",
|
||||
"url": "/servers/server/settings/locations/headers?serverId=" + serverIdString + "&locationId=" + locationIdString,
|
||||
"isActive": secondMenuItem == "header",
|
||||
"isOn": locationConfig != nil && locationConfig.Web != nil && ((locationConfig.Web.RequestHeaderPolicyRef != nil && locationConfig.Web.RequestHeaderPolicyRef.IsPrior) || (locationConfig.Web.ResponseHeaderPolicyRef != nil && locationConfig.Web.ResponseHeaderPolicyRef.IsPrior)),
|
||||
"isOn": locationConfig != nil && this.hasHTTPHeaders(locationConfig.Web),
|
||||
})
|
||||
menuItems = append(menuItems, maps.Map{
|
||||
"name": "Websocket",
|
||||
@@ -158,3 +158,21 @@ func (this *LocationHelper) createMenus(serverIdString string, locationIdString
|
||||
|
||||
return menuItems
|
||||
}
|
||||
|
||||
// 检查是否已设置Header
|
||||
func (this *LocationHelper) hasHTTPHeaders(web *serverconfigs.HTTPWebConfig) bool {
|
||||
if web == nil {
|
||||
return false
|
||||
}
|
||||
if web.RequestHeaderPolicyRef != nil {
|
||||
if web.RequestHeaderPolicyRef.IsOn && web.RequestHeaderPolicy != nil && !web.RequestHeaderPolicy.IsEmpty() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if web.ResponseHeaderPolicyRef != nil {
|
||||
if web.ResponseHeaderPolicyRef.IsOn && web.ResponseHeaderPolicy != nil && !web.ResponseHeaderPolicy.IsEmpty() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@ func (this *ServerHelper) createSettingsMenu(secondMenuItem string, serverIdStri
|
||||
"name": "HTTP Header",
|
||||
"url": "/servers/server/settings/headers?serverId=" + serverIdString,
|
||||
"isActive": secondMenuItem == "header",
|
||||
"isOn": serverConfig.Web != nil && ((serverConfig.Web.RequestHeaderPolicyRef != nil && serverConfig.Web.RequestHeaderPolicyRef.IsOn) || (serverConfig.Web.ResponseHeaderPolicyRef != nil && serverConfig.Web.ResponseHeaderPolicyRef.IsOn)),
|
||||
"isOn": this.hasHTTPHeaders(serverConfig.Web),
|
||||
})
|
||||
menuItems = append(menuItems, maps.Map{
|
||||
"name": "Websocket",
|
||||
@@ -378,3 +378,21 @@ func (this *ServerHelper) createDeleteMenu(secondMenuItem string, serverIdString
|
||||
})
|
||||
return menuItems
|
||||
}
|
||||
|
||||
// 检查是否已设置Header
|
||||
func (this *ServerHelper) hasHTTPHeaders(web *serverconfigs.HTTPWebConfig) bool {
|
||||
if web == nil {
|
||||
return false
|
||||
}
|
||||
if web.RequestHeaderPolicyRef != nil {
|
||||
if web.RequestHeaderPolicyRef.IsOn && web.RequestHeaderPolicy != nil && !web.RequestHeaderPolicy.IsEmpty() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if web.ResponseHeaderPolicyRef != nil {
|
||||
if web.ResponseHeaderPolicyRef.IsOn && web.ResponseHeaderPolicy != nil && !web.ResponseHeaderPolicy.IsEmpty() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
49
internal/web/actions/default/users/accesskeys/createPopup.go
Normal file
49
internal/web/actions/default/users/accesskeys/createPopup.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// 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/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunGet(params struct {
|
||||
UserId int64
|
||||
}) {
|
||||
this.Data["userId"] = params.UserId
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
UserId 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{
|
||||
UserId: params.UserId,
|
||||
Description: params.Description,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
defer this.CreateLogInfo("创建AccessKey %d", accessKeyIdResp.UserAccessKeyId)
|
||||
|
||||
this.Success()
|
||||
}
|
||||
24
internal/web/actions/default/users/accesskeys/delete.go
Normal file
24
internal/web/actions/default/users/accesskeys/delete.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package accesskeys
|
||||
|
||||
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 {
|
||||
AccessKeyId int64
|
||||
}) {
|
||||
defer this.CreateLogInfo("删除AccessKey %d", params.AccessKeyId)
|
||||
|
||||
_, err := this.RPC().UserAccessKeyRPC().DeleteUserAccessKey(this.AdminContext(), &pb.DeleteUserAccessKeyRequest{UserAccessKeyId: params.AccessKeyId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
54
internal/web/actions/default/users/accesskeys/index.go
Normal file
54
internal/web/actions/default/users/accesskeys/index.go
Normal file
@@ -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/users/userutils"
|
||||
"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 {
|
||||
UserId int64
|
||||
}) {
|
||||
err := userutils.InitUser(this.Parent(), params.UserId)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
accessKeysResp, err := this.RPC().UserAccessKeyRPC().FindAllEnabledUserAccessKeys(this.AdminContext(), &pb.FindAllEnabledUserAccessKeysRequest{UserId: params.UserId})
|
||||
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()
|
||||
}
|
||||
28
internal/web/actions/default/users/accesskeys/updateIsOn.go
Normal file
28
internal/web/actions/default/users/accesskeys/updateIsOn.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package accesskeys
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"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("设置AccessKey %d 启用状态", 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()
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package users
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/users/accessKeys"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
@@ -18,6 +19,14 @@ func init() {
|
||||
GetPost("/update", new(UpdateAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
GetPost("/features", new(FeaturesAction)).
|
||||
|
||||
// AccessKeys
|
||||
Prefix("/users/accessKeys").
|
||||
Get("", new(accesskeys.IndexAction)).
|
||||
GetPost("/createPopup", new(accesskeys.CreatePopupAction)).
|
||||
Post("/delete", new(accesskeys.DeleteAction)).
|
||||
Post("/updateIsOn", new(accesskeys.UpdateIsOnAction)).
|
||||
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
<menu-item :href="'/users/user?userId=' + user.id" code="index">{{user.fullname}} <span class="small">({{user.username}})</span></menu-item>
|
||||
<menu-item :href="'/users/update?userId=' + user.id" code="update">修改</menu-item>
|
||||
<menu-item :href="'/users/features?userId=' + user.id" code="feature">功能</menu-item>
|
||||
<menu-item :href="'/users/accessKeys?userId=' + user.id" code="accessKey">API AccessKey</menu-item>
|
||||
</first-menu>
|
||||
20
web/views/@default/users/accesskeys/createPopup.html
Normal file
20
web/views/@default/users/accesskeys/createPopup.html
Normal file
@@ -0,0 +1,20 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>创建新AccessKey</h3>
|
||||
|
||||
<form class="ui form" method="post" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="userId" :value="userId"/>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">备注 *</td>
|
||||
<td>
|
||||
<textarea rows="2" name="description" maxlength="100" ref="focus"></textarea>
|
||||
<p class="comment">描述AccessKey的用途等。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
39
web/views/@default/users/accesskeys/index.html
Normal file
39
web/views/@default/users/accesskeys/index.html
Normal file
@@ -0,0 +1,39 @@
|
||||
{$layout}
|
||||
{$template "../user_menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item @click.prevent="createAccessKey()">[创建AccessKey]</menu-item>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="accessKeys.length == 0">暂时还没有AccessKey。</p>
|
||||
|
||||
<table class="ui table selectable" v-if="accessKeys.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>AccessKey ID</th>
|
||||
<th>AccessKey密钥</th>
|
||||
<th>备注</th>
|
||||
<th>最后访问</th>
|
||||
<th>状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="accessKey in accessKeys">
|
||||
<td :class="{disabled: !accessKey.isOn}">{{accessKey.uniqueId}}</td>
|
||||
<td :class="{disabled: !accessKey.isOn}">{{accessKey.secret}}</td>
|
||||
<td :class="{disabled: !accessKey.isOn}">{{accessKey.description}}</td>
|
||||
<td :class="{disabled: !accessKey.isOn}">
|
||||
<span v-if="accessKey.accessedTime.length > 0">{{accessKey.accessedTime}}</span>
|
||||
<span v-else class="disabled">尚无访问</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="accessKey.isOn" class="green">已启用</span>
|
||||
<span v-else class="disabled">已禁用</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" v-if="accessKey.isOn" @click.prevent="updateAccessKeyIsOn(accessKey.id, false)">禁用</a>
|
||||
<a href="" v-if="!accessKey.isOn" @click.prevent="updateAccessKeyIsOn(accessKey.id, true)">启用</a>
|
||||
<a href="" @click.prevent="deleteAccessKey(accessKey.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
41
web/views/@default/users/accesskeys/index.js
Normal file
41
web/views/@default/users/accesskeys/index.js
Normal file
@@ -0,0 +1,41 @@
|
||||
Tea.context(function () {
|
||||
this.createAccessKey = function () {
|
||||
teaweb.popup("/users/accessKeys/createPopup?userId=" + this.user.id, {
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.updateAccessKeyIsOn = function (accessKeyId, isOn) {
|
||||
let that = this
|
||||
|
||||
let message = ""
|
||||
if (isOn) {
|
||||
message = "确定要启用此AccessKey吗?"
|
||||
} else {
|
||||
message = "确定要禁用此AccessKey吗?"
|
||||
}
|
||||
teaweb.confirm(message, function () {
|
||||
that.$post(".updateIsOn")
|
||||
.params({
|
||||
accessKeyId: accessKeyId,
|
||||
isOn: isOn ? 1 : 0
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteAccessKey = function (accessKeyId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除此AccessKey吗?", function () {
|
||||
that.$post(".delete")
|
||||
.params({
|
||||
accessKeyId: accessKeyId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user