aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-11-20 20:14:12 +0800
committercrupest <crupest@outlook.com>2020-11-20 20:14:12 +0800
commitcf06a813e77dae460e6540706bc0c90338ea9ed3 (patch)
tree224d1726a284a680d6e602e31a14322e177834a5
parent40a2dff74ccc053145d68c7d9b38146e067dfdd4 (diff)
downloadtimeline-cf06a813e77dae460e6540706bc0c90338ea9ed3.tar.gz
timeline-cf06a813e77dae460e6540706bc0c90338ea9ed3.tar.bz2
timeline-cf06a813e77dae460e6540706bc0c90338ea9ed3.zip
...
-rw-r--r--FrontEnd/src/app/http/user.ts10
-rw-r--r--FrontEnd/src/app/views/admin/UserAdmin.tsx213
2 files changed, 165 insertions, 58 deletions
diff --git a/FrontEnd/src/app/http/user.ts b/FrontEnd/src/app/http/user.ts
index 243846d1..929956d0 100644
--- a/FrontEnd/src/app/http/user.ts
+++ b/FrontEnd/src/app/http/user.ts
@@ -12,10 +12,14 @@ import {
convertToNotModified,
} from "./common";
+export const kUserManagement = "UserManagement";
+export const kAllTimelineManagement = "AllTimelineManagement";
+export const kHighlightTimelineManagement = "HighlightTimelineManagement";
+
export const kUserPermissionList = [
- "UserManagement",
- "AllTimelineManagement",
- "HighlightTimelineManagement",
+ kUserManagement,
+ kAllTimelineManagement,
+ kHighlightTimelineManagement,
] as const;
export type UserPermission = typeof kUserPermissionList[number];
diff --git a/FrontEnd/src/app/views/admin/UserAdmin.tsx b/FrontEnd/src/app/views/admin/UserAdmin.tsx
index 65cd3b74..bd60381f 100644
--- a/FrontEnd/src/app/views/admin/UserAdmin.tsx
+++ b/FrontEnd/src/app/views/admin/UserAdmin.tsx
@@ -1,64 +1,20 @@
import React, { useState, useEffect } from "react";
+import clsx from "clsx";
import { ListGroup, Row, Col, Spinner, Button } from "react-bootstrap";
import InlineSVG from "react-inlinesvg";
import PencilSquareIcon from "bootstrap-icons/icons/pencil-square.svg";
-import OperationDialog from "../common/OperationDialog";
+import OperationDialog, {
+ OperationBoolInputInfo,
+} from "../common/OperationDialog";
import { User, AuthUser } from "@/services/user";
-import { getHttpUserClient, HttpUser } from "@/http/user";
-import clsx from "clsx";
-
-const kModify = "modify";
-const kDelete = "delete";
-
-type TModify = typeof kModify;
-type TDelete = typeof kDelete;
-
-type ContextMenuItem = TModify | TDelete;
-
-interface UserCardProps {
- on: { [key in ContextMenuItem]: () => void };
- user: User;
-}
-
-const UserItem: React.FC<UserCardProps> = ({ user, on }) => {
- const [editMaskVisible, setEditMaskVisible] = React.useState<boolean>(false);
-
- return (
- <ListGroup.Item className="admin-user-item">
- <InlineSVG
- src={PencilSquareIcon}
- className="float-right icon-button text-warning"
- onClick={() => setEditMaskVisible(true)}
- />
- <h4 className="text-primary">{user.username}</h4>
- <div className="text-secondary">nickname: {user.nickname}</div>
- <div className="text-secondary">unique id: {user.uniqueId}</div>
- <div className="text-secondary">
- permissions:{" "}
- {user.permissions.map((permission) => {
- return (
- <span key={permission} className="text-danger">
- {permission}{" "}
- </span>
- );
- })}
- </div>
- <div
- className={clsx("edit-mask", !editMaskVisible && "d-none")}
- onClick={() => setEditMaskVisible(false)}
- >
- <button className="text-button primary" onClick={on["modify"]}>
- Modify
- </button>
- <button className="text-button danger" onClick={on["delete"]}>
- Delete
- </button>
- </div>
- </ListGroup.Item>
- );
-};
+import {
+ getHttpUserClient,
+ HttpUser,
+ kUserPermissionList,
+ UserPermission,
+} from "@/http/user";
interface DialogProps<TData = undefined, TReturn = undefined> {
open: boolean;
@@ -167,6 +123,127 @@ const UserModifyDialog: React.FC<DialogProps<
);
};
+const UserPermissionModifyDialog: React.FC<DialogProps<
+ {
+ username: string;
+ permissions: UserPermission[];
+ },
+ UserPermission[]
+>> = ({ open, close, token, data: { username, permissions }, onSuccess }) => {
+ const oldPermissionBoolList: boolean[] = kUserPermissionList.map(
+ (permission) => permissions.includes(permission)
+ );
+
+ return (
+ <OperationDialog
+ open={open}
+ close={close}
+ title="Caution"
+ titleColor="dangerous"
+ inputPrompt={() => (
+ <>
+ You are modify permission of user
+ <UsernameLabel>{username}</UsernameLabel> !
+ </>
+ )}
+ inputScheme={kUserPermissionList.map<OperationBoolInputInfo>(
+ (permission, index) => ({
+ type: "bool",
+ label: permission,
+ initValue: oldPermissionBoolList[index],
+ })
+ )}
+ onProcess={async (newPermissionBoolList): Promise<boolean[]> => {
+ for (let index = 0; index < kUserPermissionList.length; index++) {
+ const oldValue = oldPermissionBoolList[index];
+ const newValue = newPermissionBoolList[index];
+ const permission = kUserPermissionList[index];
+ if (oldValue === newValue) continue;
+ if (newValue) {
+ await getHttpUserClient().putUserPermission(
+ username,
+ permission,
+ token
+ );
+ } else {
+ await getHttpUserClient().deleteUserPermission(
+ username,
+ permission,
+ token
+ );
+ }
+ }
+ return newPermissionBoolList;
+ }}
+ onSuccessAndClose={(newPermissionBoolList: boolean[]) => {
+ const permissions: UserPermission[] = [];
+ for (let index = 0; index < kUserPermissionList.length; index++) {
+ if (newPermissionBoolList[index]) {
+ permissions.push(kUserPermissionList[index]);
+ }
+ }
+ onSuccess(permissions);
+ }}
+ />
+ );
+};
+
+const kModify = "modify";
+const kModifyPermission = "permission";
+const kDelete = "delete";
+
+type TModify = typeof kModify;
+type TModifyPermission = typeof kModifyPermission;
+type TDelete = typeof kDelete;
+
+type ContextMenuItem = TModify | TModifyPermission | TDelete;
+
+interface UserItemProps {
+ on: { [key in ContextMenuItem]: () => void };
+ user: User;
+}
+
+const UserItem: React.FC<UserItemProps> = ({ user, on }) => {
+ const [editMaskVisible, setEditMaskVisible] = React.useState<boolean>(false);
+
+ return (
+ <ListGroup.Item className="admin-user-item">
+ <InlineSVG
+ src={PencilSquareIcon}
+ className="float-right icon-button text-warning"
+ onClick={() => setEditMaskVisible(true)}
+ />
+ <h4 className="text-primary">{user.username}</h4>
+ <div className="text-secondary">nickname: {user.nickname}</div>
+ <div className="text-secondary">unique id: {user.uniqueId}</div>
+ <div className="text-secondary">
+ permissions:{" "}
+ {user.permissions.map((permission) => {
+ return (
+ <span key={permission} className="text-danger">
+ {permission}{" "}
+ </span>
+ );
+ })}
+ </div>
+ <div
+ className={clsx("edit-mask", !editMaskVisible && "d-none")}
+ onClick={() => setEditMaskVisible(false)}
+ >
+ <button className="text-button primary" onClick={on[kModify]}>
+ Modify
+ </button>
+ <button className="text-button primary" onClick={on[kModifyPermission]}>
+ Modify Permission
+ </button>
+ <button className="text-button danger" onClick={on[kDelete]}>
+ Delete
+ </button>
+ </div>
+ </ListGroup.Item>
+ );
+};
+
interface UserAdminProps {
user: AuthUser;
}
@@ -181,6 +258,11 @@ const UserAdmin: React.FC<UserAdminProps> = (props) => {
type: TModify;
user: HttpUser;
}
+ | {
+ type: TModifyPermission;
+ username: string;
+ permissions: UserPermission[];
+ }
| { type: TDelete; username: string };
const [users, setUsers] = useState<User[] | null>(null);
@@ -220,7 +302,7 @@ const UserAdmin: React.FC<UserAdminProps> = (props) => {
/>
);
break;
- case "delete":
+ case kDelete:
dialogNode = (
<UserDeleteDialog
open
@@ -242,6 +324,20 @@ const UserAdmin: React.FC<UserAdminProps> = (props) => {
/>
);
break;
+ case kModifyPermission:
+ dialogNode = (
+ <UserPermissionModifyDialog
+ open
+ close={() => setDialog(null)}
+ token={token}
+ data={{
+ username: dialog.username,
+ permissions: dialog.permissions,
+ }}
+ onSuccess={updateUsers}
+ />
+ );
+ break;
}
}
@@ -258,6 +354,13 @@ const UserAdmin: React.FC<UserAdminProps> = (props) => {
user,
});
},
+ permission: () => {
+ setDialog({
+ type: kModifyPermission,
+ username: user.username,
+ permissions: user.permissions,
+ });
+ },
delete: () => {
setDialog({
type: "delete",