From 4bb327469069f36eb92bb162fb96d8c3a5fee3d5 Mon Sep 17 00:00:00 2001 From: Kostiantyn Smyrnov Date: Mon, 19 Feb 2024 16:49:29 +0100 Subject: [PATCH] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20Users=20db=20list=20?= =?UTF-8?q?route=20now=20returns=20sanitized=20records?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/db/src/users.ts | 35 +++++++++++++++++++++--- packages/node-api/src/router/user.ts | 40 +++++++++++++++++----------- 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/packages/db/src/users.ts b/packages/db/src/users.ts index 0611dd0..6e0ca61 100644 --- a/packages/db/src/users.ts +++ b/packages/db/src/users.ts @@ -23,8 +23,8 @@ export interface User { * It validates that the input contains a nonempty `login` and `password`. */ export const UserInputSchema = z.object({ - login: z.string().nonempty(), - password: z.union([z.string().nonempty(), z.string().startsWith('0x')]), + login: z.string().min(1), + password: z.union([z.string().min(1), z.string().startsWith('0x')]), }); /** @@ -33,6 +33,31 @@ export const UserInputSchema = z.object({ */ export type UserInputType = z.infer; +/** + * User output schema + */ +export const SafeUserSchema = z.object({ + login: z.string().min(1), + isAdmin: z.boolean().optional(), +}); + +/** + * Users list output schema + */ +export const UsersListOutputSchema = z.array(SafeUserSchema); + +/** + * Type definition for sanitized User record, + * inferred from SafeUserSchema. + */ +export type SafeUserType = z.infer; + +/** + * Type definition for sanitized Users records list, + * inferred from UsersListOutputSchema. + */ +export type UsersListOutputSchema = z.infer; + /** * Interface defining the properties of UsersDb initialization options. */ @@ -130,7 +155,11 @@ export class UsersDb { * @throws Will throw an error if a user with the same login already exists * @memberof UsersDb */ - async add(login: string, password: string, isAdmin = false): Promise { + async add( + login: string, + password: string, + isAdmin: boolean = false, + ): Promise { const knownUser = await this.storage.get(`${this.prefix}${login}`); // Check if the user already exists diff --git a/packages/node-api/src/router/user.ts b/packages/node-api/src/router/user.ts index 3e340a5..58cee36 100644 --- a/packages/node-api/src/router/user.ts +++ b/packages/node-api/src/router/user.ts @@ -1,5 +1,10 @@ import { TRPCError } from '@trpc/server'; -import { User, UserInputSchema, comparePassword } from '@windingtree/sdk-db'; +import { + User, + UserInputSchema, + UsersListOutputSchema, + comparePassword, +} from '@windingtree/sdk-db'; import { router, procedure, @@ -40,20 +45,25 @@ export const userRouter = router({ * List users records. * Throws an error if the user already exists. */ - list: authAdminProcedure.query(async ({ ctx }) => { - try { - const { users } = ctx; - const records = await users.getAll(); - logger.trace(`Listed #${records.length} users`); - return records; - } catch (error) { - logger.error('user.list', error); - throw new TRPCError({ - code: 'BAD_REQUEST', - message: (error as Error).message, - }); - } - }), + list: authAdminProcedure + .output(UsersListOutputSchema) + .query(async ({ ctx }) => { + try { + const { users } = ctx; + const records = await users.getAll(); + logger.trace(`Listed #${records.length} users`); + return records.map(({ login, isAdmin }) => ({ + login, + isAdmin, + })); + } catch (error) { + logger.error('user.list', error); + throw new TRPCError({ + code: 'BAD_REQUEST', + message: (error as Error).message, + }); + } + }), /** * Log in an existing user.