Browse Source

assign user role part1

Signed-off-by: shanghaikid <jiangruiyi@gmail.com>
shanghaikid 1 year ago
parent
commit
279be35f97

+ 16 - 0
client/src/http/User.ts

@@ -4,6 +4,8 @@ import {
   UpdateUserParams,
   UpdateUserParams,
   CreateRoleParams,
   CreateRoleParams,
   DeleteRoleParams,
   DeleteRoleParams,
+  AssignRoleParams,
+  UnassignRoleParams,
 } from '../pages/user/Types';
 } from '../pages/user/Types';
 import BaseModel from './BaseModel';
 import BaseModel from './BaseModel';
 
 
@@ -45,6 +47,20 @@ export class UserHttp extends BaseModel {
     return super.delete({ path: `${this.USER_URL}/roles/${data.roleName}` });
     return super.delete({ path: `${this.USER_URL}/roles/${data.roleName}` });
   }
   }
 
 
+  static assignUserRole(data: AssignRoleParams) {
+    return super.update({
+      path: `${this.USER_URL}/${data.username}/role/assign`,
+      data,
+    });
+  }
+
+  static unassignUserRole(data: UnassignRoleParams) {
+    return super.update({
+      path: `${this.USER_URL}/${data.username}/role/unassign`,
+      data,
+    });
+  }
+
   get _names() {
   get _names() {
     return this.names;
     return this.names;
   }
   }

+ 47 - 2
client/src/pages/user/CreateUser.tsx

@@ -1,4 +1,10 @@
-import { makeStyles, Theme } from '@material-ui/core';
+import {
+  makeStyles,
+  Theme,
+  Checkbox,
+  FormGroup,
+  FormControlLabel,
+} from '@material-ui/core';
 import { FC, useMemo, useState } from 'react';
 import { FC, useMemo, useState } from 'react';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
 import DialogTemplate from '@/components/customDialog/DialogTemplate';
 import DialogTemplate from '@/components/customDialog/DialogTemplate';
@@ -12,9 +18,19 @@ const useStyles = makeStyles((theme: Theme) => ({
   input: {
   input: {
     margin: theme.spacing(3, 0, 0.5),
     margin: theme.spacing(3, 0, 0.5),
   },
   },
+  dialogWrapper: {
+    maxWidth: theme.spacing(70),
+    '& .MuiFormControlLabel-root': {
+      width: theme.spacing(20),
+    },
+  },
 }));
 }));
 
 
