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 { msg } from '@lingui/core/macro';
|
||||||
import { useLingui } from '@lingui/react';
|
import { useLingui } from '@lingui/react';
|
||||||
import { Trans } from '@lingui/react/macro';
|
import { Trans } from '@lingui/react/macro';
|
||||||
import type { User } from '@prisma/client';
|
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||||
import { trpc } from '@documenso/trpc/react';
|
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 { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert';
|
||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
import {
|
import {
|
||||||
@ -25,7 +25,7 @@ import { useToast } from '@documenso/ui/primitives/use-toast';
|
|||||||
|
|
||||||
export type AdminUserDeleteDialogProps = {
|
export type AdminUserDeleteDialogProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
user: User;
|
user: TGetUserResponse;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AdminUserDeleteDialog = ({ className, user }: AdminUserDeleteDialogProps) => {
|
export const AdminUserDeleteDialog = ({ className, user }: AdminUserDeleteDialogProps) => {
|
||||||
|
|||||||
@ -3,11 +3,11 @@ import { useState } from 'react';
|
|||||||
import { msg } from '@lingui/core/macro';
|
import { msg } from '@lingui/core/macro';
|
||||||
import { useLingui } from '@lingui/react';
|
import { useLingui } from '@lingui/react';
|
||||||
import { Trans } from '@lingui/react/macro';
|
import { Trans } from '@lingui/react/macro';
|
||||||
import type { User } from '@prisma/client';
|
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||||
import { trpc } from '@documenso/trpc/react';
|
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 { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert';
|
||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
import {
|
import {
|
||||||
@ -24,7 +24,7 @@ import { useToast } from '@documenso/ui/primitives/use-toast';
|
|||||||
|
|
||||||
export type AdminUserDisableDialogProps = {
|
export type AdminUserDisableDialogProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
userToDisable: User;
|
userToDisable: TGetUserResponse;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AdminUserDisableDialog = ({
|
export const AdminUserDisableDialog = ({
|
||||||
|
|||||||
@ -3,11 +3,11 @@ import { useState } from 'react';
|
|||||||
import { msg } from '@lingui/core/macro';
|
import { msg } from '@lingui/core/macro';
|
||||||
import { useLingui } from '@lingui/react';
|
import { useLingui } from '@lingui/react';
|
||||||
import { Trans } from '@lingui/react/macro';
|
import { Trans } from '@lingui/react/macro';
|
||||||
import type { User } from '@prisma/client';
|
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||||
import { trpc } from '@documenso/trpc/react';
|
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 { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert';
|
||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
import {
|
import {
|
||||||
@ -24,7 +24,7 @@ import { useToast } from '@documenso/ui/primitives/use-toast';
|
|||||||
|
|
||||||
export type AdminUserEnableDialogProps = {
|
export type AdminUserEnableDialogProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
userToEnable: User;
|
userToEnable: TGetUserResponse;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AdminUserEnableDialog = ({ className, userToEnable }: AdminUserEnableDialogProps) => {
|
export const AdminUserEnableDialog = ({ className, userToEnable }: AdminUserEnableDialogProps) => {
|
||||||
|
|||||||
@ -3,12 +3,12 @@ import { useState } from 'react';
|
|||||||
import { msg } from '@lingui/core/macro';
|
import { msg } from '@lingui/core/macro';
|
||||||
import { useLingui } from '@lingui/react';
|
import { useLingui } from '@lingui/react';
|
||||||
import { Trans } from '@lingui/react/macro';
|
import { Trans } from '@lingui/react/macro';
|
||||||
import type { User } from '@prisma/client';
|
|
||||||
import { useRevalidator } from 'react-router';
|
import { useRevalidator } from 'react-router';
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||||
import { trpc } from '@documenso/trpc/react';
|
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 { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert';
|
||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
import {
|
import {
|
||||||
@ -25,7 +25,7 @@ import { useToast } from '@documenso/ui/primitives/use-toast';
|
|||||||
|
|
||||||
export type AdminUserResetTwoFactorDialogProps = {
|
export type AdminUserResetTwoFactorDialogProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
user: User;
|
user: TGetUserResponse;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AdminUserResetTwoFactorDialog = ({
|
export const AdminUserResetTwoFactorDialog = ({
|
||||||
|
|||||||
@ -2,13 +2,13 @@ import { zodResolver } from '@hookform/resolvers/zod';
|
|||||||
import { msg } from '@lingui/core/macro';
|
import { msg } from '@lingui/core/macro';
|
||||||
import { useLingui } from '@lingui/react';
|
import { useLingui } from '@lingui/react';
|
||||||
import { Trans } from '@lingui/react/macro';
|
import { Trans } from '@lingui/react/macro';
|
||||||
import type { User } from '@prisma/client';
|
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { useRevalidator } from 'react-router';
|
import { useRevalidator } from 'react-router';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
import type { z } from 'zod';
|
import type { z } from 'zod';
|
||||||
|
|
||||||
import { trpc } from '@documenso/trpc/react';
|
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 { ZUpdateUserRequestSchema } from '@documenso/trpc/server/admin-router/update-user.types';
|
||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
import {
|
import {
|
||||||
@ -38,7 +38,7 @@ const ZUserFormSchema = ZUpdateUserRequestSchema.omit({ id: true });
|
|||||||
type TUserFormSchema = z.infer<typeof ZUserFormSchema>;
|
type TUserFormSchema = z.infer<typeof ZUserFormSchema>;
|
||||||
|
|
||||||
export default function UserPage({ params }: { params: { id: number } }) {
|
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),
|
id: Number(params.id),
|
||||||
},
|
},
|
||||||
@ -78,7 +78,7 @@ export default function UserPage({ params }: { params: { id: number } }) {
|
|||||||
return <AdminUserPage user={user} />;
|
return <AdminUserPage user={user} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AdminUserPage = ({ user }: { user: User }) => {
|
const AdminUserPage = ({ user }: { user: TGetUserResponse }) => {
|
||||||
const { _ } = useLingui();
|
const { _ } = useLingui();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { revalidate } = useRevalidator();
|
const { revalidate } = useRevalidator();
|
||||||
|
|||||||
@ -45,6 +45,9 @@ export async function loader({ params, request }: Route.LoaderArgs) {
|
|||||||
mode: 'insensitive',
|
mode: 'insensitive',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Directly convert the team member invite to a team member if they already have an account.
|
// 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: {
|
where: {
|
||||||
email: email,
|
email: email,
|
||||||
},
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
emailVerified: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle existing user but no account.
|
// Handle existing user but no account.
|
||||||
|
|||||||
@ -42,6 +42,11 @@ export const run = async ({
|
|||||||
where: {
|
where: {
|
||||||
id: userId,
|
id: userId,
|
||||||
},
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
email: true,
|
||||||
|
name: true,
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
prisma.document.findFirstOrThrow({
|
prisma.document.findFirstOrThrow({
|
||||||
where: {
|
where: {
|
||||||
|
|||||||
@ -10,12 +10,6 @@ export type UpdateUserOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const updateUser = async ({ id, name, email, roles }: UpdateUserOptions) => {
|
export const updateUser = async ({ id, name, email, roles }: UpdateUserOptions) => {
|
||||||
await prisma.user.findFirstOrThrow({
|
|
||||||
where: {
|
|
||||||
id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await prisma.user.update({
|
await prisma.user.update({
|
||||||
where: {
|
where: {
|
||||||
id,
|
id,
|
||||||
|
|||||||
@ -1,13 +1,31 @@
|
|||||||
import { prisma } from '@documenso/prisma';
|
import { prisma } from '@documenso/prisma';
|
||||||
|
|
||||||
|
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||||
|
|
||||||
export interface GetUserByIdOptions {
|
export interface GetUserByIdOptions {
|
||||||
id: number;
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getUserById = async ({ id }: GetUserByIdOptions) => {
|
export const getUserById = async ({ id }: GetUserByIdOptions) => {
|
||||||
return await prisma.user.findFirstOrThrow({
|
const user = await prisma.user.findFirst({
|
||||||
where: {
|
where: {
|
||||||
id,
|
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({
|
await tx.userSecurityAuditLog.create({
|
||||||
data: {
|
data: {
|
||||||
userId,
|
userId,
|
||||||
@ -34,7 +34,7 @@ export const updateProfile = async ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return await tx.user.update({
|
await tx.user.update({
|
||||||
where: {
|
where: {
|
||||||
id: userId,
|
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 { findDocumentsRoute } from './find-documents';
|
||||||
import { findSubscriptionClaimsRoute } from './find-subscription-claims';
|
import { findSubscriptionClaimsRoute } from './find-subscription-claims';
|
||||||
import { getAdminOrganisationRoute } from './get-admin-organisation';
|
import { getAdminOrganisationRoute } from './get-admin-organisation';
|
||||||
|
import { getUserRoute } from './get-user';
|
||||||
import { resealDocumentRoute } from './reseal-document';
|
import { resealDocumentRoute } from './reseal-document';
|
||||||
import { resetTwoFactorRoute } from './reset-two-factor-authentication';
|
import { resetTwoFactorRoute } from './reset-two-factor-authentication';
|
||||||
import { updateAdminOrganisationRoute } from './update-admin-organisation';
|
import { updateAdminOrganisationRoute } from './update-admin-organisation';
|
||||||
@ -36,6 +37,7 @@ export const adminRouter = router({
|
|||||||
createCustomer: createStripeCustomerRoute,
|
createCustomer: createStripeCustomerRoute,
|
||||||
},
|
},
|
||||||
user: {
|
user: {
|
||||||
|
get: getUserRoute,
|
||||||
update: updateUserRoute,
|
update: updateUserRoute,
|
||||||
delete: deleteUserRoute,
|
delete: deleteUserRoute,
|
||||||
enable: enableUserRoute,
|
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 { setAvatarImage } from '@documenso/lib/server-only/profile/set-avatar-image';
|
||||||
import { deleteUser } from '@documenso/lib/server-only/user/delete-user';
|
import { deleteUser } from '@documenso/lib/server-only/user/delete-user';
|
||||||
import { findUserSecurityAuditLogs } from '@documenso/lib/server-only/user/find-user-security-audit-logs';
|
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 { submitSupportTicket } from '@documenso/lib/server-only/user/submit-support-ticket';
|
||||||
import { updateProfile } from '@documenso/lib/server-only/user/update-profile';
|
import { updateProfile } from '@documenso/lib/server-only/user/update-profile';
|
||||||
|
|
||||||
import { adminProcedure, authenticatedProcedure, router } from '../trpc';
|
import { authenticatedProcedure, router } from '../trpc';
|
||||||
import {
|
import {
|
||||||
ZFindUserSecurityAuditLogsSchema,
|
ZFindUserSecurityAuditLogsSchema,
|
||||||
ZRetrieveUserByIdQuerySchema,
|
|
||||||
ZSetProfileImageMutationSchema,
|
ZSetProfileImageMutationSchema,
|
||||||
ZSubmitSupportTicketMutationSchema,
|
ZSubmitSupportTicketMutationSchema,
|
||||||
ZUpdateProfileMutationSchema,
|
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
|
updateProfile: authenticatedProcedure
|
||||||
.input(ZUpdateProfileMutationSchema)
|
.input(ZUpdateProfileMutationSchema)
|
||||||
.mutation(async ({ input, ctx }) => {
|
.mutation(async ({ input, ctx }) => {
|
||||||
const { name, signature } = input;
|
const { name, signature } = input;
|
||||||
|
|
||||||
return await updateProfile({
|
await updateProfile({
|
||||||
userId: ctx.user.id,
|
userId: ctx.user.id,
|
||||||
name,
|
name,
|
||||||
signature,
|
signature,
|
||||||
@ -52,7 +38,7 @@ export const profileRouter = router({
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
deleteAccount: authenticatedProcedure.mutation(async ({ ctx }) => {
|
deleteAccount: authenticatedProcedure.mutation(async ({ ctx }) => {
|
||||||
return await deleteUser({
|
await deleteUser({
|
||||||
id: ctx.user.id,
|
id: ctx.user.id,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -7,12 +7,6 @@ export const ZFindUserSecurityAuditLogsSchema = z.object({
|
|||||||
|
|
||||||
export type TFindUserSecurityAuditLogsSchema = z.infer<typeof ZFindUserSecurityAuditLogsSchema>;
|
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({
|
export const ZUpdateProfileMutationSchema = z.object({
|
||||||
name: z.string().min(1),
|
name: z.string().min(1),
|
||||||
signature: z.string(),
|
signature: z.string(),
|
||||||
|
|||||||
Reference in New Issue
Block a user