mirror of
https://github.com/documenso/documenso.git
synced 2025-11-10 04:22:32 +10:00
chore: refactor routes (#1992)
This commit is contained in:
@ -3,12 +3,12 @@ import { useState } from 'react';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { User } from '@prisma/client';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import type { TGetUserResponse } from '@documenso/trpc/server/admin-router/get-user.types';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
@ -25,7 +25,7 @@ import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
export type AdminUserDeleteDialogProps = {
|
||||
className?: string;
|
||||
user: User;
|
||||
user: TGetUserResponse;
|
||||
};
|
||||
|
||||
export const AdminUserDeleteDialog = ({ className, user }: AdminUserDeleteDialogProps) => {
|
||||
|
||||
@ -3,11 +3,11 @@ import { useState } from 'react';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { User } from '@prisma/client';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import type { TGetUserResponse } from '@documenso/trpc/server/admin-router/get-user.types';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
@ -24,7 +24,7 @@ import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
export type AdminUserDisableDialogProps = {
|
||||
className?: string;
|
||||
userToDisable: User;
|
||||
userToDisable: TGetUserResponse;
|
||||
};
|
||||
|
||||
export const AdminUserDisableDialog = ({
|
||||
|
||||
@ -3,11 +3,11 @@ import { useState } from 'react';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { User } from '@prisma/client';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import type { TGetUserResponse } from '@documenso/trpc/server/admin-router/get-user.types';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
@ -24,7 +24,7 @@ import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
export type AdminUserEnableDialogProps = {
|
||||
className?: string;
|
||||
userToEnable: User;
|
||||
userToEnable: TGetUserResponse;
|
||||
};
|
||||
|
||||
export const AdminUserEnableDialog = ({ className, userToEnable }: AdminUserEnableDialogProps) => {
|
||||
|
||||
@ -3,12 +3,12 @@ import { useState } from 'react';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { User } from '@prisma/client';
|
||||
import { useRevalidator } from 'react-router';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import type { TGetUserResponse } from '@documenso/trpc/server/admin-router/get-user.types';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
@ -25,7 +25,7 @@ import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
export type AdminUserResetTwoFactorDialogProps = {
|
||||
className?: string;
|
||||
user: User;
|
||||
user: TGetUserResponse;
|
||||
};
|
||||
|
||||
export const AdminUserResetTwoFactorDialog = ({
|
||||
|
||||
@ -2,13 +2,13 @@ import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { User } from '@prisma/client';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useRevalidator } from 'react-router';
|
||||
import { Link } from 'react-router';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import type { TGetUserResponse } from '@documenso/trpc/server/admin-router/get-user.types';
|
||||
import { ZUpdateUserRequestSchema } from '@documenso/trpc/server/admin-router/update-user.types';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
@ -38,7 +38,7 @@ const ZUserFormSchema = ZUpdateUserRequestSchema.omit({ id: true });
|
||||
type TUserFormSchema = z.infer<typeof ZUserFormSchema>;
|
||||
|
||||
export default function UserPage({ params }: { params: { id: number } }) {
|
||||
const { data: user, isLoading: isLoadingUser } = trpc.profile.getUser.useQuery(
|
||||
const { data: user, isLoading: isLoadingUser } = trpc.admin.user.get.useQuery(
|
||||
{
|
||||
id: Number(params.id),
|
||||
},
|
||||
@ -78,7 +78,7 @@ export default function UserPage({ params }: { params: { id: number } }) {
|
||||
return <AdminUserPage user={user} />;
|
||||
}
|
||||
|
||||
const AdminUserPage = ({ user }: { user: User }) => {
|
||||
const AdminUserPage = ({ user }: { user: TGetUserResponse }) => {
|
||||
const { _ } = useLingui();
|
||||
const { toast } = useToast();
|
||||
const { revalidate } = useRevalidator();
|
||||
|
||||
@ -45,6 +45,9 @@ export async function loader({ params, request }: Route.LoaderArgs) {
|
||||
mode: 'insensitive',
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Directly convert the team member invite to a team member if they already have an account.
|
||||
|
||||
@ -111,6 +111,10 @@ export const handleOAuthCallbackUrl = async (options: HandleOAuthCallbackUrlOpti
|
||||
where: {
|
||||
email: email,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
emailVerified: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Handle existing user but no account.
|
||||
|
||||
@ -42,6 +42,11 @@ export const run = async ({
|
||||
where: {
|
||||
id: userId,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
name: true,
|
||||
},
|
||||
}),
|
||||
prisma.document.findFirstOrThrow({
|
||||
where: {
|
||||
|
||||
@ -10,12 +10,6 @@ export type UpdateUserOptions = {
|
||||
};
|
||||
|
||||
export const updateUser = async ({ id, name, email, roles }: UpdateUserOptions) => {
|
||||
await prisma.user.findFirstOrThrow({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.user.update({
|
||||
where: {
|
||||
id,
|
||||
|
||||
@ -1,13 +1,31 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
|
||||
export interface GetUserByIdOptions {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export const getUserById = async ({ id }: GetUserByIdOptions) => {
|
||||
return await prisma.user.findFirstOrThrow({
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
emailVerified: true,
|
||||
roles: true,
|
||||
disabled: true,
|
||||
twoFactorEnabled: true,
|
||||
signature: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new AppError(AppErrorCode.NOT_FOUND);
|
||||
}
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
@ -24,7 +24,7 @@ export const updateProfile = async ({
|
||||
},
|
||||
});
|
||||
|
||||
return await prisma.$transaction(async (tx) => {
|
||||
await prisma.$transaction(async (tx) => {
|
||||
await tx.userSecurityAuditLog.create({
|
||||
data: {
|
||||
userId,
|
||||
@ -34,7 +34,7 @@ export const updateProfile = async ({
|
||||
},
|
||||
});
|
||||
|
||||
return await tx.user.update({
|
||||
await tx.user.update({
|
||||
where: {
|
||||
id: userId,
|
||||
},
|
||||
|
||||
19
packages/trpc/server/admin-router/get-user.ts
Normal file
19
packages/trpc/server/admin-router/get-user.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { getUserById } from '@documenso/lib/server-only/user/get-user-by-id';
|
||||
|
||||
import { adminProcedure } from '../trpc';
|
||||
import { ZGetUserRequestSchema, ZGetUserResponseSchema } from './get-user.types';
|
||||
|
||||
export const getUserRoute = adminProcedure
|
||||
.input(ZGetUserRequestSchema)
|
||||
.output(ZGetUserResponseSchema)
|
||||
.query(async ({ input, ctx }) => {
|
||||
const { id } = input;
|
||||
|
||||
ctx.logger.info({
|
||||
input: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
|
||||
return await getUserById({ id });
|
||||
});
|
||||
21
packages/trpc/server/admin-router/get-user.types.ts
Normal file
21
packages/trpc/server/admin-router/get-user.types.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import UserSchema from '@documenso/prisma/generated/zod/modelSchema/UserSchema';
|
||||
|
||||
export const ZGetUserRequestSchema = z.object({
|
||||
id: z.number().min(1),
|
||||
});
|
||||
|
||||
export const ZGetUserResponseSchema = UserSchema.pick({
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
emailVerified: true,
|
||||
roles: true,
|
||||
disabled: true,
|
||||
twoFactorEnabled: true,
|
||||
signature: true,
|
||||
});
|
||||
|
||||
export type TGetUserRequest = z.infer<typeof ZGetUserRequestSchema>;
|
||||
export type TGetUserResponse = z.infer<typeof ZGetUserResponseSchema>;
|
||||
@ -11,6 +11,7 @@ import { findAdminOrganisationsRoute } from './find-admin-organisations';
|
||||
import { findDocumentsRoute } from './find-documents';
|
||||
import { findSubscriptionClaimsRoute } from './find-subscription-claims';
|
||||
import { getAdminOrganisationRoute } from './get-admin-organisation';
|
||||
import { getUserRoute } from './get-user';
|
||||
import { resealDocumentRoute } from './reseal-document';
|
||||
import { resetTwoFactorRoute } from './reset-two-factor-authentication';
|
||||
import { updateAdminOrganisationRoute } from './update-admin-organisation';
|
||||
@ -36,6 +37,7 @@ export const adminRouter = router({
|
||||
createCustomer: createStripeCustomerRoute,
|
||||
},
|
||||
user: {
|
||||
get: getUserRoute,
|
||||
update: updateUserRoute,
|
||||
delete: deleteUserRoute,
|
||||
enable: enableUserRoute,
|
||||
|
||||
@ -3,14 +3,12 @@ import type { SetAvatarImageOptions } from '@documenso/lib/server-only/profile/s
|
||||
import { setAvatarImage } from '@documenso/lib/server-only/profile/set-avatar-image';
|
||||
import { deleteUser } from '@documenso/lib/server-only/user/delete-user';
|
||||
import { findUserSecurityAuditLogs } from '@documenso/lib/server-only/user/find-user-security-audit-logs';
|
||||
import { getUserById } from '@documenso/lib/server-only/user/get-user-by-id';
|
||||
import { submitSupportTicket } from '@documenso/lib/server-only/user/submit-support-ticket';
|
||||
import { updateProfile } from '@documenso/lib/server-only/user/update-profile';
|
||||
|
||||
import { adminProcedure, authenticatedProcedure, router } from '../trpc';
|
||||
import { authenticatedProcedure, router } from '../trpc';
|
||||
import {
|
||||
ZFindUserSecurityAuditLogsSchema,
|
||||
ZRetrieveUserByIdQuerySchema,
|
||||
ZSetProfileImageMutationSchema,
|
||||
ZSubmitSupportTicketMutationSchema,
|
||||
ZUpdateProfileMutationSchema,
|
||||
@ -26,24 +24,12 @@ export const profileRouter = router({
|
||||
});
|
||||
}),
|
||||
|
||||
getUser: adminProcedure.input(ZRetrieveUserByIdQuerySchema).query(async ({ input, ctx }) => {
|
||||
const { id } = input;
|
||||
|
||||
ctx.logger.info({
|
||||
input: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
|
||||
return await getUserById({ id });
|
||||
}),
|
||||
|
||||
updateProfile: authenticatedProcedure
|
||||
.input(ZUpdateProfileMutationSchema)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const { name, signature } = input;
|
||||
|
||||
return await updateProfile({
|
||||
await updateProfile({
|
||||
userId: ctx.user.id,
|
||||
name,
|
||||
signature,
|
||||
@ -52,7 +38,7 @@ export const profileRouter = router({
|
||||
}),
|
||||
|
||||
deleteAccount: authenticatedProcedure.mutation(async ({ ctx }) => {
|
||||
return await deleteUser({
|
||||
await deleteUser({
|
||||
id: ctx.user.id,
|
||||
});
|
||||
}),
|
||||
|
||||
@ -7,12 +7,6 @@ export const ZFindUserSecurityAuditLogsSchema = z.object({
|
||||
|
||||
export type TFindUserSecurityAuditLogsSchema = z.infer<typeof ZFindUserSecurityAuditLogsSchema>;
|
||||
|
||||
export const ZRetrieveUserByIdQuerySchema = z.object({
|
||||
id: z.number().min(1),
|
||||
});
|
||||
|
||||
export type TRetrieveUserByIdQuerySchema = z.infer<typeof ZRetrieveUserByIdQuerySchema>;
|
||||
|
||||
export const ZUpdateProfileMutationSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
signature: z.string(),
|
||||
|
||||
Reference in New Issue
Block a user