-const CreateUser: FC<CreateUserProps> = ({ handleCreate, handleClose }) => {
+const CreateUser: FC<CreateUserProps> = ({
+  handleCreate,
+  handleClose,
+  roles,
+}) => {
   const { t: commonTrans } = useTranslation();
   const { t: commonTrans } = useTranslation();
   const { t: userTrans } = useTranslation('user');
   const { t: userTrans } = useTranslation('user');
   const { t: btnTrans } = useTranslation('btn');
   const { t: btnTrans } = useTranslation('btn');
@@ -24,10 +40,14 @@ const CreateUser: FC<CreateUserProps> = ({ handleCreate, handleClose }) => {
   const [form, setForm] = useState<CreateUserParams>({
   const [form, setForm] = useState<CreateUserParams>({
     username: '',
     username: '',
     password: '',
     password: '',
+    roles: [],
   });
   });
+
+  // selected Role
   const checkedForm = useMemo(() => {
   const checkedForm = useMemo(() => {
     return formatForm(form);
     return formatForm(form);
   }, [form]);
   }, [form]);
+
   const { validation, checkIsValid, disabled } = useFormValidation(checkedForm);
   const { validation, checkIsValid, disabled } = useFormValidation(checkedForm);
 
 
   const classes = useStyles();
   const classes = useStyles();
@@ -87,6 +107,7 @@ const CreateUser: FC<CreateUserProps> = ({ handleCreate, handleClose }) => {
       confirmLabel={btnTrans('create')}
       confirmLabel={btnTrans('create')}
       handleConfirm={handleCreateUser}
       handleConfirm={handleCreateUser}
       confirmDisabled={disabled}
       confirmDisabled={disabled}
+      dialogClass={classes.dialogWrapper}
     >
     >
       <>
       <>
         {createConfigs.map(v => (
         {createConfigs.map(v => (
@@ -98,6 +119,30 @@ const CreateUser: FC<CreateUserProps> = ({ handleCreate, handleClose }) => {
             key={v.label}
             key={v.label}
           />
           />
         ))}
         ))}
+
+        <FormGroup row>
+          {roles.map((r: any, index: number) => (
+            <FormControlLabel
+              control={<Checkbox />}
+              key={index}
+              label={r.label}
+              value={r.value}
+              onChange={(e: React.ChangeEvent<{}>, checked: boolean) => {
+                let newRoles = [...form.roles];
+
+                if (!checked) {
+                  newRoles = newRoles.filter(
+                    (n: string | number) => n === r.vlaue
+                  );
+                } else {
+                  newRoles.push(r.value);
+                }
+
+                setForm(v => ({ ...v, roles: [...newRoles] }));
+              }}
+            />
+          ))}
+        </FormGroup>
       </>
       </>
     </DialogTemplate>
     </DialogTemplate>
   );
   );

+ 12 - 0
client/src/pages/user/Types.ts

@@ -1,15 +1,20 @@
+import { Option } from '@/components/customSelector/Types';
+
 export interface UserData {
 export interface UserData {
   name: string;
   name: string;
+  roleName?: string;
 }
 }
 
 
 export interface CreateUserParams {
 export interface CreateUserParams {
   username: string;
   username: string;
   password: string;
   password: string;
+  roles: string[];
 }
 }
 
 
 export interface CreateUserProps {
 export interface CreateUserProps {
   handleCreate: (data: CreateUserParams) => void;
   handleCreate: (data: CreateUserParams) => void;
   handleClose: () => void;
   handleClose: () => void;
+  roles: Option[]
 }
 }
 
 
 export interface UpdateUserProps {
 export interface UpdateUserProps {
@@ -41,6 +46,13 @@ export interface DeleteRoleParams {
   roleName: string;
   roleName: string;
 }
 }
 
 
+export interface AssignRoleParams {
+  username: string;
+  roleName: string;
+}
+
+export interface UnassignRoleParams extends AssignRoleParams {}
+
 export interface RoleData {
 export interface RoleData {
   name: string;
   name: string;
 }
 }

+ 38 - 3
client/src/pages/user/User.tsx

@@ -38,12 +38,36 @@ const Users = () => {
 
 
   const fetchUsers = async () => {
   const fetchUsers = async () => {
     const res = await UserHttp.getUsers();
     const res = await UserHttp.getUsers();
-
-    setUsers(res.usernames.map((v: string) => ({ name: v })));
+    const roles = await UserHttp.getRoles();
+    setUsers(
+      res.usernames.map((v: string) => {
+        const name = v;
+        const rolesByName = roles.results.filter((r: any) =>
+          r.users.map((u: any) => u.name).includes(name)
+        );
+        return {
+          name: v,
+          role:
+            v === 'root'
+              ? 'root'
+              : rolesByName.map((r: any) => r.role.name).join(','),
+        };
+      })
+    );
   };
   };
 
 
   const handleCreate = async (data: CreateUserParams) => {
   const handleCreate = async (data: CreateUserParams) => {
     await UserHttp.createUser(data);
     await UserHttp.createUser(data);
+    console.log(data, data.roles);
+    // assign user role if
+    if (data.roles.length > 0) {
+      console.log('assign roles');
+      // await UserHttp.assignUserRole({
+      //   username: data.username,
+      //   roleName: data.roleName,
+      // });
+    }
+
     fetchUsers();
     fetchUsers();
     openSnackBar(successTrans('create', { name: userTrans('user') }));
     openSnackBar(successTrans('create', { name: userTrans('user') }));
     handleCloseDialog();
     handleCloseDialog();
@@ -72,7 +96,8 @@ const Users = () => {
   const toolbarConfigs: ToolBarConfig[] = [
   const toolbarConfigs: ToolBarConfig[] = [
     {
     {
       label: userTrans('user'),
       label: userTrans('user'),
-      onClick: () => {
+      onClick: async () => {
+        const roles = await UserHttp.getRoles();
         setDialog({
         setDialog({
           open: true,
           open: true,
           type: 'custom',
           type: 'custom',
@@ -81,6 +106,9 @@ const Users = () => {
               <CreateUser
               <CreateUser
                 handleCreate={handleCreate}
                 handleCreate={handleCreate}
                 handleClose={handleCloseDialog}
                 handleClose={handleCloseDialog}
+                roles={roles.results.map((r: any) => {
+                  return { label: r.role.name, value: r.role.name };
+                })}
               />
               />
             ),
             ),
           },
           },
@@ -124,11 +152,18 @@ const Users = () => {
       disablePadding: false,
       disablePadding: false,
       label: userTrans('user'),
       label: userTrans('user'),
     },
     },
+    {
+      id: 'role',
+      align: 'left',
+      disablePadding: false,
+      label: userTrans('role'),
+    },
     {
     {
       id: 'action',
       id: 'action',
       disablePadding: false,
       disablePadding: false,
       label: 'Action',
       label: 'Action',
       showActionCell: true,
       showActionCell: true,
+      sortBy: 'action',
       actionBarConfigs: [
       actionBarConfigs: [
         {
         {
           onClick: (e: React.MouseEvent, row: UserData) => {
           onClick: (e: React.MouseEvent, row: UserData) => {

+ 16 - 0
server/src/users/dto.ts

@@ -23,3 +23,19 @@ export class UpdateUserDto {
   @IsString()
   @IsString()
   readonly newPassword: string;
   readonly newPassword: string;
 }
 }
+
+export class AssignUserRoleDto {
+  @IsString()
+  readonly username: string;
+
+  @IsString()
+  readonly roleName: string;
+}
+
+export class UnassignUserRoleDto {
+  @IsString()
+  readonly username: string;
+
+  @IsString()
+  readonly roleName: string;
+}

+ 50 - 2
server/src/users/users.controller.ts

@@ -2,8 +2,13 @@ import { NextFunction, Request, Response, Router } from 'express';
 import { dtoValidationMiddleware } from '../middlewares/validation';
 import { dtoValidationMiddleware } from '../middlewares/validation';
 import { UserService } from './users.service';
 import { UserService } from './users.service';
 import { milvusService } from '../milvus';
 import { milvusService } from '../milvus';
-
-import { CreateUserDto, UpdateUserDto, CreateRoleDto } from './dto';
+import {
+  CreateUserDto,
+  UpdateUserDto,
+  CreateRoleDto,
+  AssignUserRoleDto,
+  UnassignUserRoleDto,
+} from './dto';
 
 
 export class UserController {
 export class UserController {
   private router: Router;
   private router: Router;
@@ -41,12 +46,25 @@ export class UserController {
 
 
     this.router.delete('/roles/:roleName', this.deleteRole.bind(this));
     this.router.delete('/roles/:roleName', this.deleteRole.bind(this));
 
 
+    this.router.put(
+      '/:username/role/assign',
+      dtoValidationMiddleware(AssignUserRoleDto),
+      this.assignUserRole.bind(this)
+    );
+
+    this.router.put(
+      '/:username/role/unassign',
+      dtoValidationMiddleware(UnassignUserRoleDto),
+      this.unassignUserRole.bind(this)
+    );
+
     return this.router;
     return this.router;
   }
   }
 
 
   async getUsers(req: Request, res: Response, next: NextFunction) {
   async getUsers(req: Request, res: Response, next: NextFunction) {
     try {
     try {
       const result = await this.userService.getUsers();
       const result = await this.userService.getUsers();
+
       res.send(result);
       res.send(result);
     } catch (error) {
     } catch (error) {
       next(error);
       next(error);
@@ -115,4 +133,34 @@ export class UserController {
       next(error);
       next(error);
     }
     }
   }
   }
+
+  async assignUserRole(req: Request, res: Response, next: NextFunction) {
+    const { roleName } = req.body;
+    const { username } = req.params;
+
+    try {
+      const result = await this.userService.assignUserRole({
+        username,
+        roleName,
+      });
+      res.send(result);
+    } catch (error) {
+      next(error);
+    }
+  }
+
+  async unassignUserRole(req: Request, res: Response, next: NextFunction) {
+    const { roleName } = req.body;
+    const { username } = req.params;
+
+    try {
+      const result = await this.userService.assignUserRole({
+        username,
+        roleName,
+      });
+      res.send(result);
+    } catch (error) {
+      next(error);
+    }
+  }
 }
 }

+ 21 - 0
server/src/users/users.service.ts

@@ -5,6 +5,9 @@ import {
   DeleteUserReq,
   DeleteUserReq,
   CreateRoleReq,
   CreateRoleReq,
   DropRoleReq,
   DropRoleReq,
+  AddUserToRoleReq,
+  RemoveUserFromRoleReq,
+  HasRoleReq
 } from '@zilliz/milvus2-sdk-node';
 } from '@zilliz/milvus2-sdk-node';
 import { throwErrorFromSDK } from '../utils/Error';
 import { throwErrorFromSDK } from '../utils/Error';
 
 
@@ -59,4 +62,22 @@ export class UserService {
     throwErrorFromSDK(res);
     throwErrorFromSDK(res);
     return res;
     return res;
   }
   }
+
+  async assignUserRole(data: AddUserToRoleReq) {
+    const res = await this.milvusService.client.addUserToRole(data);
+    throwErrorFromSDK(res);
+    return res;
+  }
+
+  async unassignUserRole(data: RemoveUserFromRoleReq) {
+    const res = await this.milvusService.client.addUserToRole(data);
+    throwErrorFromSDK(res);
+    return res;
+  }
+
+  async hasRole(data: HasRoleReq) {
+    const res = await this.milvusService.client.hasRole(data);
+    throwErrorFromSDK(res.status);
+    return res;
+  }
 }
 }