mirror of
https://github.com/casdoor/casdoor.git
synced 2025-05-23 02:35:49 +08:00
feat: Support uploading roles and permssions via xlsx files. (#1899)
* Support uploading roles and permissions via xlsx file. * Template xlsx file for uploading users and permissions. * reformat according to gofumpt. * fix typo.
This commit is contained in:
parent
c7cea331e2
commit
34151c0095
50
controllers/permission_upload.go
Normal file
50
controllers/permission_upload.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Copyright 2023 The Casdoor 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 (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/object"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *ApiController) UploadPermissions() {
|
||||||
|
userId := c.GetSessionUsername()
|
||||||
|
owner, user := util.GetOwnerAndNameFromId(userId)
|
||||||
|
|
||||||
|
file, header, err := c.Ctx.Request.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fileId := fmt.Sprintf("%s_%s_%s", owner, user, util.RemoveExt(header.Filename))
|
||||||
|
|
||||||
|
path := util.GetUploadXlsxPath(fileId)
|
||||||
|
util.EnsureFileFolderExists(path)
|
||||||
|
err = saveFile(path, &file)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
affected := object.UploadPermissions(owner, fileId)
|
||||||
|
if affected {
|
||||||
|
c.ResponseOk()
|
||||||
|
} else {
|
||||||
|
c.ResponseError(c.T("user_upload:Failed to import users"))
|
||||||
|
}
|
||||||
|
}
|
50
controllers/role_upload.go
Normal file
50
controllers/role_upload.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Copyright 2023 The Casdoor 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 (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/object"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *ApiController) UploadRoles() {
|
||||||
|
userId := c.GetSessionUsername()
|
||||||
|
owner, user := util.GetOwnerAndNameFromId(userId)
|
||||||
|
|
||||||
|
file, header, err := c.Ctx.Request.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fileId := fmt.Sprintf("%s_%s_%s", owner, user, util.RemoveExt(header.Filename))
|
||||||
|
|
||||||
|
path := util.GetUploadXlsxPath(fileId)
|
||||||
|
util.EnsureFileFolderExists(path)
|
||||||
|
err = saveFile(path, &file)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
affected := object.UploadRoles(owner, fileId)
|
||||||
|
if affected {
|
||||||
|
c.ResponseOk()
|
||||||
|
} else {
|
||||||
|
c.ResponseError(c.T("user_upload:Failed to import users"))
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,9 @@
|
|||||||
package object
|
package object
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"github.com/xorm-io/core"
|
"github.com/xorm-io/core"
|
||||||
)
|
)
|
||||||
@ -188,6 +191,54 @@ func AddPermission(permission *Permission) bool {
|
|||||||
return affected != 0
|
return affected != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AddPermissions(permissions []*Permission) bool {
|
||||||
|
if len(permissions) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := adapter.Engine.Insert(permissions)
|
||||||
|
if err != nil {
|
||||||
|
if !strings.Contains(err.Error(), "Duplicate entry") {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, permission := range permissions {
|
||||||
|
// add using for loop
|
||||||
|
if affected != 0 {
|
||||||
|
addGroupingPolicies(permission)
|
||||||
|
addPolicies(permission)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddPermissionsInBatch(permissions []*Permission) bool {
|
||||||
|
batchSize := conf.GetConfigBatchSize()
|
||||||
|
|
||||||
|
if len(permissions) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
affected := false
|
||||||
|
for i := 0; i < (len(permissions)-1)/batchSize+1; i++ {
|
||||||
|
start := i * batchSize
|
||||||
|
end := (i + 1) * batchSize
|
||||||
|
if end > len(permissions) {
|
||||||
|
end = len(permissions)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp := permissions[start:end]
|
||||||
|
// TODO: save to log instead of standard output
|
||||||
|
// fmt.Printf("Add Permissions: [%d - %d].\n", start, end)
|
||||||
|
if AddPermissions(tmp) {
|
||||||
|
affected = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
func DeletePermission(permission *Permission) bool {
|
func DeletePermission(permission *Permission) bool {
|
||||||
affected, err := adapter.Engine.ID(core.PK{permission.Owner, permission.Name}).Delete(&Permission{})
|
affected, err := adapter.Engine.ID(core.PK{permission.Owner, permission.Name}).Delete(&Permission{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
77
object/permission_upload.go
Normal file
77
object/permission_upload.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Copyright 2023 The Casdoor 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 (
|
||||||
|
"github.com/casdoor/casdoor/xlsx"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getPermissionMap(owner string) map[string]*Permission {
|
||||||
|
m := map[string]*Permission{}
|
||||||
|
|
||||||
|
permissions := GetPermissions(owner)
|
||||||
|
for _, permission := range permissions {
|
||||||
|
m[permission.GetId()] = permission
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func UploadPermissions(owner string, fileId string) bool {
|
||||||
|
table := xlsx.ReadXlsxFile(fileId)
|
||||||
|
|
||||||
|
oldUserMap := getPermissionMap(owner)
|
||||||
|
newPermissions := []*Permission{}
|
||||||
|
for index, line := range table {
|
||||||
|
if index == 0 || parseLineItem(&line, 0) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
permission := &Permission{
|
||||||
|
Owner: parseLineItem(&line, 0),
|
||||||
|
Name: parseLineItem(&line, 1),
|
||||||
|
CreatedTime: parseLineItem(&line, 2),
|
||||||
|
DisplayName: parseLineItem(&line, 3),
|
||||||
|
|
||||||
|
Users: parseListItem(&line, 4),
|
||||||
|
Roles: parseListItem(&line, 5),
|
||||||
|
Domains: parseListItem(&line, 6),
|
||||||
|
|
||||||
|
Model: parseLineItem(&line, 7),
|
||||||
|
Adapter: parseLineItem(&line, 8),
|
||||||
|
ResourceType: parseLineItem(&line, 9),
|
||||||
|
|
||||||
|
Resources: parseListItem(&line, 10),
|
||||||
|
Actions: parseListItem(&line, 11),
|
||||||
|
|
||||||
|
Effect: parseLineItem(&line, 12),
|
||||||
|
IsEnabled: parseLineItemBool(&line, 13),
|
||||||
|
|
||||||
|
Submitter: parseLineItem(&line, 14),
|
||||||
|
Approver: parseLineItem(&line, 15),
|
||||||
|
ApproveTime: parseLineItem(&line, 16),
|
||||||
|
State: parseLineItem(&line, 17),
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := oldUserMap[permission.GetId()]; !ok {
|
||||||
|
newPermissions = append(newPermissions, permission)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(newPermissions) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return AddPermissionsInBatch(newPermissions)
|
||||||
|
}
|
@ -16,6 +16,9 @@ package object
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/conf"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"github.com/xorm-io/core"
|
"github.com/xorm-io/core"
|
||||||
@ -160,6 +163,45 @@ func AddRole(role *Role) bool {
|
|||||||
return affected != 0
|
return affected != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AddRoles(roles []*Role) bool {
|
||||||
|
if len(roles) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
affected, err := adapter.Engine.Insert(roles)
|
||||||
|
if err != nil {
|
||||||
|
if !strings.Contains(err.Error(), "Duplicate entry") {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddRolesInBatch(roles []*Role) bool {
|
||||||
|
batchSize := conf.GetConfigBatchSize()
|
||||||
|
|
||||||
|
if len(roles) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
affected := false
|
||||||
|
for i := 0; i < (len(roles)-1)/batchSize+1; i++ {
|
||||||
|
start := i * batchSize
|
||||||
|
end := (i + 1) * batchSize
|
||||||
|
if end > len(roles) {
|
||||||
|
end = len(roles)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp := roles[start:end]
|
||||||
|
// TODO: save to log instead of standard output
|
||||||
|
// fmt.Printf("Add users: [%d - %d].\n", start, end)
|
||||||
|
if AddRoles(tmp) {
|
||||||
|
affected = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
func DeleteRole(role *Role) bool {
|
func DeleteRole(role *Role) bool {
|
||||||
roleId := role.GetId()
|
roleId := role.GetId()
|
||||||
permissions := GetPermissionsByRole(roleId)
|
permissions := GetPermissionsByRole(roleId)
|
||||||
|
63
object/role_upload.go
Normal file
63
object/role_upload.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// Copyright 2023 The Casdoor 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 (
|
||||||
|
"github.com/casdoor/casdoor/xlsx"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getRoleMap(owner string) map[string]*Role {
|
||||||
|
m := map[string]*Role{}
|
||||||
|
|
||||||
|
roles := GetRoles(owner)
|
||||||
|
for _, role := range roles {
|
||||||
|
m[role.GetId()] = role
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func UploadRoles(owner string, fileId string) bool {
|
||||||
|
table := xlsx.ReadXlsxFile(fileId)
|
||||||
|
|
||||||
|
oldUserMap := getRoleMap(owner)
|
||||||
|
newRoles := []*Role{}
|
||||||
|
for index, line := range table {
|
||||||
|
if index == 0 || parseLineItem(&line, 0) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
role := &Role{
|
||||||
|
Owner: parseLineItem(&line, 0),
|
||||||
|
Name: parseLineItem(&line, 1),
|
||||||
|
CreatedTime: parseLineItem(&line, 2),
|
||||||
|
DisplayName: parseLineItem(&line, 3),
|
||||||
|
|
||||||
|
Users: parseListItem(&line, 4),
|
||||||
|
Roles: parseListItem(&line, 5),
|
||||||
|
Domains: parseListItem(&line, 6),
|
||||||
|
IsEnabled: parseLineItemBool(&line, 7),
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := oldUserMap[role.GetId()]; !ok {
|
||||||
|
newRoles = append(newRoles, role)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(newRoles) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return AddRolesInBatch(newRoles)
|
||||||
|
}
|
@ -15,6 +15,9 @@
|
|||||||
package object
|
package object
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"github.com/casdoor/casdoor/xlsx"
|
"github.com/casdoor/casdoor/xlsx"
|
||||||
)
|
)
|
||||||
@ -47,6 +50,26 @@ func parseLineItemBool(line *[]string, i int) bool {
|
|||||||
return parseLineItemInt(line, i) != 0
|
return parseLineItemInt(line, i) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseListItem(lines *[]string, i int) []string {
|
||||||
|
if i >= len(*lines) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
line := (*lines)[i]
|
||||||
|
items := strings.Split(line, ";")
|
||||||
|
trimmedItems := make([]string, 0, len(items))
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
|
trimmedItem := strings.TrimSpace(item)
|
||||||
|
if trimmedItem != "" {
|
||||||
|
trimmedItems = append(trimmedItems, trimmedItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(trimmedItems)
|
||||||
|
|
||||||
|
return trimmedItems
|
||||||
|
}
|
||||||
|
|
||||||
func UploadUsers(owner string, fileId string) bool {
|
func UploadUsers(owner string, fileId string) bool {
|
||||||
table := xlsx.ReadXlsxFile(fileId)
|
table := xlsx.ReadXlsxFile(fileId)
|
||||||
|
|
||||||
|
@ -82,6 +82,7 @@ func initAPI() {
|
|||||||
beego.Router("/api/update-role", &controllers.ApiController{}, "POST:UpdateRole")
|
beego.Router("/api/update-role", &controllers.ApiController{}, "POST:UpdateRole")
|
||||||
beego.Router("/api/add-role", &controllers.ApiController{}, "POST:AddRole")
|
beego.Router("/api/add-role", &controllers.ApiController{}, "POST:AddRole")
|
||||||
beego.Router("/api/delete-role", &controllers.ApiController{}, "POST:DeleteRole")
|
beego.Router("/api/delete-role", &controllers.ApiController{}, "POST:DeleteRole")
|
||||||
|
beego.Router("/api/upload-roles", &controllers.ApiController{}, "POST:UploadRoles")
|
||||||
|
|
||||||
beego.Router("/api/get-permissions", &controllers.ApiController{}, "GET:GetPermissions")
|
beego.Router("/api/get-permissions", &controllers.ApiController{}, "GET:GetPermissions")
|
||||||
beego.Router("/api/get-permissions-by-submitter", &controllers.ApiController{}, "GET:GetPermissionsBySubmitter")
|
beego.Router("/api/get-permissions-by-submitter", &controllers.ApiController{}, "GET:GetPermissionsBySubmitter")
|
||||||
@ -90,6 +91,7 @@ func initAPI() {
|
|||||||
beego.Router("/api/update-permission", &controllers.ApiController{}, "POST:UpdatePermission")
|
beego.Router("/api/update-permission", &controllers.ApiController{}, "POST:UpdatePermission")
|
||||||
beego.Router("/api/add-permission", &controllers.ApiController{}, "POST:AddPermission")
|
beego.Router("/api/add-permission", &controllers.ApiController{}, "POST:AddPermission")
|
||||||
beego.Router("/api/delete-permission", &controllers.ApiController{}, "POST:DeletePermission")
|
beego.Router("/api/delete-permission", &controllers.ApiController{}, "POST:DeletePermission")
|
||||||
|
beego.Router("/api/upload-permissions", &controllers.ApiController{}, "POST:UploadPermissions")
|
||||||
|
|
||||||
beego.Router("/api/enforce", &controllers.ApiController{}, "POST:Enforce")
|
beego.Router("/api/enforce", &controllers.ApiController{}, "POST:Enforce")
|
||||||
beego.Router("/api/batch-enforce", &controllers.ApiController{}, "POST:BatchEnforce")
|
beego.Router("/api/batch-enforce", &controllers.ApiController{}, "POST:BatchEnforce")
|
||||||
|
@ -14,13 +14,14 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
import {Button, Switch, Table} from "antd";
|
import {Button, Switch, Table, Upload} from "antd";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import * as Setting from "./Setting";
|
import * as Setting from "./Setting";
|
||||||
import * as PermissionBackend from "./backend/PermissionBackend";
|
import * as PermissionBackend from "./backend/PermissionBackend";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import BaseListPage from "./BaseListPage";
|
import BaseListPage from "./BaseListPage";
|
||||||
import PopconfirmModal from "./common/modal/PopconfirmModal";
|
import PopconfirmModal from "./common/modal/PopconfirmModal";
|
||||||
|
import {UploadOutlined} from "@ant-design/icons";
|
||||||
|
|
||||||
class PermissionListPage extends BaseListPage {
|
class PermissionListPage extends BaseListPage {
|
||||||
newPermission() {
|
newPermission() {
|
||||||
@ -79,6 +80,40 @@ class PermissionListPage extends BaseListPage {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uploadPermissionFile(info) {
|
||||||
|
const {status, response: res} = info.file;
|
||||||
|
if (status === "done") {
|
||||||
|
if (res.status === "ok") {
|
||||||
|
Setting.showMessage("success", "Users uploaded successfully, refreshing the page");
|
||||||
|
|
||||||
|
const {pagination} = this.state;
|
||||||
|
this.fetch({pagination});
|
||||||
|
} else {
|
||||||
|
Setting.showMessage("error", `Users failed to upload: ${res.msg}`);
|
||||||
|
}
|
||||||
|
} else if (status === "error") {
|
||||||
|
Setting.showMessage("error", "File failed to upload");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
renderPermissionUpload() {
|
||||||
|
const props = {
|
||||||
|
name: "file",
|
||||||
|
accept: ".xlsx",
|
||||||
|
method: "post",
|
||||||
|
action: `${Setting.ServerUrl}/api/upload-permissions`,
|
||||||
|
withCredentials: true,
|
||||||
|
onChange: (info) => {
|
||||||
|
this.uploadPermissionFile(info);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Upload {...props}>
|
||||||
|
<Button type="primary" size="small">
|
||||||
|
<UploadOutlined /> {i18next.t("user:Upload (.xlsx)")}
|
||||||
|
</Button></Upload>
|
||||||
|
);
|
||||||
|
}
|
||||||
renderTable(permissions) {
|
renderTable(permissions) {
|
||||||
const columns = [
|
const columns = [
|
||||||
// https://github.com/ant-design/ant-design/issues/22184
|
// https://github.com/ant-design/ant-design/issues/22184
|
||||||
@ -325,7 +360,10 @@ class PermissionListPage extends BaseListPage {
|
|||||||
title={() => (
|
title={() => (
|
||||||
<div>
|
<div>
|
||||||
{i18next.t("general:Permissions")}
|
{i18next.t("general:Permissions")}
|
||||||
<Button type="primary" size="small" onClick={this.addPermission.bind(this)}>{i18next.t("general:Add")}</Button>
|
<Button style={{marginRight: "5px"}} type="primary" size="small" onClick={this.addPermission.bind(this)}>{i18next.t("general:Add")}</Button>
|
||||||
|
{
|
||||||
|
this.renderPermissionUpload()
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
loading={this.state.loading}
|
loading={this.state.loading}
|
||||||
|
@ -14,13 +14,14 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
import {Button, Switch, Table} from "antd";
|
import {Button, Switch, Table, Upload} from "antd";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import * as Setting from "./Setting";
|
import * as Setting from "./Setting";
|
||||||
import * as RoleBackend from "./backend/RoleBackend";
|
import * as RoleBackend from "./backend/RoleBackend";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import BaseListPage from "./BaseListPage";
|
import BaseListPage from "./BaseListPage";
|
||||||
import PopconfirmModal from "./common/modal/PopconfirmModal";
|
import PopconfirmModal from "./common/modal/PopconfirmModal";
|
||||||
|
import {UploadOutlined} from "@ant-design/icons";
|
||||||
|
|
||||||
class RoleListPage extends BaseListPage {
|
class RoleListPage extends BaseListPage {
|
||||||
newRole() {
|
newRole() {
|
||||||
@ -71,6 +72,42 @@ class RoleListPage extends BaseListPage {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uploadRoleFile(info) {
|
||||||
|
const {status, response: res} = info.file;
|
||||||
|
if (status === "done") {
|
||||||
|
if (res.status === "ok") {
|
||||||
|
Setting.showMessage("success", "Users uploaded successfully, refreshing the page");
|
||||||
|
|
||||||
|
const {pagination} = this.state;
|
||||||
|
this.fetch({pagination});
|
||||||
|
} else {
|
||||||
|
Setting.showMessage("error", `Users failed to upload: ${res.msg}`);
|
||||||
|
}
|
||||||
|
} else if (status === "error") {
|
||||||
|
Setting.showMessage("error", "File failed to upload");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderRoleUpload() {
|
||||||
|
const props = {
|
||||||
|
name: "file",
|
||||||
|
accept: ".xlsx",
|
||||||
|
method: "post",
|
||||||
|
action: `${Setting.ServerUrl}/api/upload-roles`,
|
||||||
|
withCredentials: true,
|
||||||
|
onChange: (info) => {
|
||||||
|
this.uploadRoleFile(info);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Upload {...props}>
|
||||||
|
<Button type="primary" size="small">
|
||||||
|
<UploadOutlined /> {i18next.t("user:Upload (.xlsx)")}
|
||||||
|
</Button>
|
||||||
|
</Upload>
|
||||||
|
);
|
||||||
|
}
|
||||||
renderTable(roles) {
|
renderTable(roles) {
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@ -200,7 +237,10 @@ class RoleListPage extends BaseListPage {
|
|||||||
title={() => (
|
title={() => (
|
||||||
<div>
|
<div>
|
||||||
{i18next.t("general:Roles")}
|
{i18next.t("general:Roles")}
|
||||||
<Button type="primary" size="small" onClick={this.addRole.bind(this)}>{i18next.t("general:Add")}</Button>
|
<Button style={{marginRight: "5px"}} type="primary" size="small" onClick={this.addRole.bind(this)}>{i18next.t("general:Add")}</Button>
|
||||||
|
{
|
||||||
|
this.renderRoleUpload()
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
loading={this.state.loading}
|
loading={this.state.loading}
|
||||||
|
BIN
xlsx/permission_test.xlsx
Normal file
BIN
xlsx/permission_test.xlsx
Normal file
Binary file not shown.
BIN
xlsx/role_test.xlsx
Normal file
BIN
xlsx/role_test.xlsx
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user