From a687a23a641ca262dbffd383af129a0069fbc5ee Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 16 Nov 2020 16:30:32 +0800 Subject: ... --- FrontEnd/src/app/http/user.ts | 46 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'FrontEnd/src/app/http') diff --git a/FrontEnd/src/app/http/user.ts b/FrontEnd/src/app/http/user.ts index a0a02cce..9ba6508f 100644 --- a/FrontEnd/src/app/http/user.ts +++ b/FrontEnd/src/app/http/user.ts @@ -12,10 +12,18 @@ import { convertToNotModified, } from "./common"; +export const kUserPermissionList = [ + "UserManagement", + "AllTimelineManagement", + "HighlightTimelineManagement", +] as const; + +export type UserPermission = typeof kUserPermissionList[number]; + export interface HttpUser { uniqueId: string; username: string; - administrator: boolean; + permissions: UserPermission[]; nickname: string; } @@ -54,6 +62,16 @@ export interface IHttpUserClient { ): Promise; putAvatar(username: string, data: Blob, token: string): Promise; changePassword(req: HttpChangePasswordRequest, token: string): Promise; + putUserPermission( + username: string, + permission: UserPermission, + token: string + ): Promise; + deleteUserPermission( + username: string, + permission: UserPermission, + token: string + ): Promise; } export class HttpUserClient implements IHttpUserClient { @@ -119,6 +137,32 @@ export class HttpUserClient implements IHttpUserClient { .catch(convertToNetworkError) .then(); } + + putUserPermission( + username: string, + permission: UserPermission, + token: string + ): Promise { + return axios + .put( + `${apiBaseUrl}/users/${username}/permissions/${permission}?token=${token}` + ) + .catch(convertToNetworkError) + .then(); + } + + deleteUserPermission( + username: string, + permission: UserPermission, + token: string + ): Promise { + return axios + .delete( + `${apiBaseUrl}/users/${username}/permissions/${permission}?token=${token}` + ) + .catch(convertToNetworkError) + .then(); + } } let client: IHttpUserClient = new HttpUserClient(); -- cgit v1.2.3 From 711a148fbbf4361f9c0632eff973c2f240a67c5d Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 16 Nov 2020 17:20:42 +0800 Subject: ... --- FrontEnd/src/app/http/user.ts | 8 +++ FrontEnd/src/app/views/admin/Admin.tsx | 64 ++++----------------- FrontEnd/src/app/views/admin/AdminSubPage.tsx | 44 +++++++++++++++ FrontEnd/src/app/views/admin/UserAdmin.tsx | 80 ++++++--------------------- 4 files changed, 80 insertions(+), 116 deletions(-) create mode 100644 FrontEnd/src/app/views/admin/AdminSubPage.tsx (limited to 'FrontEnd/src/app/http') diff --git a/FrontEnd/src/app/http/user.ts b/FrontEnd/src/app/http/user.ts index 9ba6508f..92a6433e 100644 --- a/FrontEnd/src/app/http/user.ts +++ b/FrontEnd/src/app/http/user.ts @@ -49,6 +49,7 @@ export class HttpChangePasswordBadCredentialError extends Error { } export interface IHttpUserClient { + list(): Promise; get(username: string): Promise; patch( username: string, @@ -75,6 +76,13 @@ export interface IHttpUserClient { } export class HttpUserClient implements IHttpUserClient { + list(): Promise { + return axios + .get(`${apiBaseUrl}/users`) + .then(extractResponseData) + .catch(convertToNetworkError); + } + get(username: string): Promise { return axios .get(`${apiBaseUrl}/users/${username}`) diff --git a/FrontEnd/src/app/views/admin/Admin.tsx b/FrontEnd/src/app/views/admin/Admin.tsx index a64a9bc0..e17da5bc 100644 --- a/FrontEnd/src/app/views/admin/Admin.tsx +++ b/FrontEnd/src/app/views/admin/Admin.tsx @@ -1,12 +1,5 @@ import React, { Fragment } from "react"; -import { - Redirect, - Route, - Switch, - useRouteMatch, - useHistory, -} from "react-router"; -import { Nav } from "react-bootstrap"; +import { Redirect, Route, Switch, useRouteMatch, match } from "react-router"; import { AuthUser } from "@/services/user"; @@ -16,57 +9,22 @@ interface AdminProps { user: AuthUser; } -const Admin: React.FC = (props) => { +const Admin: React.FC = ({ user }) => { const match = useRouteMatch(); - const history = useHistory(); - type TabNames = "users" | "more"; - - const tabName = history.location.pathname.replace(match.path + "/", ""); - - function toggle(newTab: TabNames): void { - history.push(`${match.url}/${newTab}`); - } - - const createRoute = ( - name: string, - body: React.ReactNode - ): React.ReactNode => { - return ( - -
- - {body} - - ); - }; return ( - {createRoute("users", )} - {createRoute("more",
More Page Works
)} + + {(p) => { + const match = p.match as match<{ name: string }>; + const name = match.params["name"]; + if (name === "users") { + return ; + } + }} +
); diff --git a/FrontEnd/src/app/views/admin/AdminSubPage.tsx b/FrontEnd/src/app/views/admin/AdminSubPage.tsx new file mode 100644 index 00000000..5d2df13c --- /dev/null +++ b/FrontEnd/src/app/views/admin/AdminSubPage.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import { Nav } from "react-bootstrap"; +import { useHistory, useRouteMatch } from "react-router"; + +const AdminSubPage: React.FC = ({ children }) => { + const match = useRouteMatch<{ name: string }>(); + const history = useHistory(); + + const name = match.params.name; + + function toggle(newTab: string): void { + history.push(`/admin/${newTab}`); + } + + return ( + <> + + {children} + + ); +}; + +export default AdminSubPage; diff --git a/FrontEnd/src/app/views/admin/UserAdmin.tsx b/FrontEnd/src/app/views/admin/UserAdmin.tsx index 4ad9ed09..856e6136 100644 --- a/FrontEnd/src/app/views/admin/UserAdmin.tsx +++ b/FrontEnd/src/app/views/admin/UserAdmin.tsx @@ -10,19 +10,16 @@ import { } from "react-bootstrap"; import OperationDialog from "../common/OperationDialog"; +import AdminSubPage from "./AdminSubPage"; + import { User, AuthUser } from "@/services/user"; +import { getHttpUserClient } from "@/http/user"; const apiBaseUrl = "/api"; -async function fetchUserList(_token: string): Promise { - const res = await axios.get(`${apiBaseUrl}/users`); - return res.data; -} - interface CreateUserInfo { username: string; password: string; - administrator: boolean; } async function createUser(user: CreateUserInfo, token: string): Promise { @@ -57,16 +54,6 @@ function changePassword( }); } -function changePermission( - username: string, - newPermission: boolean, - token: string -): Promise { - return axios.patch(`${apiBaseUrl}/users/${username}?token=${token}`, { - administrator: newPermission, - }); -} - const kChangeUsername = "changeusername"; const kChangePassword = "changepassword"; const kChangePermission = "changepermission"; @@ -103,9 +90,9 @@ const UserItem: React.FC = (props) => {

{user.username}

- {user.administrator ? "administrator" : "user"} + {user.permissions ? "administrator" : "user"} @@ -156,14 +143,12 @@ const CreateUserDialog: React.FC = (props) => { [ { type: "text", label: "Username" }, { type: "text", label: "Password" }, - { type: "bool", label: "Administrator" }, ] as const } - onProcess={([username, password, administrator]) => + onProcess={([username, password]) => props.process({ username: username, password: password, - administrator: administrator, }) } close={props.close} @@ -316,15 +301,17 @@ const UserAdmin: React.FC = (props) => { useEffect(() => { let subscribe = true; - void fetchUserList(props.user.token).then((us) => { - if (subscribe) { - setUsers(us); - } - }); + void getHttpUserClient() + .list() + .then((us) => { + if (subscribe) { + setUsers(us); + } + }); return () => { subscribe = false; }; - }, [props.user]); + }, []); let dialogNode: React.ReactNode; if (dialog) @@ -389,26 +376,6 @@ const UserAdmin: React.FC = (props) => { ); break; case kChangePermission: { - const newPermission = dialog.newPermission; - dialogNode = ( - setDialog(null)} - username={dialog.username} - newPermission={newPermission} - process={async () => { - await changePermission(dialog.username, newPermission, token); - setUsers((oldUsers) => { - const users = (oldUsers ?? []).slice(); - const findedUser = users.find( - (u) => u.username === dialog.username - ); - if (findedUser) findedUser.administrator = newPermission; - return users; - }); - }} - /> - ); break; } } @@ -419,26 +386,13 @@ const UserAdmin: React.FC = (props) => { { - setDialog( - item === kChangePermission - ? { - type: kChangePermission, - username: user.username, - newPermission: !user.administrator, - } - : { - type: item, - username: user.username, - } - ); - }} + onContextMenu={(item) => {}} /> ); }); return ( - <> + {userComponents} {dialogNode} - + ); } else { return ; -- cgit v1.2.3 From e51e3b7c3c987f52823798b749e6c6deb2bfbe38 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 17 Nov 2020 17:31:42 +0800 Subject: ... --- FrontEnd/src/app/http/user.ts | 25 ++ FrontEnd/src/app/views/admin/AdminSubPage.tsx | 18 +- FrontEnd/src/app/views/admin/UserAdmin.tsx | 352 +++++++--------------- FrontEnd/src/app/views/common/OperationDialog.tsx | 31 +- 4 files changed, 163 insertions(+), 263 deletions(-) (limited to 'FrontEnd/src/app/http') diff --git a/FrontEnd/src/app/http/user.ts b/FrontEnd/src/app/http/user.ts index 92a6433e..243846d1 100644 --- a/FrontEnd/src/app/http/user.ts +++ b/FrontEnd/src/app/http/user.ts @@ -28,6 +28,8 @@ export interface HttpUser { } export interface HttpUserPatchRequest { + username?: string; + password?: string; nickname?: string; } @@ -36,6 +38,11 @@ export interface HttpChangePasswordRequest { newPassword: string; } +export interface HttpCreateUserRequest { + username: string; + password: string; +} + export class HttpUserNotExistError extends Error { constructor(public innerError?: AxiosError) { super(); @@ -56,6 +63,7 @@ export interface IHttpUserClient { req: HttpUserPatchRequest, token: string ): Promise; + delete(username: string, token: string): Promise; getAvatar(username: string): Promise; getAvatar( username: string, @@ -73,6 +81,8 @@ export interface IHttpUserClient { permission: UserPermission, token: string ): Promise; + + createUser(req: HttpCreateUserRequest, token: string): Promise; } export class HttpUserClient implements IHttpUserClient { @@ -102,6 +112,13 @@ export class HttpUserClient implements IHttpUserClient { .catch(convertToNetworkError); } + delete(username: string, token: string): Promise { + return axios + .delete(`${apiBaseUrl}/users/${username}?token=${token}`) + .catch(convertToNetworkError) + .then(); + } + getAvatar(username: string): Promise; getAvatar( username: string, @@ -171,6 +188,14 @@ export class HttpUserClient implements IHttpUserClient { .catch(convertToNetworkError) .then(); } + + createUser(req: HttpCreateUserRequest, token: string): Promise { + return axios + .post(`${apiBaseUrl}/userop/createuser?token=${token}`, req) + .then(extractResponseData) + .catch(convertToNetworkError) + .then(); + } } let client: IHttpUserClient = new HttpUserClient(); diff --git a/FrontEnd/src/app/views/admin/AdminSubPage.tsx b/FrontEnd/src/app/views/admin/AdminSubPage.tsx index 5d2df13c..5efe1ee3 100644 --- a/FrontEnd/src/app/views/admin/AdminSubPage.tsx +++ b/FrontEnd/src/app/views/admin/AdminSubPage.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Nav } from "react-bootstrap"; +import { Container, Nav } from "react-bootstrap"; import { useHistory, useRouteMatch } from "react-router"; const AdminSubPage: React.FC = ({ children }) => { @@ -13,8 +13,8 @@ const AdminSubPage: React.FC = ({ children }) => { } return ( - <> -