From e02ab7d256863cf9bbc8e659be71d7641e4815ed Mon Sep 17 00:00:00 2001 From: pit Date: Wed, 11 Oct 2023 12:32:33 +0300 Subject: [PATCH] chore: implement pr feedback --- .../app/(dashboard)/admin/users/[id]/page.tsx | 129 ++++++++++-------- packages/lib/server-only/admin/update-user.ts | 3 +- .../lib/server-only/user/get-all-users.ts | 4 +- packages/trpc/server/admin-router/router.ts | 16 +-- packages/trpc/server/profile-router/router.ts | 36 ++--- packages/trpc/server/trpc.ts | 30 ++++ packages/ui/primitives/combobox.tsx | 66 +++++---- 7 files changed, 154 insertions(+), 130 deletions(-) diff --git a/apps/web/src/app/(dashboard)/admin/users/[id]/page.tsx b/apps/web/src/app/(dashboard)/admin/users/[id]/page.tsx index 802f2ec0c..8c68f1270 100644 --- a/apps/web/src/app/(dashboard)/admin/users/[id]/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/users/[id]/page.tsx @@ -3,21 +3,23 @@ import { useRouter } from 'next/navigation'; import { zodResolver } from '@hookform/resolvers/zod'; -import { Loader } from 'lucide-react'; -import { Controller, useForm } from 'react-hook-form'; +import { useForm } from 'react-hook-form'; import { trpc } from '@documenso/trpc/react'; import { Button } from '@documenso/ui/primitives/button'; import { Combobox } from '@documenso/ui/primitives/combobox'; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@documenso/ui/primitives/form/form'; import { Input } from '@documenso/ui/primitives/input'; -import { Label } from '@documenso/ui/primitives/label'; import { useToast } from '@documenso/ui/primitives/use-toast'; -import { FormErrorMessage } from '../../../../../components/form/form-error-message'; -import { - TUserFormSchema, - ZUserFormSchema, -} from '../../../../../providers/admin-user-profile-update.types'; +import { TUserFormSchema, ZUserFormSchema } from '~/providers/admin-user-profile-update.types'; export default function UserPage({ params }: { params: { id: number } }) { const { toast } = useToast(); @@ -34,21 +36,11 @@ export default function UserPage({ params }: { params: { id: number } }) { const user = result.data; - const roles = user?.roles; - let rolesArr: string[] = []; - - if (roles) { - rolesArr = Object.values(roles); - } + const roles = user?.roles ?? []; const { mutateAsync: updateUserMutation } = trpc.admin.updateUser.useMutation(); - const { - register, - control, - handleSubmit, - formState: { errors, isSubmitting }, - } = useForm({ + const form = useForm({ resolver: zodResolver(ZUserFormSchema), values: { name: user?.name ?? '', @@ -85,42 +77,69 @@ export default function UserPage({ params }: { params: { id: number } }) { return (

Manage {user?.name}'s profile

