From 9b6131890c2b7e4e65449c7a7f75a1221b14d0b9 Mon Sep 17 00:00:00 2001 From: Yang Luo Date: Sat, 1 Jan 2022 16:28:06 +0800 Subject: [PATCH] Add permission page. --- controllers/permission.go | 116 ++++++++++++ object/adapter.go | 5 + object/permission.go | 132 +++++++++++++ routers/router.go | 6 + web/src/App.js | 13 ++ web/src/PermissionEditPage.js | 271 +++++++++++++++++++++++++++ web/src/PermissionListPage.js | 271 +++++++++++++++++++++++++++ web/src/backend/PermissionBackend.js | 56 ++++++ web/src/locales/de/data.json | 11 ++ web/src/locales/en/data.json | 11 ++ web/src/locales/fr/data.json | 11 ++ web/src/locales/ja/data.json | 11 ++ web/src/locales/ko/data.json | 11 ++ web/src/locales/ru/data.json | 11 ++ web/src/locales/zh/data.json | 11 ++ 15 files changed, 947 insertions(+) create mode 100644 controllers/permission.go create mode 100644 object/permission.go create mode 100644 web/src/PermissionEditPage.js create mode 100644 web/src/PermissionListPage.js create mode 100644 web/src/backend/PermissionBackend.js diff --git a/controllers/permission.go b/controllers/permission.go new file mode 100644 index 00000000..9f0ad4c1 --- /dev/null +++ b/controllers/permission.go @@ -0,0 +1,116 @@ +// Copyright 2021 The casbin Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package controllers + +import ( + "encoding/json" + + "github.com/astaxie/beego/utils/pagination" + "github.com/casbin/casdoor/object" + "github.com/casbin/casdoor/util" +) + +// GetPermissions +// @Title GetPermissions +// @Tag Permission API +// @Description get permissions +// @Param owner query string true "The owner of permissions" +// @Success 200 {array} object.Permission The Response object +// @router /get-permissions [get] +func (c *ApiController) GetPermissions() { + owner := c.Input().Get("owner") + limit := c.Input().Get("pageSize") + page := c.Input().Get("p") + field := c.Input().Get("field") + value := c.Input().Get("value") + sortField := c.Input().Get("sortField") + sortOrder := c.Input().Get("sortOrder") + if limit == "" || page == "" { + c.Data["json"] = object.GetPermissions(owner) + c.ServeJSON() + } else { + limit := util.ParseInt(limit) + paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetPermissionCount(owner, field, value))) + permissions := object.GetPaginationPermissions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder) + c.ResponseOk(permissions, paginator.Nums()) + } +} + +// @Title GetPermission +// @Tag Permission API +// @Description get permission +// @Param id query string true "The id of the permission" +// @Success 200 {object} object.Permission The Response object +// @router /get-permission [get] +func (c *ApiController) GetPermission() { + id := c.Input().Get("id") + + c.Data["json"] = object.GetPermission(id) + c.ServeJSON() +} + +// @Title UpdatePermission +// @Tag Permission API +// @Description update permission +// @Param id query string true "The id of the permission" +// @Param body body object.Permission true "The details of the permission" +// @Success 200 {object} controllers.Response The Response object +// @router /update-permission [post] +func (c *ApiController) UpdatePermission() { + id := c.Input().Get("id") + + var permission object.Permission + err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission) + if err != nil { + panic(err) + } + + c.Data["json"] = wrapActionResponse(object.UpdatePermission(id, &permission)) + c.ServeJSON() +} + +// @Title AddPermission +// @Tag Permission API +// @Description add permission +// @Param body body object.Permission true "The details of the permission" +// @Success 200 {object} controllers.Response The Response object +// @router /add-permission [post] +func (c *ApiController) AddPermission() { + var permission object.Permission + err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission) + if err != nil { + panic(err) + } + + c.Data["json"] = wrapActionResponse(object.AddPermission(&permission)) + c.ServeJSON() +} + +// @Title DeletePermission +// @Tag Permission API +// @Description delete permission +// @Param body body object.Permission true "The details of the permission" +// @Success 200 {object} controllers.Response The Response object +// @router /delete-permission [post] +func (c *ApiController) DeletePermission() { + var permission object.Permission + err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission) + if err != nil { + panic(err) + } + + c.Data["json"] = wrapActionResponse(object.DeletePermission(&permission)) + c.ServeJSON() +} diff --git a/object/adapter.go b/object/adapter.go index aaef6baf..b5b0c7d6 100644 --- a/object/adapter.go +++ b/object/adapter.go @@ -110,6 +110,11 @@ func (a *Adapter) createTable() { panic(err) } + err = a.Engine.Sync2(new(Permission)) + if err != nil { + panic(err) + } + err = a.Engine.Sync2(new(Provider)) if err != nil { panic(err) diff --git a/object/permission.go b/object/permission.go new file mode 100644 index 00000000..e2afc4c0 --- /dev/null +++ b/object/permission.go @@ -0,0 +1,132 @@ +// Copyright 2021 The casbin Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package object + +import ( + "fmt" + + "github.com/casbin/casdoor/util" + "xorm.io/core" +) + +type Permission struct { + Owner string `xorm:"varchar(100) notnull pk" json:"owner"` + Name string `xorm:"varchar(100) notnull pk" json:"name"` + CreatedTime string `xorm:"varchar(100)" json:"createdTime"` + DisplayName string `xorm:"varchar(100)" json:"displayName"` + + Users []string `xorm:"mediumtext" json:"users"` + Roles []string `xorm:"mediumtext" json:"roles"` + + ResourceType string `xorm:"varchar(100)" json:"resourceType"` + Resources []string `xorm:"mediumtext" json:"resources"` + Actions []string `xorm:"mediumtext" json:"actions"` + Effect string `xorm:"varchar(100)" json:"effect"` + + IsEnabled bool `json:"isEnabled"` +} + +func GetPermissionCount(owner, field, value string) int { + session := adapter.Engine.Where("owner=?", owner) + if field != "" && value != "" { + session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value)) + } + count, err := session.Count(&Permission{}) + if err != nil { + panic(err) + } + + return int(count) +} + +func GetPermissions(owner string) []*Permission { + permissions := []*Permission{} + err := adapter.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner}) + if err != nil { + panic(err) + } + + return permissions +} + +func GetPaginationPermissions(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Permission { + permissions := []*Permission{} + session := GetSession(owner, offset, limit, field, value, sortField, sortOrder) + err := session.Find(&permissions) + if err != nil { + panic(err) + } + + return permissions +} + +func getPermission(owner string, name string) *Permission { + if owner == "" || name == "" { + return nil + } + + permission := Permission{Owner: owner, Name: name} + existed, err := adapter.Engine.Get(&permission) + if err != nil { + panic(err) + } + + if existed { + return &permission + } else { + return nil + } +} + +func GetPermission(id string) *Permission { + owner, name := util.GetOwnerAndNameFromId(id) + return getPermission(owner, name) +} + +func UpdatePermission(id string, permission *Permission) bool { + owner, name := util.GetOwnerAndNameFromId(id) + if getPermission(owner, name) == nil { + return false + } + + affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(permission) + if err != nil { + panic(err) + } + + return affected != 0 +} + +func AddPermission(permission *Permission) bool { + affected, err := adapter.Engine.Insert(permission) + if err != nil { + panic(err) + } + + return affected != 0 +} + +func DeletePermission(permission *Permission) bool { + affected, err := adapter.Engine.ID(core.PK{permission.Owner, permission.Name}).Delete(&Permission{}) + if err != nil { + panic(err) + } + + return affected != 0 +} + +func (permission *Permission) GetId() string { + return fmt.Sprintf("%s/%s", permission.Owner, permission.Name) +} diff --git a/routers/router.go b/routers/router.go index 30fe8eee..c8b0c00d 100644 --- a/routers/router.go +++ b/routers/router.go @@ -76,6 +76,12 @@ func initAPI() { beego.Router("/api/add-role", &controllers.ApiController{}, "POST:AddRole") beego.Router("/api/delete-role", &controllers.ApiController{}, "POST:DeleteRole") + beego.Router("/api/get-permissions", &controllers.ApiController{}, "GET:GetPermissions") + beego.Router("/api/get-permission", &controllers.ApiController{}, "GET:GetPermission") + beego.Router("/api/update-permission", &controllers.ApiController{}, "POST:UpdatePermission") + beego.Router("/api/add-permission", &controllers.ApiController{}, "POST:AddPermission") + beego.Router("/api/delete-permission", &controllers.ApiController{}, "POST:DeletePermission") + beego.Router("/api/set-password", &controllers.ApiController{}, "POST:SetPassword") beego.Router("/api/check-user-password", &controllers.ApiController{}, "POST:CheckUserPassword") beego.Router("/api/get-email-and-phone", &controllers.ApiController{}, "POST:GetEmailAndPhone") diff --git a/web/src/App.js b/web/src/App.js index 7ba49d8b..7f9553a1 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -25,6 +25,8 @@ import UserListPage from "./UserListPage"; import UserEditPage from "./UserEditPage"; import RoleListPage from "./RoleListPage"; import RoleEditPage from "./RoleEditPage"; +import PermissionListPage from "./PermissionListPage"; +import PermissionEditPage from "./PermissionEditPage"; import ProviderListPage from "./ProviderListPage"; import ProviderEditPage from "./ProviderEditPage"; import ApplicationListPage from "./ApplicationListPage"; @@ -106,6 +108,8 @@ class App extends Component { this.setState({ selectedMenuKey: '/users' }); } else if (uri.includes('/roles')) { this.setState({ selectedMenuKey: '/roles' }); + } else if (uri.includes('/permissions')) { + this.setState({ selectedMenuKey: '/permissions' }); } else if (uri.includes('/providers')) { this.setState({ selectedMenuKey: '/providers' }); } else if (uri.includes('/applications')) { @@ -338,6 +342,13 @@ class App extends Component { ); + res.push( + + + {i18next.t("general:Permissions")} + + + ); res.push( @@ -449,6 +460,8 @@ class App extends Component { }/> this.renderLoginIfNotLoggedIn()}/> this.renderLoginIfNotLoggedIn()}/> + this.renderLoginIfNotLoggedIn()}/> + this.renderLoginIfNotLoggedIn()}/> this.renderLoginIfNotLoggedIn()}/> this.renderLoginIfNotLoggedIn()}/> this.renderLoginIfNotLoggedIn()}/> diff --git a/web/src/PermissionEditPage.js b/web/src/PermissionEditPage.js new file mode 100644 index 00000000..b98ce746 --- /dev/null +++ b/web/src/PermissionEditPage.js @@ -0,0 +1,271 @@ +// Copyright 2021 The casbin Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import React from "react"; +import {Button, Card, Col, Input, Row, Select, Switch} from 'antd'; +import * as PermissionBackend from "./backend/PermissionBackend"; +import * as OrganizationBackend from "./backend/OrganizationBackend"; +import * as UserBackend from "./backend/UserBackend"; +import * as Setting from "./Setting"; +import i18next from "i18next"; +import * as RoleBackend from "./backend/RoleBackend"; + +const { Option } = Select; + +class PermissionEditPage extends React.Component { + constructor(props) { + super(props); + this.state = { + classes: props, + organizationName: props.organizationName !== undefined ? props.organizationName : props.match.params.organizationName, + permissionName: props.match.params.permissionName, + permission: null, + organizations: [], + users: [], + roles: [], + }; + } + + UNSAFE_componentWillMount() { + this.getPermission(); + this.getOrganizations(); + } + + getPermission() { + PermissionBackend.getPermission(this.state.organizationName, this.state.permissionName) + .then((permission) => { + this.setState({ + permission: permission, + }); + + this.getUsers(permission.owner); + this.getRoles(permission.owner); + }); + } + + getOrganizations() { + OrganizationBackend.getOrganizations("admin") + .then((res) => { + this.setState({ + organizations: (res.msg === undefined) ? res : [], + }); + }); + } + + getUsers(organizationName) { + UserBackend.getUsers(organizationName) + .then((res) => { + this.setState({ + users: res, + }); + }); + } + + getRoles(organizationName) { + RoleBackend.getRoles(organizationName) + .then((res) => { + this.setState({ + roles: res, + }); + }); + } + + parsePermissionField(key, value) { + if ([""].includes(key)) { + value = Setting.myParseInt(value); + } + return value; + } + + updatePermissionField(key, value) { + value = this.parsePermissionField(key, value); + + let permission = this.state.permission; + permission[key] = value; + this.setState({ + permission: permission, + }); + } + + renderPermission() { + return ( + + {i18next.t("permission:Edit Permission")}     + + + + } style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner"> + + + {Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} : + + + + + + + + {Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} : + + + { + this.updatePermissionField('name', e.target.value); + }} /> + + + + + {Setting.getLabel(i18next.t("general:Display name"), i18next.t("general:Display name - Tooltip"))} : + + + { + this.updatePermissionField('displayName', e.target.value); + }} /> + + + + + {Setting.getLabel(i18next.t("role:Sub users"), i18next.t("role:Sub users - Tooltip"))} : + + + + + + + + {Setting.getLabel(i18next.t("role:Sub roles"), i18next.t("role:Sub roles - Tooltip"))} : + + + + + + + + {Setting.getLabel(i18next.t("permission:Resource type"), i18next.t("permission:Resource type - Tooltip"))} : + + + + + + + + {Setting.getLabel(i18next.t("permission:Actions"), i18next.t("permission:Actions - Tooltip"))} : + + + + + + + + {Setting.getLabel(i18next.t("permission:Effect"), i18next.t("permission:Effect - Tooltip"))} : + + + + + + + + {Setting.getLabel(i18next.t("general:Is enabled"), i18next.t("general:Is enabled - Tooltip"))} : + + + { + this.updatePermissionField('isEnabled', checked); + }} /> + + + + ) + } + + submitPermissionEdit(willExist) { + let permission = Setting.deepCopy(this.state.permission); + PermissionBackend.updatePermission(this.state.organizationName, this.state.permissionName, permission) + .then((res) => { + if (res.msg === "") { + Setting.showMessage("success", `Successfully saved`); + this.setState({ + permissionName: this.state.permission.name, + }); + + if (willExist) { + this.props.history.push(`/permissions`); + } else { + this.props.history.push(`/permissions/${this.state.permission.owner}/${this.state.permission.name}`); + } + } else { + Setting.showMessage("error", res.msg); + this.updatePermissionField('name', this.state.permissionName); + } + }) + .catch(error => { + Setting.showMessage("error", `Failed to connect to server: ${error}`); + }); + } + + render() { + return ( +
+ { + this.state.permission !== null ? this.renderPermission() : null + } +
+ + +
+
+ ); + } +} + +export default PermissionEditPage; diff --git a/web/src/PermissionListPage.js b/web/src/PermissionListPage.js new file mode 100644 index 00000000..7a0f0f70 --- /dev/null +++ b/web/src/PermissionListPage.js @@ -0,0 +1,271 @@ +// Copyright 2021 The casbin Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import React from "react"; +import {Link} from "react-router-dom"; +import {Button, Popconfirm, Switch, Table} from 'antd'; +import moment from "moment"; +import * as Setting from "./Setting"; +import * as PermissionBackend from "./backend/PermissionBackend"; +import i18next from "i18next"; +import BaseListPage from "./BaseListPage"; + +class PermissionListPage extends BaseListPage { + newPermission() { + const randomName = Setting.getRandomName(); + return { + owner: "built-in", + name: `permission_${randomName}`, + createdTime: moment().format(), + displayName: `New Permission - ${randomName}`, + users: [], + roles: [], + resourceType: "Application", + resources: ["app-built-in"], + action: "Read", + effect: "Allow", + isEnabled: true, + } + } + + addPermission() { + const newPermission = this.newPermission(); + PermissionBackend.addPermission(newPermission) + .then((res) => { + Setting.showMessage("success", `Permission added successfully`); + this.props.history.push(`/permissions/${newPermission.owner}/${newPermission.name}`); + } + ) + .catch(error => { + Setting.showMessage("error", `Permission failed to add: ${error}`); + }); + } + + deletePermission(i) { + PermissionBackend.deletePermission(this.state.data[i]) + .then((res) => { + Setting.showMessage("success", `Permission deleted successfully`); + this.setState({ + data: Setting.deleteRow(this.state.data, i), + pagination: {total: this.state.pagination.total - 1}, + }); + } + ) + .catch(error => { + Setting.showMessage("error", `Permission failed to delete: ${error}`); + }); + } + + renderTable(permissions) { + const columns = [ + { + title: i18next.t("general:Organization"), + dataIndex: 'owner', + key: 'owner', + width: '120px', + sorter: true, + ...this.getColumnSearchProps('owner'), + render: (text, record, index) => { + return ( + + {text} + + ) + } + }, + { + title: i18next.t("general:Name"), + dataIndex: 'name', + key: 'name', + width: '150px', + fixed: 'left', + sorter: true, + ...this.getColumnSearchProps('name'), + render: (text, record, index) => { + return ( + + {text} + + ) + } + }, + { + title: i18next.t("general:Created time"), + dataIndex: 'createdTime', + key: 'createdTime', + width: '160px', + sorter: true, + render: (text, record, index) => { + return Setting.getFormattedDate(text); + } + }, + { + title: i18next.t("general:Display name"), + dataIndex: 'displayName', + key: 'displayName', + width: '160px', + sorter: true, + ...this.getColumnSearchProps('displayName'), + }, + { + title: i18next.t("role:Sub users"), + dataIndex: 'users', + key: 'users', + // width: '100px', + sorter: true, + ...this.getColumnSearchProps('users'), + render: (text, record, index) => { + return Setting.getTags(text); + } + }, + { + title: i18next.t("role:Sub roles"), + dataIndex: 'roles', + key: 'roles', + // width: '100px', + sorter: true, + ...this.getColumnSearchProps('roles'), + render: (text, record, index) => { + return Setting.getTags(text); + } + }, + { + title: i18next.t("permission:Resource type"), + dataIndex: 'resourceType', + key: 'resourceType', + filterMultiple: false, + filters: [ + {text: 'Application', value: 'Application'}, + ], + width: '170px', + sorter: true, + }, + { + title: i18next.t("permission:Resources"), + dataIndex: 'resources', + key: 'resources', + // width: '100px', + sorter: true, + ...this.getColumnSearchProps('resources'), + render: (text, record, index) => { + return Setting.getTags(text); + } + }, + { + title: i18next.t("permission:Actions"), + dataIndex: 'actions', + key: 'actions', + // width: '100px', + sorter: true, + ...this.getColumnSearchProps('actions'), + render: (text, record, index) => { + return Setting.getTags(text); + } + }, + { + title: i18next.t("permission:Effect"), + dataIndex: 'effect', + key: 'effect', + filterMultiple: false, + filters: [ + {text: 'Allow', value: 'Allow'}, + {text: 'Deny', value: 'Deny'}, + ], + width: '120px', + sorter: true, + }, + { + title: i18next.t("general:Is enabled"), + dataIndex: 'isEnabled', + key: 'isEnabled', + width: '120px', + sorter: true, + render: (text, record, index) => { + return ( + + ) + } + }, + { + title: i18next.t("general:Action"), + dataIndex: '', + key: 'op', + width: '170px', + fixed: (Setting.isMobile()) ? "false" : "right", + render: (text, record, index) => { + return ( +
+ + this.deletePermission(index)} + > + + +
+ ) + } + }, + ]; + + const paginationProps = { + total: this.state.pagination.total, + showQuickJumper: true, + showSizeChanger: true, + showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total), + }; + + return ( +
+ ( +
+ {i18next.t("general:Permissions")}     + +
+ )} + loading={this.state.loading} + onChange={this.handleTableChange} + /> + + ); + } + + fetch = (params = {}) => { + let field = params.searchedColumn, value = params.searchText; + let sortField = params.sortField, sortOrder = params.sortOrder; + if (params.type !== undefined && params.type !== null) { + field = "type"; + value = params.type; + } + this.setState({ loading: true }); + PermissionBackend.getPermissions("", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + .then((res) => { + if (res.status === "ok") { + this.setState({ + loading: false, + data: res.data, + pagination: { + ...params.pagination, + total: res.data2, + }, + searchText: params.searchText, + searchedColumn: params.searchedColumn, + }); + } + }); + }; +} + +export default PermissionListPage; diff --git a/web/src/backend/PermissionBackend.js b/web/src/backend/PermissionBackend.js new file mode 100644 index 00000000..405242f8 --- /dev/null +++ b/web/src/backend/PermissionBackend.js @@ -0,0 +1,56 @@ +// Copyright 2021 The casbin Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import * as Setting from "../Setting"; + +export function getPermissions(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") { + return fetch(`${Setting.ServerUrl}/api/get-permissions?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, { + method: "GET", + credentials: "include" + }).then(res => res.json()); +} + +export function getPermission(owner, name) { + return fetch(`${Setting.ServerUrl}/api/get-permission?id=${owner}/${encodeURIComponent(name)}`, { + method: "GET", + credentials: "include" + }).then(res => res.json()); +} + +export function updatePermission(owner, name, permission) { + let newPermission = Setting.deepCopy(permission); + return fetch(`${Setting.ServerUrl}/api/update-permission?id=${owner}/${encodeURIComponent(name)}`, { + method: 'POST', + credentials: 'include', + body: JSON.stringify(newPermission), + }).then(res => res.json()); +} + +export function addPermission(permission) { + let newPermission = Setting.deepCopy(permission); + return fetch(`${Setting.ServerUrl}/api/add-permission`, { + method: 'POST', + credentials: 'include', + body: JSON.stringify(newPermission), + }).then(res => res.json()); +} + +export function deletePermission(permission) { + let newPermission = Setting.deepCopy(permission); + return fetch(`${Setting.ServerUrl}/api/delete-permission`, { + method: 'POST', + credentials: 'include', + body: JSON.stringify(newPermission), + }).then(res => res.json()); +} diff --git a/web/src/locales/de/data.json b/web/src/locales/de/data.json index e5f95113..981b6e96 100644 --- a/web/src/locales/de/data.json +++ b/web/src/locales/de/data.json @@ -133,6 +133,7 @@ "Password salt - Tooltip": "Random parameters used for password encryption", "Password type": "Password type", "Password type - Tooltip": "The form in which the password is stored in the database", + "Permissions": "Permissions", "Personal name": "Personal name", "Phone": "Phone", "Phone - Tooltip": "Phone", @@ -231,6 +232,16 @@ "Website URL": "Website URL", "Website URL - Tooltip": "Unique string-style identifier" }, + "permission": { + "Actions": "Actions", + "Actions - Tooltip": "Actions - Tooltip", + "Edit Permission": "Edit Permission", + "Effect": "Effect", + "Effect - Tooltip": "Effect - Tooltip", + "Resource type": "Resource type", + "Resource type - Tooltip": "Resource type - Tooltip", + "Resources": "Resources" + }, "provider": { "Access key": "Access key", "Access key - Tooltip": "Access key - Tooltip", diff --git a/web/src/locales/en/data.json b/web/src/locales/en/data.json index a15d65d7..0005b4d8 100644 --- a/web/src/locales/en/data.json +++ b/web/src/locales/en/data.json @@ -133,6 +133,7 @@ "Password salt - Tooltip": "Password salt - Tooltip", "Password type": "Password type", "Password type - Tooltip": "Password type - Tooltip", + "Permissions": "Permissions", "Personal name": "Personal name", "Phone": "Phone", "Phone - Tooltip": "Phone - Tooltip", @@ -231,6 +232,16 @@ "Website URL": "Website URL", "Website URL - Tooltip": "Website URL - Tooltip" }, + "permission": { + "Actions": "Actions", + "Actions - Tooltip": "Actions - Tooltip", + "Edit Permission": "Edit Permission", + "Effect": "Effect", + "Effect - Tooltip": "Effect - Tooltip", + "Resource type": "Resource type", + "Resource type - Tooltip": "Resource type - Tooltip", + "Resources": "Resources" + }, "provider": { "Access key": "Access key", "Access key - Tooltip": "Access key - Tooltip", diff --git a/web/src/locales/fr/data.json b/web/src/locales/fr/data.json index e5f95113..981b6e96 100644 --- a/web/src/locales/fr/data.json +++ b/web/src/locales/fr/data.json @@ -133,6 +133,7 @@ "Password salt - Tooltip": "Random parameters used for password encryption", "Password type": "Password type", "Password type - Tooltip": "The form in which the password is stored in the database", + "Permissions": "Permissions", "Personal name": "Personal name", "Phone": "Phone", "Phone - Tooltip": "Phone", @@ -231,6 +232,16 @@ "Website URL": "Website URL", "Website URL - Tooltip": "Unique string-style identifier" }, + "permission": { + "Actions": "Actions", + "Actions - Tooltip": "Actions - Tooltip", + "Edit Permission": "Edit Permission", + "Effect": "Effect", + "Effect - Tooltip": "Effect - Tooltip", + "Resource type": "Resource type", + "Resource type - Tooltip": "Resource type - Tooltip", + "Resources": "Resources" + }, "provider": { "Access key": "Access key", "Access key - Tooltip": "Access key - Tooltip", diff --git a/web/src/locales/ja/data.json b/web/src/locales/ja/data.json index e5f95113..981b6e96 100644 --- a/web/src/locales/ja/data.json +++ b/web/src/locales/ja/data.json @@ -133,6 +133,7 @@ "Password salt - Tooltip": "Random parameters used for password encryption", "Password type": "Password type", "Password type - Tooltip": "The form in which the password is stored in the database", + "Permissions": "Permissions", "Personal name": "Personal name", "Phone": "Phone", "Phone - Tooltip": "Phone", @@ -231,6 +232,16 @@ "Website URL": "Website URL", "Website URL - Tooltip": "Unique string-style identifier" }, + "permission": { + "Actions": "Actions", + "Actions - Tooltip": "Actions - Tooltip", + "Edit Permission": "Edit Permission", + "Effect": "Effect", + "Effect - Tooltip": "Effect - Tooltip", + "Resource type": "Resource type", + "Resource type - Tooltip": "Resource type - Tooltip", + "Resources": "Resources" + }, "provider": { "Access key": "Access key", "Access key - Tooltip": "Access key - Tooltip", diff --git a/web/src/locales/ko/data.json b/web/src/locales/ko/data.json index e5f95113..981b6e96 100644 --- a/web/src/locales/ko/data.json +++ b/web/src/locales/ko/data.json @@ -133,6 +133,7 @@ "Password salt - Tooltip": "Random parameters used for password encryption", "Password type": "Password type", "Password type - Tooltip": "The form in which the password is stored in the database", + "Permissions": "Permissions", "Personal name": "Personal name", "Phone": "Phone", "Phone - Tooltip": "Phone", @@ -231,6 +232,16 @@ "Website URL": "Website URL", "Website URL - Tooltip": "Unique string-style identifier" }, + "permission": { + "Actions": "Actions", + "Actions - Tooltip": "Actions - Tooltip", + "Edit Permission": "Edit Permission", + "Effect": "Effect", + "Effect - Tooltip": "Effect - Tooltip", + "Resource type": "Resource type", + "Resource type - Tooltip": "Resource type - Tooltip", + "Resources": "Resources" + }, "provider": { "Access key": "Access key", "Access key - Tooltip": "Access key - Tooltip", diff --git a/web/src/locales/ru/data.json b/web/src/locales/ru/data.json index e5f95113..981b6e96 100644 --- a/web/src/locales/ru/data.json +++ b/web/src/locales/ru/data.json @@ -133,6 +133,7 @@ "Password salt - Tooltip": "Random parameters used for password encryption", "Password type": "Password type", "Password type - Tooltip": "The form in which the password is stored in the database", + "Permissions": "Permissions", "Personal name": "Personal name", "Phone": "Phone", "Phone - Tooltip": "Phone", @@ -231,6 +232,16 @@ "Website URL": "Website URL", "Website URL - Tooltip": "Unique string-style identifier" }, + "permission": { + "Actions": "Actions", + "Actions - Tooltip": "Actions - Tooltip", + "Edit Permission": "Edit Permission", + "Effect": "Effect", + "Effect - Tooltip": "Effect - Tooltip", + "Resource type": "Resource type", + "Resource type - Tooltip": "Resource type - Tooltip", + "Resources": "Resources" + }, "provider": { "Access key": "Access key", "Access key - Tooltip": "Access key - Tooltip", diff --git a/web/src/locales/zh/data.json b/web/src/locales/zh/data.json index 8c2b1661..ef716abe 100644 --- a/web/src/locales/zh/data.json +++ b/web/src/locales/zh/data.json @@ -133,6 +133,7 @@ "Password salt - Tooltip": "用于密码加密的随机参数", "Password type": "密码类型", "Password type - Tooltip": "密码在数据库中存储的形式", + "Permissions": "权限", "Personal name": "姓名", "Phone": "手机号", "Phone - Tooltip": "手机号", @@ -231,6 +232,16 @@ "Website URL": "网页地址", "Website URL - Tooltip": "网页地址" }, + "permission": { + "Actions": "动作", + "Actions - Tooltip": "授权的动作", + "Edit Permission": "编辑权限", + "Effect": "效果", + "Effect - Tooltip": "允许还是拒绝", + "Resource type": "资源类型", + "Resource type - Tooltip": "授权资源的类型", + "Resources": "资源" + }, "provider": { "Access key": "Access key", "Access key - Tooltip": "Access key",