diff --git a/backend/src/collections/userdb/userdb.service.ts b/backend/src/collections/userdb/userdb.service.ts index 9dd2769..66c91a0 100644 --- a/backend/src/collections/userdb/userdb.service.ts +++ b/backend/src/collections/userdb/userdb.service.ts @@ -26,6 +26,8 @@ export class UsersService { private rolesService: RolesService, ) {} + // Creation and deletion + public async create( username: string, password: string, @@ -63,6 +65,8 @@ export class UsersService { } } + // Authentication + async authenticate( username: string, password: string, @@ -76,6 +80,8 @@ export class UsersService { return await this.findOne(username); } + // Permissions and roles + public async getPermissions( user: string | EUserBackend, ): AsyncFailable { @@ -130,6 +136,8 @@ export class UsersService { } } + // Listing + public async findOne( username: string, getPrivate?: B, @@ -151,9 +159,18 @@ export class UsersService { } } - public async findAll(): AsyncFailable { + public async findMany( + count: number, + page: number, + ): AsyncFailable { + if (count < 1 || page < 0) return Fail('Invalid page'); + if (count > 100) return Fail('Too many results'); + try { - return await this.usersRepository.find(); + return await this.usersRepository.find({ + take: count, + skip: count * page, + }); } catch (e: any) { return Fail(e?.message); } @@ -163,6 +180,8 @@ export class UsersService { return HasSuccess(await this.findOne(username)); } + // Internal resolver + private async resolve( user: string | EUserBackend, ): AsyncFailable { diff --git a/backend/src/routes/api/user/usermanage.controller.ts b/backend/src/routes/api/user/usermanage.controller.ts index a184c1d..56a9e9f 100644 --- a/backend/src/routes/api/user/usermanage.controller.ts +++ b/backend/src/routes/api/user/usermanage.controller.ts @@ -7,10 +7,13 @@ import { Post } from '@nestjs/common'; import { + UserCreateRequest, + UserCreateResponse, UserDeleteRequest, UserDeleteResponse, UserInfoRequest, UserInfoResponse, + UserListRequest, UserListResponse, UserUpdateRolesRequest, UserUpdateRolesResponse @@ -29,7 +32,18 @@ export class UserManageController { @Get('list') async listUsers(): Promise { - const users = await this.usersService.findAll(); + const body = new UserListRequest(); + body.count = 20; + body.page = 0; + + return this.listUsersPaged(body); + } + + @Post('list') + async listUsersPaged( + @Body() body: UserListRequest, + ): Promise { + const users = await this.usersService.findMany(body.count, body.page); if (HasFailed(users)) { this.logger.warn(users.getReason()); throw new InternalServerErrorException('Could not list users'); @@ -37,10 +51,27 @@ export class UserManageController { return { users, - total: users.length, + count: users.length, + page: body.page, }; } + @Post('create') + async register( + @Body() create: UserCreateRequest, + ): Promise { + const user = await this.usersService.create( + create.username, + create.password, + ); + if (HasFailed(user)) { + this.logger.warn(user.getReason()); + throw new InternalServerErrorException('Could not create user'); + } + + return user; + } + @Post('delete') async delete( @Body() deleteData: UserDeleteRequest, @@ -54,6 +85,18 @@ export class UserManageController { return user; } + @Post('info') + async getUser(@Body() body: UserInfoRequest): Promise { + console.log(body); + const user = await this.usersService.findOne(body.username); + if (HasFailed(user)) { + this.logger.warn(user.getReason()); + throw new InternalServerErrorException('Could not find user'); + } + + return user; + } + @Post('roles') async setPermissions( @Body() body: UserUpdateRolesRequest, @@ -70,16 +113,4 @@ export class UserManageController { return updatedUser; } - - @Post('info') - async getUser(@Body() body: UserInfoRequest): Promise { - console.log(body); - const user = await this.usersService.findOne(body.username); - if (HasFailed(user)) { - this.logger.warn(user.getReason()); - throw new InternalServerErrorException('Could not find user'); - } - - return user; - } } diff --git a/frontend/src/app/routes/settings/settings.routing.module.ts b/frontend/src/app/routes/settings/settings.routing.module.ts index 21bc358..037db97 100644 --- a/frontend/src/app/routes/settings/settings.routing.module.ts +++ b/frontend/src/app/routes/settings/settings.routing.module.ts @@ -29,18 +29,6 @@ const SettingsRoutes: PRoutes = [ }, }, }, - { - path: 'system', - loadChildren: () => SettingsSysprefRouteModule, - data: { - permissions: [Permission.SysPrefManage], - page: { - title: 'System Settings', - icon: 'settings', - category: 'system', - }, - }, - }, { path: 'users', loadChildren: () => SettingsUsersRouteModule, @@ -53,6 +41,18 @@ const SettingsRoutes: PRoutes = [ }, }, }, + { + path: 'system', + loadChildren: () => SettingsSysprefRouteModule, + data: { + permissions: [Permission.SysPrefManage], + page: { + title: 'System Settings', + icon: 'tune', + category: 'system', + }, + }, + }, ], canActivate: [PermissionGuard], canActivateChild: [PermissionGuard], diff --git a/shared/src/dto/api/usermanage.dto.ts b/shared/src/dto/api/usermanage.dto.ts index 60fdcce..c779c73 100644 --- a/shared/src/dto/api/usermanage.dto.ts +++ b/shared/src/dto/api/usermanage.dto.ts @@ -1,8 +1,53 @@ import { Type } from 'class-transformer'; -import { IsArray, IsDefined, IsInt, IsNotEmpty, IsPositive, IsString, ValidateNested } from 'class-validator'; +import { IsArray, IsDefined, IsInt, IsNotEmpty, IsString, Min, ValidateNested } from 'class-validator'; import { EUser } from '../../entities/user.entity'; import { Roles } from '../roles.dto'; +// UserList +export class UserListRequest { + @IsDefined() + @IsInt() + @Min(0) + count: number; + + @IsDefined() + @IsInt() + @Min(0) + page: number; +} + +export class UserListResponse { + @IsArray() + @IsDefined() + @ValidateNested() + @Type(() => EUser) + users: EUser[]; + + @IsDefined() + @IsInt() + @Min(0) + count: number; + + @IsDefined() + @IsInt() + @Min(0) + page: number; +} + +// UserCreate +export class UserCreateRequest { + @IsString() + @IsNotEmpty() + username: string; + + @IsString() + @IsNotEmpty() + password: string; +} + +export class UserCreateResponse extends EUser {} + + // UserDelete export class UserDeleteRequest { @IsString() @@ -21,20 +66,6 @@ export class UserInfoRequest { export class UserInfoResponse extends EUser {} -// UserList -export class UserListResponse { - @IsArray() - @IsDefined() - @ValidateNested() - @Type(() => EUser) - users: EUser[]; - - @IsInt() - @IsPositive() - @IsDefined() - total: number; -} - // UserUpdateRoles export class UserUpdateRolesRequest { @IsString()