-
-
- - - -
-
- - - -
-
- - ( - onChange(values)} /> - )} - /> - -
+ + +
+ ( + + + Name + + + + + + + )} + /> + ( + + + Email + + + + + + + )} + /> -
- -
- + ( + +
+ + Roles + + + onChange(values)} + /> + + +
+
+ )} + /> + +
+ +
+
+ +
); } diff --git a/packages/lib/server-only/admin/update-user.ts b/packages/lib/server-only/admin/update-user.ts index e4cc7b2bc..9013899a7 100644 --- a/packages/lib/server-only/admin/update-user.ts +++ b/packages/lib/server-only/admin/update-user.ts @@ -15,7 +15,7 @@ export const updateUser = async ({ id, name, email, roles }: UpdateUserOptions) }, }); - const updatedUser = await prisma.user.update({ + return await prisma.user.update({ where: { id, }, @@ -25,5 +25,4 @@ export const updateUser = async ({ id, name, email, roles }: UpdateUserOptions) roles, }, }); - return updatedUser; }; diff --git a/packages/lib/server-only/user/get-all-users.ts b/packages/lib/server-only/user/get-all-users.ts index babcc7ba1..a1ff2c929 100644 --- a/packages/lib/server-only/user/get-all-users.ts +++ b/packages/lib/server-only/user/get-all-users.ts @@ -2,7 +2,7 @@ import { Prisma } from '@prisma/client'; import { prisma } from '@documenso/prisma'; -type getAllUsersProps = { +type GetAllUsersProps = { username: string; email: string; page: number; @@ -14,7 +14,7 @@ export const findUsers = async ({ email = '', page = 1, perPage = 10, -}: getAllUsersProps) => { +}: GetAllUsersProps) => { const whereClause = Prisma.validator()({ OR: [ { diff --git a/packages/trpc/server/admin-router/router.ts b/packages/trpc/server/admin-router/router.ts index 67556a251..666e3f085 100644 --- a/packages/trpc/server/admin-router/router.ts +++ b/packages/trpc/server/admin-router/router.ts @@ -1,24 +1,14 @@ import { TRPCError } from '@trpc/server'; -import { isAdmin } from '@documenso/lib/next-auth/guards/is-admin'; import { updateUser } from '@documenso/lib/server-only/admin/update-user'; -import { authenticatedProcedure, router } from '../trpc'; +import { adminProcedure, router } from '../trpc'; import { ZUpdateProfileMutationByAdminSchema } from './schema'; export const adminRouter = router({ - updateUser: authenticatedProcedure + updateUser: adminProcedure .input(ZUpdateProfileMutationByAdminSchema) - .mutation(async ({ input, ctx }) => { - const isUserAdmin = isAdmin(ctx.user); - - if (!isUserAdmin) { - throw new TRPCError({ - code: 'UNAUTHORIZED', - message: 'Not authorized to perform this action.', - }); - } - + .mutation(async ({ input }) => { const { id, name, email, roles } = input; try { diff --git a/packages/trpc/server/profile-router/router.ts b/packages/trpc/server/profile-router/router.ts index 8d83528c0..0f6636650 100644 --- a/packages/trpc/server/profile-router/router.ts +++ b/packages/trpc/server/profile-router/router.ts @@ -1,13 +1,12 @@ import { TRPCError } from '@trpc/server'; -import { isAdmin } from '@documenso/lib/next-auth/guards/is-admin'; import { forgotPassword } from '@documenso/lib/server-only/user/forgot-password'; import { getUserById } from '@documenso/lib/server-only/user/get-user-by-id'; import { resetPassword } from '@documenso/lib/server-only/user/reset-password'; import { updatePassword } from '@documenso/lib/server-only/user/update-password'; import { updateProfile } from '@documenso/lib/server-only/user/update-profile'; -import { authenticatedProcedure, procedure, router } from '../trpc'; +import { adminProcedure, authenticatedProcedure, procedure, router } from '../trpc'; import { ZForgotPasswordFormSchema, ZResetPasswordFormSchema, @@ -17,29 +16,18 @@ import { } from './schema'; export const profileRouter = router({ - getUser: authenticatedProcedure - .input(ZRetrieveUserByIdQuerySchema) - .query(async ({ input, ctx }) => { - const isUserAdmin = isAdmin(ctx.user); + getUser: adminProcedure.input(ZRetrieveUserByIdQuerySchema).query(async ({ input }) => { + try { + const { id } = input; - if (!isUserAdmin) { - throw new TRPCError({ - code: 'UNAUTHORIZED', - message: 'Not authorized to perform this action.', - }); - } - - try { - const { id } = input; - - return await getUserById({ id }); - } catch (err) { - throw new TRPCError({ - code: 'BAD_REQUEST', - message: 'We were unable to retrieve the specified account. Please try again.', - }); - } - }), + return await getUserById({ id }); + } catch (err) { + throw new TRPCError({ + code: 'BAD_REQUEST', + message: 'We were unable to retrieve the specified account. Please try again.', + }); + } + }), updateProfile: authenticatedProcedure .input(ZUpdateProfileMutationSchema) diff --git a/packages/trpc/server/trpc.ts b/packages/trpc/server/trpc.ts index 91d2a239f..a382e3511 100644 --- a/packages/trpc/server/trpc.ts +++ b/packages/trpc/server/trpc.ts @@ -1,6 +1,8 @@ import { TRPCError, initTRPC } from '@trpc/server'; import SuperJSON from 'superjson'; +import { isAdmin } from '@documenso/lib/next-auth/guards/is-admin'; + import { TrpcContext } from './context'; const t = initTRPC.context().create({ @@ -28,9 +30,37 @@ export const authenticatedMiddleware = t.middleware(async ({ ctx, next }) => { }); }); +export const adminMiddleware = t.middleware(async ({ ctx, next }) => { + if (!ctx.session || !ctx.user) { + throw new TRPCError({ + code: 'UNAUTHORIZED', + message: 'You must be logged in to perform this action.', + }); + } + + const isUserAdmin = isAdmin(ctx.user); + + if (!isUserAdmin) { + throw new TRPCError({ + code: 'UNAUTHORIZED', + message: 'Not authorized to perform this action.', + }); + } + + return await next({ + ctx: { + ...ctx, + + user: ctx.user, + session: ctx.session, + }, + }); +}); + /** * Routers and Procedures */ export const router = t.router; export const procedure = t.procedure; export const authenticatedProcedure = t.procedure.use(authenticatedMiddleware); +export const adminProcedure = t.procedure.use(adminMiddleware); diff --git a/packages/ui/primitives/combobox.tsx b/packages/ui/primitives/combobox.tsx index 90fdc7849..899ccd61d 100644 --- a/packages/ui/primitives/combobox.tsx +++ b/packages/ui/primitives/combobox.tsx @@ -44,40 +44,38 @@ const Combobox = ({ listValues, onChange }: ComboboxProps) => { }; return ( - <> - - - - - - - - No value found. - - {allRoles.map((value: string, i: number) => ( - handleSelect(value)}> - - {value} - - ))} - - - - - + + + + + + + + No value found. + + {allRoles.map((value: string, i: number) => ( + handleSelect(value)}> + + {value} + + ))} + + + + ); };