fix: refactor routers (#1523)

This commit is contained in:
David Nguyen
2024-12-10 16:11:20 +09:00
committed by GitHub
parent dd162205fa
commit fae9c0ca24
33 changed files with 1122 additions and 738 deletions

View File

@@ -47,7 +47,7 @@ export const DocumentPageViewButton = ({ document, team }: DocumentPageViewButto
const onDownloadClick = async () => { const onDownloadClick = async () => {
try { try {
const documentWithData = await trpcClient.document.getDocumentById.query({ const documentWithData = await trpcClient.document.getDocumentById.query({
id: document.id, documentId: document.id,
teamId: team?.id, teamId: team?.id,
}); });

View File

@@ -75,7 +75,7 @@ export const DocumentPageViewDropdown = ({ document, team }: DocumentPageViewDro
const onDownloadClick = async () => { const onDownloadClick = async () => {
try { try {
const documentWithData = await trpcClient.document.getDocumentById.query({ const documentWithData = await trpcClient.document.getDocumentById.query({
id: document.id, documentId: document.id,
teamId: team?.id, teamId: team?.id,
}); });

View File

@@ -60,7 +60,7 @@ export const DocumentPageView = async ({ params, team }: DocumentPageViewProps)
const { user } = await getRequiredServerComponentSession(); const { user } = await getRequiredServerComponentSession();
const document = await getDocumentById({ const document = await getDocumentById({
id: documentId, documentId,
userId: user.id, userId: user.id,
teamId: team?.id, teamId: team?.id,
}).catch(() => null); }).catch(() => null);

View File

@@ -63,7 +63,7 @@ export const EditDocumentForm = ({
const { data: document, refetch: refetchDocument } = const { data: document, refetch: refetchDocument } =
trpc.document.getDocumentWithDetailsById.useQuery( trpc.document.getDocumentWithDetailsById.useQuery(
{ {
id: initialDocument.id, documentId: initialDocument.id,
teamId: team?.id, teamId: team?.id,
}, },
{ {
@@ -79,7 +79,7 @@ export const EditDocumentForm = ({
onSuccess: (newData) => { onSuccess: (newData) => {
utils.document.getDocumentWithDetailsById.setData( utils.document.getDocumentWithDetailsById.setData(
{ {
id: initialDocument.id, documentId: initialDocument.id,
teamId: team?.id, teamId: team?.id,
}, },
(oldData) => ({ ...(oldData || initialDocument), ...newData }), (oldData) => ({ ...(oldData || initialDocument), ...newData }),
@@ -93,7 +93,7 @@ export const EditDocumentForm = ({
onSuccess: (newData) => { onSuccess: (newData) => {
utils.document.getDocumentWithDetailsById.setData( utils.document.getDocumentWithDetailsById.setData(
{ {
id: initialDocument.id, documentId: initialDocument.id,
teamId: team?.id, teamId: team?.id,
}, },
(oldData) => ({ ...(oldData || initialDocument), ...newData, id: Number(newData.id) }), (oldData) => ({ ...(oldData || initialDocument), ...newData, id: Number(newData.id) }),
@@ -106,7 +106,7 @@ export const EditDocumentForm = ({
onSuccess: (newFields) => { onSuccess: (newFields) => {
utils.document.getDocumentWithDetailsById.setData( utils.document.getDocumentWithDetailsById.setData(
{ {
id: initialDocument.id, documentId: initialDocument.id,
teamId: team?.id, teamId: team?.id,
}, },
(oldData) => ({ ...(oldData || initialDocument), Field: newFields }), (oldData) => ({ ...(oldData || initialDocument), Field: newFields }),
@@ -120,7 +120,7 @@ export const EditDocumentForm = ({
onSuccess: (newData) => { onSuccess: (newData) => {
utils.document.getDocumentWithDetailsById.setData( utils.document.getDocumentWithDetailsById.setData(
{ {
id: initialDocument.id, documentId: initialDocument.id,
teamId: team?.id, teamId: team?.id,
}, },
(oldData) => ({ (oldData) => ({
@@ -137,7 +137,7 @@ export const EditDocumentForm = ({
onSuccess: (newRecipients) => { onSuccess: (newRecipients) => {
utils.document.getDocumentWithDetailsById.setData( utils.document.getDocumentWithDetailsById.setData(
{ {
id: initialDocument.id, documentId: initialDocument.id,
teamId: team?.id, teamId: team?.id,
}, },
(oldData) => ({ ...(oldData || initialDocument), Recipient: newRecipients }), (oldData) => ({ ...(oldData || initialDocument), Recipient: newRecipients }),
@@ -150,7 +150,7 @@ export const EditDocumentForm = ({
onSuccess: (newData) => { onSuccess: (newData) => {
utils.document.getDocumentWithDetailsById.setData( utils.document.getDocumentWithDetailsById.setData(
{ {
id: initialDocument.id, documentId: initialDocument.id,
teamId: team?.id, teamId: team?.id,
}, },
(oldData) => ({ ...(oldData || initialDocument), ...newData }), (oldData) => ({ ...(oldData || initialDocument), ...newData }),

View File

@@ -41,7 +41,7 @@ export const DocumentEditPageView = async ({ params, team }: DocumentEditPageVie
const { user } = await getRequiredServerComponentSession(); const { user } = await getRequiredServerComponentSession();
const document = await getDocumentWithDetailsById({ const document = await getDocumentWithDetailsById({
id: documentId, documentId,
userId: user.id, userId: user.id,
teamId: team?.id, teamId: team?.id,
}).catch(() => null); }).catch(() => null);

View File

@@ -47,7 +47,7 @@ export const DocumentLogsPageView = async ({ params, team }: DocumentLogsPageVie
const [document, recipients] = await Promise.all([ const [document, recipients] = await Promise.all([
getDocumentById({ getDocumentById({
id: documentId, documentId,
userId: user.id, userId: user.id,
teamId: team?.id, teamId: team?.id,
}).catch(() => null), }).catch(() => null),

View File

@@ -54,7 +54,7 @@ export const DataTableActionButton = ({ row, team }: DataTableActionButtonProps)
if (!recipient) { if (!recipient) {
document = await trpcClient.document.getDocumentById.query({ document = await trpcClient.document.getDocumentById.query({
id: row.id, documentId: row.id,
teamId: team?.id, teamId: team?.id,
}); });
} else { } else {

View File

@@ -85,7 +85,7 @@ export const DataTableActionDropdown = ({ row, team }: DataTableActionDropdownPr
if (!recipient) { if (!recipient) {
document = await trpcClient.document.getDocumentById.query({ document = await trpcClient.document.getDocumentById.query({
id: row.id, documentId: row.id,
teamId: team?.id, teamId: team?.id,
}); });
} else { } else {

View File

@@ -76,7 +76,7 @@ export const DeleteDocumentDialog = ({
const onDelete = async () => { const onDelete = async () => {
try { try {
await deleteDocument({ id, teamId }); await deleteDocument({ documentId: id, teamId });
} catch { } catch {
toast({ toast({
title: _(msg`Something went wrong`), title: _(msg`Something went wrong`),

View File

@@ -36,7 +36,7 @@ export const DuplicateDocumentDialog = ({
const { _ } = useLingui(); const { _ } = useLingui();
const { data: document, isLoading } = trpcReact.document.getDocumentById.useQuery({ const { data: document, isLoading } = trpcReact.document.getDocumentById.useQuery({
id, documentId: id,
teamId: team?.id, teamId: team?.id,
}); });
@@ -66,7 +66,7 @@ export const DuplicateDocumentDialog = ({
const onDuplicate = async () => { const onDuplicate = async () => {
try { try {
await duplicateDocument({ id, teamId: team?.id }); await duplicateDocument({ documentId: id, teamId: team?.id });
} catch { } catch {
toast({ toast({
title: _(msg`Something went wrong`), title: _(msg`Something went wrong`),
@@ -92,7 +92,7 @@ export const DuplicateDocumentDialog = ({
</h1> </h1>
</div> </div>
) : ( ) : (
<div className="p-2 [&>div]:h-[50vh] [&>div]:overflow-y-scroll "> <div className="p-2 [&>div]:h-[50vh] [&>div]:overflow-y-scroll">
<LazyPDFViewer key={document?.id} documentData={documentData} /> <LazyPDFViewer key={document?.id} documentData={documentData} />
</div> </div>
)} )}

View File

@@ -59,10 +59,10 @@ export const EditTemplateForm = ({
const utils = trpc.useUtils(); const utils = trpc.useUtils();
const { data: template, refetch: refetchTemplate } = const { data: template, refetch: refetchTemplate } = trpc.template.getTemplateById.useQuery(
trpc.template.getTemplateWithDetailsById.useQuery(
{ {
id: initialTemplate.id, templateId: initialTemplate.id,
teamId: initialTemplate.teamId || undefined,
}, },
{ {
initialData: initialTemplate, initialData: initialTemplate,
@@ -92,12 +92,12 @@ export const EditTemplateForm = ({
const currentDocumentFlow = documentFlow[step]; const currentDocumentFlow = documentFlow[step];
const { mutateAsync: updateTemplateSettings } = trpc.template.updateTemplateSettings.useMutation({ const { mutateAsync: updateTemplateSettings } = trpc.template.updateTemplate.useMutation({
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION, ...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
onSuccess: (newData) => { onSuccess: (newData) => {
utils.template.getTemplateWithDetailsById.setData( utils.template.getTemplateById.setData(
{ {
id: initialTemplate.id, templateId: initialTemplate.id,
}, },
(oldData) => ({ ...(oldData || initialTemplate), ...newData }), (oldData) => ({ ...(oldData || initialTemplate), ...newData }),
); );
@@ -108,9 +108,9 @@ export const EditTemplateForm = ({
trpc.template.setSigningOrderForTemplate.useMutation({ trpc.template.setSigningOrderForTemplate.useMutation({
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION, ...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
onSuccess: (newData) => { onSuccess: (newData) => {
utils.template.getTemplateWithDetailsById.setData( utils.template.getTemplateById.setData(
{ {
id: initialTemplate.id, templateId: initialTemplate.id,
}, },
(oldData) => ({ ...(oldData || initialTemplate), ...newData }), (oldData) => ({ ...(oldData || initialTemplate), ...newData }),
); );
@@ -120,9 +120,9 @@ export const EditTemplateForm = ({
const { mutateAsync: addTemplateFields } = trpc.field.addTemplateFields.useMutation({ const { mutateAsync: addTemplateFields } = trpc.field.addTemplateFields.useMutation({
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION, ...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
onSuccess: (newData) => { onSuccess: (newData) => {
utils.template.getTemplateWithDetailsById.setData( utils.template.getTemplateById.setData(
{ {
id: initialTemplate.id, templateId: initialTemplate.id,
}, },
(oldData) => ({ ...(oldData || initialTemplate), ...newData }), (oldData) => ({ ...(oldData || initialTemplate), ...newData }),
); );
@@ -132,9 +132,9 @@ export const EditTemplateForm = ({
const { mutateAsync: addTemplateSigners } = trpc.recipient.addTemplateSigners.useMutation({ const { mutateAsync: addTemplateSigners } = trpc.recipient.addTemplateSigners.useMutation({
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION, ...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
onSuccess: (newData) => { onSuccess: (newData) => {
utils.template.getTemplateWithDetailsById.setData( utils.template.getTemplateById.setData(
{ {
id: initialTemplate.id, templateId: initialTemplate.id,
}, },
(oldData) => ({ ...(oldData || initialTemplate), ...newData }), (oldData) => ({ ...(oldData || initialTemplate), ...newData }),
); );
@@ -145,9 +145,9 @@ export const EditTemplateForm = ({
trpc.template.updateTemplateTypedSignatureSettings.useMutation({ trpc.template.updateTemplateTypedSignatureSettings.useMutation({
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION, ...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
onSuccess: (newData) => { onSuccess: (newData) => {
utils.template.getTemplateWithDetailsById.setData( utils.template.getTemplateById.setData(
{ {
id: initialTemplate.id, templateId: initialTemplate.id,
}, },
(oldData) => ({ (oldData) => ({
...(oldData || initialTemplate), ...(oldData || initialTemplate),

View File

@@ -8,7 +8,7 @@ import { ChevronLeft } from 'lucide-react';
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise'; import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session'; import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session';
import { getTemplateWithDetailsById } from '@documenso/lib/server-only/template/get-template-with-details-by-id'; import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id';
import { formatTemplatesPath } from '@documenso/lib/utils/teams'; import { formatTemplatesPath } from '@documenso/lib/utils/teams';
import type { Team } from '@documenso/prisma/client'; import type { Team } from '@documenso/prisma/client';
@@ -37,9 +37,10 @@ export const TemplateEditPageView = async ({ params, team }: TemplateEditPageVie
const { user } = await getRequiredServerComponentSession(); const { user } = await getRequiredServerComponentSession();
const template = await getTemplateWithDetailsById({ const template = await getTemplateById({
id: templateId, id: templateId,
userId: user.id, userId: user.id,
teamId: team?.id,
}).catch(() => null); }).catch(() => null);
if (!template || !template.templateDocumentData) { if (!template || !template.templateDocumentData) {

View File

@@ -85,7 +85,7 @@ export const DeleteTemplateDialog = ({
type="button" type="button"
variant="destructive" variant="destructive"
loading={isLoading} loading={isLoading}
onClick={async () => deleteTemplate({ id, teamId })} onClick={async () => deleteTemplate({ templateId: id, teamId })}
> >
<Trans>Delete</Trans> <Trans>Delete</Trans>
</Button> </Button>

View File

@@ -40,7 +40,7 @@ export type TConfigureDirectTemplateFormSchema = z.infer<typeof ZConfigureDirect
export type ConfigureDirectTemplateFormProps = { export type ConfigureDirectTemplateFormProps = {
flowStep: DocumentFlowStep; flowStep: DocumentFlowStep;
isDocumentPdfLoaded: boolean; isDocumentPdfLoaded: boolean;
template: TemplateWithDetails; template: Omit<TemplateWithDetails, 'User'>;
directTemplateRecipient: Recipient & { Field: Field[] }; directTemplateRecipient: Recipient & { Field: Field[] };
initialEmail?: string; initialEmail?: string;
onSubmit: (_data: TConfigureDirectTemplateFormSchema) => void; onSubmit: (_data: TConfigureDirectTemplateFormSchema) => void;

View File

@@ -28,7 +28,7 @@ import type { DirectTemplateLocalField } from './sign-direct-template';
import { SignDirectTemplateForm } from './sign-direct-template'; import { SignDirectTemplateForm } from './sign-direct-template';
export type TemplatesDirectPageViewProps = { export type TemplatesDirectPageViewProps = {
template: TemplateWithDetails; template: Omit<TemplateWithDetails, 'User'>;
directTemplateToken: string; directTemplateToken: string;
directTemplateRecipient: Recipient & { Field: Field[] }; directTemplateRecipient: Recipient & { Field: Field[] };
}; };

View File

@@ -55,7 +55,7 @@ export type SignDirectTemplateFormProps = {
flowStep: DocumentFlowStep; flowStep: DocumentFlowStep;
directRecipient: Recipient; directRecipient: Recipient;
directRecipientFields: Field[]; directRecipientFields: Field[];
template: TemplateWithDetails; template: Omit<TemplateWithDetails, 'User'>;
onSubmit: (_data: DirectTemplateLocalField[]) => Promise<void>; onSubmit: (_data: DirectTemplateLocalField[]) => Promise<void>;
}; };

View File

@@ -48,7 +48,7 @@ export default async function WaitingForTurnToSignPage({
if (user) { if (user) {
isOwnerOrTeamMember = await getDocumentById({ isOwnerOrTeamMember = await getDocumentById({
id: document.id, documentId: document.id,
userId: user.id, userId: user.id,
teamId: document.teamId ?? undefined, teamId: document.teamId ?? undefined,
}) })

View File

@@ -117,7 +117,7 @@ export const ManagePublicTemplateDialog = ({
}); });
const { mutateAsync: updateTemplateSettings, isLoading: isUpdatingTemplateSettings } = const { mutateAsync: updateTemplateSettings, isLoading: isUpdatingTemplateSettings } =
trpc.template.updateTemplateSettings.useMutation(); trpc.template.updateTemplate.useMutation();
const setTemplateToPrivate = async (templateId: number) => { const setTemplateToPrivate = async (templateId: number) => {
try { try {

View File

@@ -88,7 +88,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
try { try {
const document = await getDocumentById({ const document = await getDocumentById({
id: Number(documentId), documentId: Number(documentId),
userId: user.id, userId: user.id,
teamId: team?.id, teamId: team?.id,
}); });
@@ -158,7 +158,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
} }
const document = await getDocumentById({ const document = await getDocumentById({
id: Number(documentId), documentId: Number(documentId),
userId: user.id, userId: user.id,
teamId: team?.id, teamId: team?.id,
}); });
@@ -211,7 +211,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
try { try {
const document = await getDocumentById({ const document = await getDocumentById({
id: Number(documentId), documentId: Number(documentId),
userId: user.id, userId: user.id,
teamId: team?.id, teamId: team?.id,
}); });
@@ -640,7 +640,11 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
const { id } = args.params; const { id } = args.params;
const { sendEmail = true } = args.body ?? {}; const { sendEmail = true } = args.body ?? {};
const document = await getDocumentById({ id: Number(id), userId: user.id, teamId: team?.id }); const document = await getDocumentById({
documentId: Number(id),
userId: user.id,
teamId: team?.id,
});
if (!document) { if (!document) {
return { return {
@@ -757,7 +761,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
const { name, email, role, authOptions, signingOrder } = args.body; const { name, email, role, authOptions, signingOrder } = args.body;
const document = await getDocumentById({ const document = await getDocumentById({
id: Number(documentId), documentId: Number(documentId),
userId: user.id, userId: user.id,
teamId: team?.id, teamId: team?.id,
}); });
@@ -848,7 +852,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
const { name, email, role, authOptions, signingOrder } = args.body; const { name, email, role, authOptions, signingOrder } = args.body;
const document = await getDocumentById({ const document = await getDocumentById({
id: Number(documentId), documentId: Number(documentId),
userId: user.id, userId: user.id,
teamId: team?.id, teamId: team?.id,
}); });
@@ -907,7 +911,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
const { id: documentId, recipientId } = args.params; const { id: documentId, recipientId } = args.params;
const document = await getDocumentById({ const document = await getDocumentById({
id: Number(documentId), documentId: Number(documentId),
userId: user.id, userId: user.id,
teamId: team?.id, teamId: team?.id,
}); });
@@ -1134,7 +1138,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
args.body; args.body;
const document = await getDocumentById({ const document = await getDocumentById({
id: Number(documentId), documentId: Number(documentId),
userId: user.id, userId: user.id,
teamId: team?.id, teamId: team?.id,
}); });
@@ -1223,7 +1227,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
const { id: documentId, fieldId } = args.params; const { id: documentId, fieldId } = args.params;
const document = await getDocumentById({ const document = await getDocumentById({
id: Number(documentId), documentId: Number(documentId),
userId: user.id, userId: user.id,
}); });

View File

@@ -4,18 +4,18 @@ import { DocumentSource, type Prisma } from '@documenso/prisma/client';
import { getDocumentWhereInput } from './get-document-by-id'; import { getDocumentWhereInput } from './get-document-by-id';
export interface DuplicateDocumentByIdOptions { export interface DuplicateDocumentByIdOptions {
id: number; documentId: number;
userId: number; userId: number;
teamId?: number; teamId?: number;
} }
export const duplicateDocumentById = async ({ export const duplicateDocumentById = async ({
id, documentId,
userId, userId,
teamId, teamId,
}: DuplicateDocumentByIdOptions) => { }: DuplicateDocumentByIdOptions) => {
const documentWhereInput = await getDocumentWhereInput({ const documentWhereInput = await getDocumentWhereInput({
documentId: id, documentId,
userId, userId,
teamId, teamId,
}); });

View File

@@ -9,14 +9,14 @@ import { DocumentVisibility } from '../../types/document-visibility';
import { getTeamById } from '../team/get-team'; import { getTeamById } from '../team/get-team';
export type GetDocumentByIdOptions = { export type GetDocumentByIdOptions = {
id: number; documentId: number;
userId: number; userId: number;
teamId?: number; teamId?: number;
}; };
export const getDocumentById = async ({ id, userId, teamId }: GetDocumentByIdOptions) => { export const getDocumentById = async ({ documentId, userId, teamId }: GetDocumentByIdOptions) => {
const documentWhereInput = await getDocumentWhereInput({ const documentWhereInput = await getDocumentWhereInput({
documentId: id, documentId,
userId, userId,
teamId, teamId,
}); });

View File

@@ -4,18 +4,18 @@ import type { DocumentWithDetails } from '@documenso/prisma/types/document';
import { getDocumentWhereInput } from './get-document-by-id'; import { getDocumentWhereInput } from './get-document-by-id';
export type GetDocumentWithDetailsByIdOptions = { export type GetDocumentWithDetailsByIdOptions = {
id: number; documentId: number;
userId: number; userId: number;
teamId?: number; teamId?: number;
}; };
export const getDocumentWithDetailsById = async ({ export const getDocumentWithDetailsById = async ({
id, documentId,
userId, userId,
teamId, teamId,
}: GetDocumentWithDetailsByIdOptions): Promise<DocumentWithDetails> => { }: GetDocumentWithDetailsByIdOptions): Promise<DocumentWithDetails> => {
const documentWhereInput = await getDocumentWhereInput({ const documentWhereInput = await getDocumentWhereInput({
documentId: id, documentId,
userId, userId,
teamId, teamId,
}); });

View File

@@ -1,15 +1,45 @@
import type { z } from 'zod';
import { prisma } from '@documenso/prisma'; import { prisma } from '@documenso/prisma';
import type { Prisma } from '@documenso/prisma/client'; import type { Prisma } from '@documenso/prisma/client';
import {
DocumentDataSchema,
FieldSchema,
RecipientSchema,
TemplateDirectLinkSchema,
TemplateMetaSchema,
TemplateSchema,
UserSchema,
} from '@documenso/prisma/generated/zod';
import { AppError, AppErrorCode } from '../../errors/app-error'; import { AppError, AppErrorCode } from '../../errors/app-error';
export interface GetTemplateByIdOptions { export type GetTemplateByIdOptions = {
id: number; id: number;
userId: number; userId: number;
teamId?: number; teamId?: number;
} };
export const getTemplateById = async ({ id, userId, teamId }: GetTemplateByIdOptions) => { export const ZGetTemplateByIdResponseSchema = TemplateSchema.extend({
directLink: TemplateDirectLinkSchema.nullable(),
templateDocumentData: DocumentDataSchema,
templateMeta: TemplateMetaSchema.nullable(),
Recipient: RecipientSchema.array(),
Field: FieldSchema.array(),
User: UserSchema.pick({
id: true,
name: true,
email: true,
}),
});
export type TGetTemplateByIdResponse = z.infer<typeof ZGetTemplateByIdResponseSchema>;
export const getTemplateById = async ({
id,
userId,
teamId,
}: GetTemplateByIdOptions): Promise<TGetTemplateByIdResponse> => {
const whereFilter: Prisma.TemplateWhereInput = { const whereFilter: Prisma.TemplateWhereInput = {
id, id,
OR: OR:

View File

@@ -1,49 +0,0 @@
import { prisma } from '@documenso/prisma';
import type { TemplateWithDetails } from '@documenso/prisma/types/template';
import { AppError, AppErrorCode } from '../../errors/app-error';
export type GetTemplateWithDetailsByIdOptions = {
id: number;
userId: number;
};
export const getTemplateWithDetailsById = async ({
id,
userId,
}: GetTemplateWithDetailsByIdOptions): Promise<TemplateWithDetails> => {
const template = await prisma.template.findFirst({
where: {
id,
OR: [
{
userId,
},
{
team: {
members: {
some: {
userId,
},
},
},
},
],
},
include: {
directLink: true,
templateDocumentData: true,
templateMeta: true,
Recipient: true,
Field: true,
},
});
if (!template) {
throw new AppError(AppErrorCode.NOT_FOUND, {
message: 'Template not found',
});
}
return template;
};

View File

@@ -1,21 +1,9 @@
import type { import type { TGetTemplateByIdResponse } from '@documenso/lib/server-only/template/get-template-by-id';
DocumentData, import type { DocumentData, Template, TemplateMeta } from '@documenso/prisma/client';
Field,
Recipient,
Template,
TemplateDirectLink,
TemplateMeta,
} from '@documenso/prisma/client';
export type TemplateWithData = Template & { export type TemplateWithData = Template & {
templateDocumentData?: DocumentData | null; templateDocumentData?: DocumentData | null;
templateMeta?: TemplateMeta | null; templateMeta?: TemplateMeta | null;
}; };
export type TemplateWithDetails = Template & { export type TemplateWithDetails = TGetTemplateByIdResponse;
directLink: TemplateDirectLink | null;
templateDocumentData: DocumentData;
templateMeta: TemplateMeta | null;
Recipient: Recipient[];
Field: Field[];
};

View File

@@ -1,5 +1,6 @@
import { TRPCError } from '@trpc/server'; import { TRPCError } from '@trpc/server';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import { z } from 'zod';
import { getServerLimits } from '@documenso/ee/server-only/limits/server'; import { getServerLimits } from '@documenso/ee/server-only/limits/server';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app'; import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
@@ -28,7 +29,7 @@ import { DocumentStatus } from '@documenso/prisma/client';
import { authenticatedProcedure, procedure, router } from '../trpc'; import { authenticatedProcedure, procedure, router } from '../trpc';
import { import {
ZCreateDocumentMutationSchema, ZCreateDocumentMutationSchema,
ZDeleteDraftDocumentMutationSchema as ZDeleteDocumentMutationSchema, ZDeleteDocumentMutationSchema,
ZDownloadAuditLogsMutationSchema, ZDownloadAuditLogsMutationSchema,
ZDownloadCertificateMutationSchema, ZDownloadCertificateMutationSchema,
ZFindDocumentAuditLogsQuerySchema, ZFindDocumentAuditLogsQuerySchema,
@@ -48,6 +49,7 @@ import {
} from './schema'; } from './schema';
export const documentRouter = router({ export const documentRouter = router({
// Internal endpoint for now.
getDocumentById: authenticatedProcedure getDocumentById: authenticatedProcedure
.input(ZGetDocumentByIdQuerySchema) .input(ZGetDocumentByIdQuerySchema)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
@@ -57,6 +59,7 @@ export const documentRouter = router({
}); });
}), }),
// Internal endpoint for now.
getDocumentByToken: procedure getDocumentByToken: procedure
.input(ZGetDocumentByTokenQuerySchema) .input(ZGetDocumentByTokenQuerySchema)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
@@ -68,8 +71,50 @@ export const documentRouter = router({
}); });
}), }),
findDocuments: authenticatedProcedure
.meta({
openapi: {
method: 'GET',
path: '/document/find',
summary: 'Find documents',
description: 'Find documents based on a search criteria',
tags: ['Documents'],
},
})
.input(ZFindDocumentsQuerySchema)
.output(z.unknown())
.query(async ({ input, ctx }) => {
const { user } = ctx;
const { search, teamId, templateId, page, perPage, orderBy, source, status } = input;
const documents = await findDocuments({
userId: user.id,
teamId,
templateId,
search,
source,
status,
page,
perPage,
orderBy,
});
return documents;
}),
getDocumentWithDetailsById: authenticatedProcedure getDocumentWithDetailsById: authenticatedProcedure
.meta({
openapi: {
method: 'GET',
path: '/document/{documentId}',
summary: 'Get document',
description: 'Returns a document given an ID',
tags: ['Documents'],
},
})
.input(ZGetDocumentWithDetailsByIdQuerySchema) .input(ZGetDocumentWithDetailsByIdQuerySchema)
.output(z.unknown())
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
return await getDocumentWithDetailsById({ return await getDocumentWithDetailsById({
...input, ...input,
@@ -78,7 +123,16 @@ export const documentRouter = router({
}), }),
createDocument: authenticatedProcedure createDocument: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/document/create',
summary: 'Create document',
tags: ['Documents'],
},
})
.input(ZCreateDocumentMutationSchema) .input(ZCreateDocumentMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { title, documentDataId, teamId } = input; const { title, documentDataId, teamId } = input;
@@ -100,76 +154,18 @@ export const documentRouter = router({
}); });
}), }),
deleteDocument: authenticatedProcedure // Todo: Refactor to updateDocument.
.input(ZDeleteDocumentMutationSchema)
.mutation(async ({ input, ctx }) => {
const { id, teamId } = input;
const userId = ctx.user.id;
return await deleteDocument({
id,
userId,
teamId,
requestMetadata: extractNextApiRequestMetadata(ctx.req),
});
}),
moveDocumentToTeam: authenticatedProcedure
.input(ZMoveDocumentsToTeamSchema)
.mutation(async ({ input, ctx }) => {
const { documentId, teamId } = input;
const userId = ctx.user.id;
return await moveDocumentToTeam({
documentId,
teamId,
userId,
requestMetadata: extractNextApiRequestMetadata(ctx.req),
});
}),
findDocuments: authenticatedProcedure
.input(ZFindDocumentsQuerySchema)
.query(async ({ input, ctx }) => {
const { user } = ctx;
const { search, teamId, templateId, page, perPage, orderBy, source, status } = input;
const documents = await findDocuments({
userId: user.id,
teamId,
templateId,
search,
source,
status,
page,
perPage,
orderBy,
});
return documents;
}),
findDocumentAuditLogs: authenticatedProcedure
.input(ZFindDocumentAuditLogsQuerySchema)
.query(async ({ input, ctx }) => {
const { page, perPage, documentId, cursor, filterForRecentActivity, orderBy } = input;
return await findDocumentAuditLogs({
page,
perPage,
documentId,
cursor,
filterForRecentActivity,
orderBy,
userId: ctx.user.id,
});
}),
// Todo: Add API
setSettingsForDocument: authenticatedProcedure setSettingsForDocument: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/document/{documentId}',
summary: 'Update document',
tags: ['Documents'],
},
})
.input(ZSetSettingsForDocumentMutationSchema) .input(ZSetSettingsForDocumentMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { documentId, teamId, data, meta } = input; const { documentId, teamId, data, meta } = input;
@@ -198,6 +194,56 @@ export const documentRouter = router({
}); });
}), }),
deleteDocument: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/document/{documentId}/delete',
summary: 'Delete document',
tags: ['Documents'],
},
})
.input(ZDeleteDocumentMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => {
const { documentId, teamId } = input;
const userId = ctx.user.id;
return await deleteDocument({
id: documentId,
userId,
teamId,
requestMetadata: extractNextApiRequestMetadata(ctx.req),
});
}),
moveDocumentToTeam: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/document/{documentId}/move',
summary: 'Move document',
description: 'Move a document to a team',
tags: ['Documents'],
},
})
.input(ZMoveDocumentsToTeamSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => {
const { documentId, teamId } = input;
const userId = ctx.user.id;
return await moveDocumentToTeam({
documentId,
teamId,
userId,
requestMetadata: extractNextApiRequestMetadata(ctx.req),
});
}),
// Internal endpoint for now.
// Should probably use `updateDocument`
setTitleForDocument: authenticatedProcedure setTitleForDocument: authenticatedProcedure
.input(ZSetTitleForDocumentMutationSchema) .input(ZSetTitleForDocumentMutationSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
@@ -214,6 +260,7 @@ export const documentRouter = router({
}); });
}), }),
// Internal endpoint for now.
setPasswordForDocument: authenticatedProcedure setPasswordForDocument: authenticatedProcedure
.input(ZSetPasswordForDocumentMutationSchema) .input(ZSetPasswordForDocumentMutationSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
@@ -238,6 +285,7 @@ export const documentRouter = router({
}); });
}), }),
// Internal endpoint for now.
setSigningOrderForDocument: authenticatedProcedure setSigningOrderForDocument: authenticatedProcedure
.input(ZSetSigningOrderForDocumentMutationSchema) .input(ZSetSigningOrderForDocumentMutationSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
@@ -251,13 +299,14 @@ export const documentRouter = router({
}); });
}), }),
// Internal endpoint for now.
updateTypedSignatureSettings: authenticatedProcedure updateTypedSignatureSettings: authenticatedProcedure
.input(ZUpdateTypedSignatureSettingsMutationSchema) .input(ZUpdateTypedSignatureSettingsMutationSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { documentId, teamId, typedSignatureEnabled } = input; const { documentId, teamId, typedSignatureEnabled } = input;
const document = await getDocumentById({ const document = await getDocumentById({
id: documentId, documentId,
teamId, teamId,
userId: ctx.user.id, userId: ctx.user.id,
}).catch(() => null); }).catch(() => null);
@@ -277,8 +326,20 @@ export const documentRouter = router({
}); });
}), }),
// Todo: Refactor to distributeDocument.
// Todo: Rework before releasing API.
sendDocument: authenticatedProcedure sendDocument: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/document/{documentId}/distribute',
summary: 'Distribute document',
description: 'Send the document out to recipients based on your distribution method',
tags: ['Documents'],
},
})
.input(ZSendDocumentMutationSchema) .input(ZSendDocumentMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { documentId, teamId, meta } = input; const { documentId, teamId, meta } = input;
@@ -314,7 +375,18 @@ export const documentRouter = router({
}), }),
resendDocument: authenticatedProcedure resendDocument: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/document/{documentId}/resend',
summary: 'Resend document',
description:
'Resend the document to recipients who have not signed. Will use the distribution method set in the document.',
tags: ['Documents'],
},
})
.input(ZResendDocumentMutationSchema) .input(ZResendDocumentMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
return await resendDocument({ return await resendDocument({
userId: ctx.user.id, userId: ctx.user.id,
@@ -324,7 +396,16 @@ export const documentRouter = router({
}), }),
duplicateDocument: authenticatedProcedure duplicateDocument: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/document/{documentId}/duplicate',
summary: 'Duplicate document',
tags: ['Documents'],
},
})
.input(ZGetDocumentByIdQuerySchema) .input(ZGetDocumentByIdQuerySchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
return await duplicateDocumentById({ return await duplicateDocumentById({
userId: ctx.user.id, userId: ctx.user.id,
@@ -332,6 +413,7 @@ export const documentRouter = router({
}); });
}), }),
// Internal endpoint for now.
searchDocuments: authenticatedProcedure searchDocuments: authenticatedProcedure
.input(ZSearchDocumentsMutationSchema) .input(ZSearchDocumentsMutationSchema)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
@@ -345,13 +427,31 @@ export const documentRouter = router({
return documents; return documents;
}), }),
// Internal endpoint for now.
findDocumentAuditLogs: authenticatedProcedure
.input(ZFindDocumentAuditLogsQuerySchema)
.query(async ({ input, ctx }) => {
const { page, perPage, documentId, cursor, filterForRecentActivity, orderBy } = input;
return await findDocumentAuditLogs({
page,
perPage,
documentId,
cursor,
filterForRecentActivity,
orderBy,
userId: ctx.user.id,
});
}),
// Internal endpoint for now.
downloadAuditLogs: authenticatedProcedure downloadAuditLogs: authenticatedProcedure
.input(ZDownloadAuditLogsMutationSchema) .input(ZDownloadAuditLogsMutationSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { documentId, teamId } = input; const { documentId, teamId } = input;
const document = await getDocumentById({ const document = await getDocumentById({
id: documentId, documentId,
userId: ctx.user.id, userId: ctx.user.id,
teamId, teamId,
}).catch(() => null); }).catch(() => null);
@@ -373,13 +473,14 @@ export const documentRouter = router({
}; };
}), }),
// Internal endpoint for now.
downloadCertificate: authenticatedProcedure downloadCertificate: authenticatedProcedure
.input(ZDownloadCertificateMutationSchema) .input(ZDownloadCertificateMutationSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { documentId, teamId } = input; const { documentId, teamId } = input;
const document = await getDocumentById({ const document = await getDocumentById({
id: documentId, documentId,
userId: ctx.user.id, userId: ctx.user.id,
teamId, teamId,
}); });

View File

@@ -48,7 +48,7 @@ export const ZFindDocumentAuditLogsQuerySchema = ZBaseTableSearchParamsSchema.ex
}); });
export const ZGetDocumentByIdQuerySchema = z.object({ export const ZGetDocumentByIdQuerySchema = z.object({
id: z.number().min(1), documentId: z.number().min(1),
teamId: z.number().min(1).optional(), teamId: z.number().min(1).optional(),
}); });
@@ -61,7 +61,7 @@ export const ZGetDocumentByTokenQuerySchema = z.object({
export type TGetDocumentByTokenQuerySchema = z.infer<typeof ZGetDocumentByTokenQuerySchema>; export type TGetDocumentByTokenQuerySchema = z.infer<typeof ZGetDocumentByTokenQuerySchema>;
export const ZGetDocumentWithDetailsByIdQuerySchema = z.object({ export const ZGetDocumentWithDetailsByIdQuerySchema = z.object({
id: z.number().min(1), documentId: z.number().min(1),
teamId: z.number().min(1).optional(), teamId: z.number().min(1).optional(),
}); });
@@ -206,12 +206,12 @@ export const ZResendDocumentMutationSchema = z.object({
export type TSendDocumentMutationSchema = z.infer<typeof ZSendDocumentMutationSchema>; export type TSendDocumentMutationSchema = z.infer<typeof ZSendDocumentMutationSchema>;
export const ZDeleteDraftDocumentMutationSchema = z.object({ export const ZDeleteDocumentMutationSchema = z.object({
id: z.number().min(1), documentId: z.number().min(1),
teamId: z.number().min(1).optional(), teamId: z.number().min(1).optional(),
}); });
export type TDeleteDraftDocumentMutationSchema = z.infer<typeof ZDeleteDraftDocumentMutationSchema>; export type TDeleteDocumentMutationSchema = z.infer<typeof ZDeleteDocumentMutationSchema>;
export const ZSearchDocumentsMutationSchema = z.object({ export const ZSearchDocumentsMutationSchema = z.object({
query: z.string(), query: z.string(),

View File

@@ -1,3 +1,5 @@
import { z } from 'zod';
import { getFieldById } from '@documenso/lib/server-only/field/get-field-by-id'; import { getFieldById } from '@documenso/lib/server-only/field/get-field-by-id';
import { removeSignedFieldWithToken } from '@documenso/lib/server-only/field/remove-signed-field-with-token'; import { removeSignedFieldWithToken } from '@documenso/lib/server-only/field/remove-signed-field-with-token';
import { setFieldsForDocument } from '@documenso/lib/server-only/field/set-fields-for-document'; import { setFieldsForDocument } from '@documenso/lib/server-only/field/set-fields-for-document';
@@ -15,8 +17,39 @@ import {
} from './schema'; } from './schema';
export const fieldRouter = router({ export const fieldRouter = router({
getField: authenticatedProcedure
.meta({
openapi: {
method: 'GET',
path: '/field/{fieldId}',
summary: 'Get field',
description: 'Returns a document or template field',
tags: ['Fields'],
},
})
.input(ZGetFieldQuerySchema)
.output(z.unknown())
.query(async ({ input, ctx }) => {
const { fieldId, teamId } = input;
return await getFieldById({
userId: ctx.user.id,
teamId,
fieldId,
});
}),
addFields: authenticatedProcedure addFields: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/document/{documentId}/field',
summary: 'Set document fields',
tags: ['Fields'],
},
})
.input(ZAddFieldsMutationSchema) .input(ZAddFieldsMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { documentId, fields } = input; const { documentId, fields } = input;
@@ -39,7 +72,16 @@ export const fieldRouter = router({
}), }),
addTemplateFields: authenticatedProcedure addTemplateFields: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/template/{templateId}/field',
summary: 'Set template fields',
tags: ['Fields'],
},
})
.input(ZAddTemplateFieldsMutationSchema) .input(ZAddTemplateFieldsMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { templateId, fields } = input; const { templateId, fields } = input;
@@ -60,6 +102,7 @@ export const fieldRouter = router({
}); });
}), }),
// Internal endpoint for now.
signFieldWithToken: procedure signFieldWithToken: procedure
.input(ZSignFieldWithTokenMutationSchema) .input(ZSignFieldWithTokenMutationSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
@@ -76,6 +119,7 @@ export const fieldRouter = router({
}); });
}), }),
// Internal endpoint for now.
removeSignedFieldWithToken: procedure removeSignedFieldWithToken: procedure
.input(ZRemovedSignedFieldWithTokenMutationSchema) .input(ZRemovedSignedFieldWithTokenMutationSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
@@ -87,40 +131,4 @@ export const fieldRouter = router({
requestMetadata: extractNextApiRequestMetadata(ctx.req), requestMetadata: extractNextApiRequestMetadata(ctx.req),
}); });
}), }),
getField: authenticatedProcedure.input(ZGetFieldQuerySchema).query(async ({ input, ctx }) => {
const { fieldId, teamId } = input;
return await getFieldById({
userId: ctx.user.id,
teamId,
fieldId,
});
}),
// This doesn't appear to be used anywhere, and it doesn't seem to support updating template fields
// so commenting this out for now.
// updateField: authenticatedProcedure
// .input(ZUpdateFieldMutationSchema)
// .mutation(async ({ input, ctx }) => {
// try {
// const { documentId, fieldId, fieldMeta, teamId } = input;
// return await updateField({
// userId: ctx.user.id,
// teamId,
// fieldId,
// documentId,
// requestMetadata: extractNextApiRequestMetadata(ctx.req),
// fieldMeta: fieldMeta,
// });
// } catch (err) {
// console.error(err);
// throw new TRPCError({
// code: 'BAD_REQUEST',
// message: 'We were unable to set this field. Please try again later.',
// });
// }
// }),
}); });

View File

@@ -1,3 +1,5 @@
import { z } from 'zod';
import { completeDocumentWithToken } from '@documenso/lib/server-only/document/complete-document-with-token'; import { completeDocumentWithToken } from '@documenso/lib/server-only/document/complete-document-with-token';
import { rejectDocumentWithToken } from '@documenso/lib/server-only/document/reject-document-with-token'; import { rejectDocumentWithToken } from '@documenso/lib/server-only/document/reject-document-with-token';
import { setRecipientsForDocument } from '@documenso/lib/server-only/recipient/set-recipients-for-document'; import { setRecipientsForDocument } from '@documenso/lib/server-only/recipient/set-recipients-for-document';
@@ -14,7 +16,16 @@ import {
export const recipientRouter = router({ export const recipientRouter = router({
addSigners: authenticatedProcedure addSigners: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/document/{documentId}/recipient/set',
summary: 'Set document recipients',
tags: ['Recipients'],
},
})
.input(ZAddSignersMutationSchema) .input(ZAddSignersMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { documentId, teamId, signers } = input; const { documentId, teamId, signers } = input;
@@ -35,7 +46,16 @@ export const recipientRouter = router({
}), }),
addTemplateSigners: authenticatedProcedure addTemplateSigners: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/template/{templateId}/recipient/set',
summary: 'Set template recipients',
tags: ['Recipients'],
},
})
.input(ZAddTemplateSignersMutationSchema) .input(ZAddTemplateSignersMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { templateId, signers, teamId } = input; const { templateId, signers, teamId } = input;
@@ -54,6 +74,7 @@ export const recipientRouter = router({
}); });
}), }),
// Internal endpoint for now.
completeDocumentWithToken: procedure completeDocumentWithToken: procedure
.input(ZCompleteDocumentWithTokenMutationSchema) .input(ZCompleteDocumentWithTokenMutationSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
@@ -68,6 +89,7 @@ export const recipientRouter = router({
}); });
}), }),
// Internal endpoint for now.
rejectDocumentWithToken: procedure rejectDocumentWithToken: procedure
.input(ZRejectDocumentWithTokenMutationSchema) .input(ZRejectDocumentWithTokenMutationSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {

View File

@@ -4,7 +4,7 @@ import { z } from 'zod';
import { getTeamPrices } from '@documenso/ee/server-only/stripe/get-team-prices'; import { getTeamPrices } from '@documenso/ee/server-only/stripe/get-team-prices';
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import { acceptTeamInvitation } from '@documenso/lib/server-only/team/accept-team-invitation'; import { acceptTeamInvitation } from '@documenso/lib/server-only/team/accept-team-invitation';
import { ZCreateTeamResponseSchema, createTeam } from '@documenso/lib/server-only/team/create-team'; import { createTeam } from '@documenso/lib/server-only/team/create-team';
import { createTeamBillingPortal } from '@documenso/lib/server-only/team/create-team-billing-portal'; import { createTeamBillingPortal } from '@documenso/lib/server-only/team/create-team-billing-portal';
import { createTeamPendingCheckoutSession } from '@documenso/lib/server-only/team/create-team-checkout-session'; import { createTeamPendingCheckoutSession } from '@documenso/lib/server-only/team/create-team-checkout-session';
import { createTeamEmailVerification } from '@documenso/lib/server-only/team/create-team-email-verification'; import { createTeamEmailVerification } from '@documenso/lib/server-only/team/create-team-email-verification';
@@ -18,43 +18,22 @@ import { deleteTeamMembers } from '@documenso/lib/server-only/team/delete-team-m
import { deleteTeamPending } from '@documenso/lib/server-only/team/delete-team-pending'; import { deleteTeamPending } from '@documenso/lib/server-only/team/delete-team-pending';
import { deleteTeamTransferRequest } from '@documenso/lib/server-only/team/delete-team-transfer-request'; import { deleteTeamTransferRequest } from '@documenso/lib/server-only/team/delete-team-transfer-request';
import { findTeamInvoices } from '@documenso/lib/server-only/team/find-team-invoices'; import { findTeamInvoices } from '@documenso/lib/server-only/team/find-team-invoices';
import { import { findTeamMemberInvites } from '@documenso/lib/server-only/team/find-team-member-invites';
ZFindTeamMemberInvitesResponseSchema, import { findTeamMembers } from '@documenso/lib/server-only/team/find-team-members';
findTeamMemberInvites,
} from '@documenso/lib/server-only/team/find-team-member-invites';
import {
ZFindTeamMembersResponseSchema,
findTeamMembers,
} from '@documenso/lib/server-only/team/find-team-members';
import { findTeams } from '@documenso/lib/server-only/team/find-teams'; import { findTeams } from '@documenso/lib/server-only/team/find-teams';
import { import { findTeamsPending } from '@documenso/lib/server-only/team/find-teams-pending';
ZFindTeamsPendingResponseSchema, import { getTeamById } from '@documenso/lib/server-only/team/get-team';
findTeamsPending,
} from '@documenso/lib/server-only/team/find-teams-pending';
import { ZGetTeamByIdResponseSchema, getTeamById } from '@documenso/lib/server-only/team/get-team';
import { getTeamEmailByEmail } from '@documenso/lib/server-only/team/get-team-email-by-email'; import { getTeamEmailByEmail } from '@documenso/lib/server-only/team/get-team-email-by-email';
import { import { getTeamInvitations } from '@documenso/lib/server-only/team/get-team-invitations';
ZGetTeamInvitationsResponseSchema, import { getTeamMembers } from '@documenso/lib/server-only/team/get-team-members';
getTeamInvitations, import { getTeams } from '@documenso/lib/server-only/team/get-teams';
} from '@documenso/lib/server-only/team/get-team-invitations';
import {
ZGetTeamMembersResponseSchema,
getTeamMembers,
} from '@documenso/lib/server-only/team/get-team-members';
import { ZGetTeamsResponseSchema, getTeams } from '@documenso/lib/server-only/team/get-teams';
import { leaveTeam } from '@documenso/lib/server-only/team/leave-team'; import { leaveTeam } from '@documenso/lib/server-only/team/leave-team';
import { requestTeamOwnershipTransfer } from '@documenso/lib/server-only/team/request-team-ownership-transfer'; import { requestTeamOwnershipTransfer } from '@documenso/lib/server-only/team/request-team-ownership-transfer';
import { resendTeamEmailVerification } from '@documenso/lib/server-only/team/resend-team-email-verification'; import { resendTeamEmailVerification } from '@documenso/lib/server-only/team/resend-team-email-verification';
import { resendTeamMemberInvitation } from '@documenso/lib/server-only/team/resend-team-member-invitation'; import { resendTeamMemberInvitation } from '@documenso/lib/server-only/team/resend-team-member-invitation';
import { updateTeam } from '@documenso/lib/server-only/team/update-team'; import { updateTeam } from '@documenso/lib/server-only/team/update-team';
import { import { updateTeamBrandingSettings } from '@documenso/lib/server-only/team/update-team-branding-settings';
ZUpdateTeamBrandingSettingsResponseSchema, import { updateTeamDocumentSettings } from '@documenso/lib/server-only/team/update-team-document-settings';
updateTeamBrandingSettings,
} from '@documenso/lib/server-only/team/update-team-branding-settings';
import {
ZUpdateTeamDocumentSettingsResponseSchema,
updateTeamDocumentSettings,
} from '@documenso/lib/server-only/team/update-team-document-settings';
import { updateTeamEmail } from '@documenso/lib/server-only/team/update-team-email'; import { updateTeamEmail } from '@documenso/lib/server-only/team/update-team-email';
import { updateTeamMember } from '@documenso/lib/server-only/team/update-team-member'; import { updateTeamMember } from '@documenso/lib/server-only/team/update-team-member';
import { updateTeamPublicProfile } from '@documenso/lib/server-only/team/update-team-public-profile'; import { updateTeamPublicProfile } from '@documenso/lib/server-only/team/update-team-public-profile';
@@ -95,6 +74,516 @@ import {
} from './schema'; } from './schema';
export const teamRouter = router({ export const teamRouter = router({
getTeams: authenticatedProcedure
.meta({
openapi: {
method: 'GET',
path: '/team',
summary: 'Get teams',
description: 'Returns all teams that you are a member of',
tags: ['Teams'],
},
})
.input(z.void())
.output(z.unknown())
.query(async ({ ctx }) => {
return await getTeams({ userId: ctx.user.id });
}),
getTeam: authenticatedProcedure
.meta({
openapi: {
method: 'GET',
path: '/team/{teamId}',
summary: 'Get team',
tags: ['Teams'],
},
})
.input(ZGetTeamQuerySchema)
.output(z.unknown())
.query(async ({ input, ctx }) => {
return await getTeamById({ teamId: input.teamId, userId: ctx.user.id });
}),
createTeam: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/team/create',
summary: 'Create team',
tags: ['Teams'],
},
})
.input(ZCreateTeamMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => {
return await createTeam({
userId: ctx.user.id,
...input,
});
}),
updateTeam: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/team/{teamId}',
summary: 'Update team',
tags: ['Teams'],
},
})
.input(ZUpdateTeamMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => {
return await updateTeam({
userId: ctx.user.id,
...input,
});
}),
deleteTeam: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/team/{teamId}/delete',
summary: 'Delete team',
tags: ['Teams'],
},
})
.input(ZDeleteTeamMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => {
return await deleteTeam({
userId: ctx.user.id,
...input,
});
}),
leaveTeam: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/team/{teamId}/leave',
summary: 'Leave a team',
description: '',
tags: ['Teams'],
},
})
.input(ZLeaveTeamMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => {
return await leaveTeam({
userId: ctx.user.id,
...input,
});
}),
findTeamMemberInvites: authenticatedProcedure
.meta({
openapi: {
method: 'GET',
path: '/team/{teamId}/member/invite',
summary: 'Find member invites',
description: 'Returns pending team member invites',
tags: ['Teams'],
},
})
.input(ZFindTeamMemberInvitesQuerySchema)
.output(z.unknown())
.query(async ({ input, ctx }) => {
return await findTeamMemberInvites({
userId: ctx.user.id,
...input,
});
}),
createTeamMemberInvites: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/team/{teamId}/member/invite',
summary: 'Invite members',
description: 'Send email invitations to users to join the team',
tags: ['Teams'],
},
})
.input(ZCreateTeamMemberInvitesMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => {
return await createTeamMemberInvites({
userId: ctx.user.id,
userName: ctx.user.name ?? '',
...input,
});
}),
resendTeamMemberInvitation: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/team/{teamId}/member/invite/{invitationId}/resend',
summary: 'Resend member invite',
description: 'Resend an email invitation to a user to join the team',
tags: ['Teams'],
},
})
.input(ZResendTeamMemberInvitationMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => {
await resendTeamMemberInvitation({
userId: ctx.user.id,
userName: ctx.user.name ?? '',
...input,
});
}),
deleteTeamMemberInvitations: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/team/{teamId}/member/invite/delete',
summary: 'Delete member invite',
description: 'Delete a pending team member invite',
tags: ['Teams'],
},
})
.input(ZDeleteTeamMemberInvitationsMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => {
return await deleteTeamMemberInvitations({
userId: ctx.user.id,
...input,
});
}),
getTeamMembers: authenticatedProcedure
.meta({
openapi: {
method: 'GET',
path: '/team/{teamId}/member',
summary: 'Get members',
tags: ['Teams'],
},
})
.input(ZGetTeamMembersQuerySchema)
.output(z.unknown())
.query(async ({ input, ctx }) => {
return await getTeamMembers({ teamId: input.teamId, userId: ctx.user.id });
}),
findTeamMembers: authenticatedProcedure
.meta({
openapi: {
method: 'GET',
path: '/team/{teamId}/member/find',
summary: 'Find members',
description: 'Find team members based on a search criteria',
tags: ['Teams'],
},
})
.input(ZFindTeamMembersQuerySchema)
.output(z.unknown())
.query(async ({ input, ctx }) => {
return await findTeamMembers({
userId: ctx.user.id,
...input,
});
}),
updateTeamMember: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/team/{teamId}/member/{teamMemberId}',
summary: 'Update member',
tags: ['Teams'],
},
})
.input(ZUpdateTeamMemberMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => {
return await updateTeamMember({
userId: ctx.user.id,
...input,
});
}),
deleteTeamMembers: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/team/{teamId}/member/delete',
summary: 'Delete members',
description: '',
tags: ['Teams'],
},
})
.input(ZDeleteTeamMembersMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => {
return await deleteTeamMembers({
userId: ctx.user.id,
...input,
});
}),
// Todo: Refactor, seems to be a redundant endpoint.
findTeams: authenticatedProcedure.input(ZFindTeamsQuerySchema).query(async ({ input, ctx }) => {
return await findTeams({
userId: ctx.user.id,
...input,
});
}),
// Internal endpoint for now.
createTeamEmailVerification: authenticatedProcedure
// .meta({
// openapi: {
// method: 'POST',
// path: '/team/{teamId}/email/create',
// summary: 'Create team email',
// description: 'Add an email to a team and send an email request to verify it',
// tags: ['Teams'],
// },
// })
.input(ZCreateTeamEmailVerificationMutationSchema)
.mutation(async ({ input, ctx }) => {
return await createTeamEmailVerification({
teamId: input.teamId,
userId: ctx.user.id,
data: {
email: input.email,
name: input.name,
},
});
}),
// Internal endpoint for now.
getTeamInvitations: authenticatedProcedure
// .meta({
// openapi: {
// method: 'GET',
// path: '/team/invite',
// summary: 'Get team invitations',
// description: '',
// tags: ['Teams'],
// },
// })
.input(z.void())
.query(async ({ ctx }) => {
return await getTeamInvitations({ email: ctx.user.email });
}),
updateTeamPublicProfile: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/team/{teamId}/profile',
summary: 'Update a team public profile',
description: '',
tags: ['Teams'],
},
})
.input(ZUpdateTeamPublicProfileMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => {
try {
const { teamId, bio, enabled } = input;
await updateTeamPublicProfile({
userId: ctx.user.id,
teamId,
data: {
bio,
enabled,
},
});
} catch (err) {
console.error(err);
const error = AppError.parseError(err);
if (error.code !== AppErrorCode.UNKNOWN_ERROR) {
throw error;
}
throw new TRPCError({
code: 'BAD_REQUEST',
message:
'We were unable to update your public profile. Please review the information you provided and try again.',
});
}
}),
// Internal endpoint for now.
requestTeamOwnershipTransfer: authenticatedProcedure
// .meta({
// openapi: {
// method: 'POST',
// path: '/team/{teamId}/transfer',
// summary: 'Request a team ownership transfer',
// description: '',
// tags: ['Teams'],
// },
// })
.input(ZRequestTeamOwnerhsipTransferMutationSchema)
.mutation(async ({ input, ctx }) => {
return await requestTeamOwnershipTransfer({
userId: ctx.user.id,
userName: ctx.user.name ?? '',
...input,
});
}),
// Internal endpoint for now.
deleteTeamTransferRequest: authenticatedProcedure
// .meta({
// openapi: {
// method: 'POST',
// path: '/team/{teamId}/transfer/delete',
// summary: 'Delete team transfer request',
// tags: ['Teams'],
// },
// })
.input(ZDeleteTeamTransferRequestMutationSchema)
.mutation(async ({ input, ctx }) => {
return await deleteTeamTransferRequest({
userId: ctx.user.id,
...input,
});
}),
// Todo
getTeamEmailByEmail: authenticatedProcedure.query(async ({ ctx }) => {
return await getTeamEmailByEmail({ email: ctx.user.email });
}),
// Internal endpoint for now.
updateTeamEmail: authenticatedProcedure
// .meta({
// openapi: {
// method: 'POST',
// path: '/team/{teamId}/email',
// summary: 'Update a team email',
// description: '',
// tags: ['Teams'],
// },
// })
.input(ZUpdateTeamEmailMutationSchema)
.mutation(async ({ input, ctx }) => {
return await updateTeamEmail({
userId: ctx.user.id,
...input,
});
}),
// Internal endpoint for now.
deleteTeamEmail: authenticatedProcedure
// .meta({
// openapi: {
// method: 'POST',
// path: '/team/{teamId}/email/delete',
// summary: 'Delete team email',
// description: '',
// tags: ['Teams'],
// },
// })
.input(ZDeleteTeamEmailMutationSchema)
.mutation(async ({ input, ctx }) => {
return await deleteTeamEmail({
userId: ctx.user.id,
userEmail: ctx.user.email,
...input,
});
}),
// Internal endpoint for now.
resendTeamEmailVerification: authenticatedProcedure
// .meta({
// openapi: {
// method: 'POST',
// path: '/team/{teamId}/email/resend',
// summary: 'Resend team email verification',
// tags: ['Teams'],
// },
// })
.input(ZResendTeamEmailVerificationMutationSchema)
.mutation(async ({ input, ctx }) => {
await resendTeamEmailVerification({
userId: ctx.user.id,
...input,
});
}),
// Internal endpoint for now.
deleteTeamEmailVerification: authenticatedProcedure
// .meta({
// openapi: {
// method: 'POST',
// path: '/team/{teamId}/email/verify/delete',
// summary: 'Delete team email verification',
// tags: ['Teams'],
// },
// })
.input(ZDeleteTeamEmailVerificationMutationSchema)
.mutation(async ({ input, ctx }) => {
return await deleteTeamEmailVerification({
userId: ctx.user.id,
...input,
});
}),
// Internal endpoint. Use updateTeam instead.
updateTeamBrandingSettings: authenticatedProcedure
.input(ZUpdateTeamBrandingSettingsMutationSchema)
.mutation(async ({ ctx, input }) => {
const { teamId, settings } = input;
return await updateTeamBrandingSettings({
userId: ctx.user.id,
teamId,
settings,
});
}),
// Internal endpoint for now.
createTeamPendingCheckout: authenticatedProcedure
.input(ZCreateTeamPendingCheckoutMutationSchema)
.mutation(async ({ input, ctx }) => {
return await createTeamPendingCheckoutSession({
userId: ctx.user.id,
...input,
});
}),
// Internal endpoint for now.
findTeamInvoices: authenticatedProcedure
.input(ZFindTeamInvoicesQuerySchema)
.query(async ({ input, ctx }) => {
return await findTeamInvoices({
userId: ctx.user.id,
...input,
});
}),
// Internal endpoint for now.
getTeamPrices: authenticatedProcedure.query(async () => {
return await getTeamPrices();
}),
// Internal endpoint. Use updateTeam instead.
updateTeamDocumentSettings: authenticatedProcedure
.input(ZUpdateTeamDocumentSettingsMutationSchema)
.mutation(async ({ ctx, input }) => {
const { teamId, settings } = input;
return await updateTeamDocumentSettings({
userId: ctx.user.id,
teamId,
settings,
});
}),
// Internal endpoint for now. // Internal endpoint for now.
acceptTeamInvitation: authenticatedProcedure acceptTeamInvitation: authenticatedProcedure
.input(ZAcceptTeamInvitationMutationSchema) .input(ZAcceptTeamInvitationMutationSchema)
@@ -125,169 +614,18 @@ export const teamRouter = router({
}); });
}), }),
createTeam: authenticatedProcedure
.meta({ openapi: { method: 'POST', path: '/team' } })
.input(ZCreateTeamMutationSchema)
.output(ZCreateTeamResponseSchema)
.mutation(async ({ input, ctx }) => {
return await createTeam({
userId: ctx.user.id,
...input,
});
}),
createTeamEmailVerification: authenticatedProcedure
.meta({ openapi: { method: 'POST', path: '/team/{teamId}/email' } })
.input(ZCreateTeamEmailVerificationMutationSchema)
.output(z.void())
.mutation(async ({ input, ctx }) => {
return await createTeamEmailVerification({
teamId: input.teamId,
userId: ctx.user.id,
data: {
email: input.email,
name: input.name,
},
});
}),
createTeamMemberInvites: authenticatedProcedure
.meta({ openapi: { method: 'POST', path: '/team/{teamId}/member/invite' } })
.input(ZCreateTeamMemberInvitesMutationSchema)
.output(z.void())
.mutation(async ({ input, ctx }) => {
return await createTeamMemberInvites({
userId: ctx.user.id,
userName: ctx.user.name ?? '',
...input,
});
}),
// Internal endpoint for now. // Internal endpoint for now.
createTeamPendingCheckout: authenticatedProcedure
.input(ZCreateTeamPendingCheckoutMutationSchema)
.mutation(async ({ input, ctx }) => {
return await createTeamPendingCheckoutSession({
userId: ctx.user.id,
...input,
});
}),
deleteTeam: authenticatedProcedure
// .meta({ openapi: { method: 'DELETE', path: '/team/{teamId}' } })
.input(ZDeleteTeamMutationSchema)
.mutation(async ({ input, ctx }) => {
return await deleteTeam({
userId: ctx.user.id,
...input,
});
}),
deleteTeamEmail: authenticatedProcedure
// .meta({ openapi: { method: 'DELETE', path: '/team/{teamId}/email' } })
.input(ZDeleteTeamEmailMutationSchema)
.mutation(async ({ input, ctx }) => {
return await deleteTeamEmail({
userId: ctx.user.id,
userEmail: ctx.user.email,
...input,
});
}),
deleteTeamEmailVerification: authenticatedProcedure
// .meta({ openapi: { method: 'DELETE', path: '/team/{teamId}/email-verification' } })
.input(ZDeleteTeamEmailVerificationMutationSchema)
.mutation(async ({ input, ctx }) => {
return await deleteTeamEmailVerification({
userId: ctx.user.id,
...input,
});
}),
deleteTeamMemberInvitations: authenticatedProcedure
// .meta({ openapi: { method: 'DELETE', path: '/team/{teamId}/member/invite' } })
.input(ZDeleteTeamMemberInvitationsMutationSchema)
.mutation(async ({ input, ctx }) => {
return await deleteTeamMemberInvitations({
userId: ctx.user.id,
...input,
});
}),
deleteTeamMembers: authenticatedProcedure
// .meta({ openapi: { method: 'DELETE', path: '/team/{teamId}/member' } })
.input(ZDeleteTeamMembersMutationSchema)
.mutation(async ({ input, ctx }) => {
return await deleteTeamMembers({
userId: ctx.user.id,
...input,
});
}),
deleteTeamPending: authenticatedProcedure
// .meta({ openapi: { method: 'DELETE', path: '/team-pending/{pendingTeamId}' } })
.input(ZDeleteTeamPendingMutationSchema)
.mutation(async ({ input, ctx }) => {
return await deleteTeamPending({
userId: ctx.user.id,
...input,
});
}),
deleteTeamTransferRequest: authenticatedProcedure
// .meta({ openapi: { method: 'DELETE', path: '/team/{teamId}/transfer' } })
.input(ZDeleteTeamTransferRequestMutationSchema)
.mutation(async ({ input, ctx }) => {
return await deleteTeamTransferRequest({
userId: ctx.user.id,
...input,
});
}),
// Internal endpoint for now.
findTeamInvoices: authenticatedProcedure
.input(ZFindTeamInvoicesQuerySchema)
.query(async ({ input, ctx }) => {
return await findTeamInvoices({
userId: ctx.user.id,
...input,
});
}),
findTeamMemberInvites: authenticatedProcedure
.meta({ openapi: { method: 'GET', path: '/team/{teamId}/member/invite' } })
.input(ZFindTeamMemberInvitesQuerySchema)
.output(ZFindTeamMemberInvitesResponseSchema)
.query(async ({ input, ctx }) => {
return await findTeamMemberInvites({
userId: ctx.user.id,
...input,
});
}),
findTeamMembers: authenticatedProcedure
.meta({ openapi: { method: 'GET', path: '/team/{teamId}/member' } })
.input(ZFindTeamMembersQuerySchema)
.output(ZFindTeamMembersResponseSchema)
.query(async ({ input, ctx }) => {
return await findTeamMembers({
userId: ctx.user.id,
...input,
});
}),
// Todo: Refactor, seems to be a redundant endpoint.
findTeams: authenticatedProcedure.input(ZFindTeamsQuerySchema).query(async ({ input, ctx }) => {
return await findTeams({
userId: ctx.user.id,
...input,
});
}),
findTeamsPending: authenticatedProcedure findTeamsPending: authenticatedProcedure
.meta({ openapi: { method: 'GET', path: '/team-pending' } }) // .meta({
// openapi: {
// method: 'GET',
// path: '/team/pending',
// summary: 'Find pending teams',
// description: 'Find teams that are pending payment',
// tags: ['Teams'],
// },
// })
.input(ZFindTeamsPendingQuerySchema) .input(ZFindTeamsPendingQuerySchema)
.output(ZFindTeamsPendingResponseSchema)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
return await findTeamsPending({ return await findTeamsPending({
userId: ctx.user.id, userId: ctx.user.id,
@@ -295,187 +633,22 @@ export const teamRouter = router({
}); });
}), }),
getTeam: authenticatedProcedure
.meta({ openapi: { method: 'GET', path: '/team/{teamId}' } })
.input(ZGetTeamQuerySchema)
.output(ZGetTeamByIdResponseSchema)
.query(async ({ input, ctx }) => {
return await getTeamById({ teamId: input.teamId, userId: ctx.user.id });
}),
// Todo
getTeamEmailByEmail: authenticatedProcedure.query(async ({ ctx }) => {
return await getTeamEmailByEmail({ email: ctx.user.email });
}),
getTeamInvitations: authenticatedProcedure
.meta({ openapi: { method: 'GET', path: '/team/invite' } })
.input(z.void())
.output(ZGetTeamInvitationsResponseSchema)
.query(async ({ ctx }) => {
return await getTeamInvitations({ email: ctx.user.email });
}),
getTeamMembers: authenticatedProcedure
.meta({ openapi: { method: 'GET', path: '/team/member' } })
.input(ZGetTeamMembersQuerySchema)
.output(ZGetTeamMembersResponseSchema)
.query(async ({ input, ctx }) => {
return await getTeamMembers({ teamId: input.teamId, userId: ctx.user.id });
}),
// Internal endpoint for now. // Internal endpoint for now.
getTeamPrices: authenticatedProcedure.query(async () => { deleteTeamPending: authenticatedProcedure
return await getTeamPrices(); // .meta({
}), // openapi: {
// method: 'POST',
getTeams: authenticatedProcedure // path: '/team/pending/{pendingTeamId}/delete',
.meta({ openapi: { method: 'GET', path: '/team' } }) // summary: 'Delete pending team',
.input(z.void()) // description: '',
.output(ZGetTeamsResponseSchema) // tags: ['Teams'],
.query(async ({ ctx }) => { // },
return await getTeams({ userId: ctx.user.id }); // })
}), .input(ZDeleteTeamPendingMutationSchema)
leaveTeam: authenticatedProcedure
.meta({ openapi: { method: 'POST', path: '/team/{teamId}/leave' } })
.input(ZLeaveTeamMutationSchema)
.output(z.void())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
return await leaveTeam({ return await deleteTeamPending({
userId: ctx.user.id, userId: ctx.user.id,
...input, ...input,
}); });
}), }),
updateTeam: authenticatedProcedure
.meta({ openapi: { method: 'PATCH', path: '/team/{teamId}' } })
.input(ZUpdateTeamMutationSchema)
.output(z.void())
.mutation(async ({ input, ctx }) => {
return await updateTeam({
userId: ctx.user.id,
...input,
});
}),
updateTeamEmail: authenticatedProcedure
.meta({ openapi: { method: 'PATCH', path: '/team/{teamId}/email' } })
.input(ZUpdateTeamEmailMutationSchema)
.output(z.void())
.mutation(async ({ input, ctx }) => {
return await updateTeamEmail({
userId: ctx.user.id,
...input,
});
}),
updateTeamMember: authenticatedProcedure
.meta({ openapi: { method: 'PATCH', path: '/team/{teamId}/member' } })
.input(ZUpdateTeamMemberMutationSchema)
.output(z.void())
.mutation(async ({ input, ctx }) => {
return await updateTeamMember({
userId: ctx.user.id,
...input,
});
}),
updateTeamPublicProfile: authenticatedProcedure
.meta({ openapi: { method: 'PATCH', path: '/team/{teamId}/profile' } })
.input(ZUpdateTeamPublicProfileMutationSchema)
.output(z.void())
.mutation(async ({ input, ctx }) => {
try {
const { teamId, bio, enabled } = input;
await updateTeamPublicProfile({
userId: ctx.user.id,
teamId,
data: {
bio,
enabled,
},
});
} catch (err) {
console.error(err);
const error = AppError.parseError(err);
if (error.code !== AppErrorCode.UNKNOWN_ERROR) {
throw error;
}
throw new TRPCError({
code: 'BAD_REQUEST',
message:
'We were unable to update your public profile. Please review the information you provided and try again.',
});
}
}),
requestTeamOwnershipTransfer: authenticatedProcedure
.meta({ openapi: { method: 'POST', path: '/team/{teamId}/transfer' } })
.input(ZRequestTeamOwnerhsipTransferMutationSchema)
.output(z.void())
.mutation(async ({ input, ctx }) => {
return await requestTeamOwnershipTransfer({
userId: ctx.user.id,
userName: ctx.user.name ?? '',
...input,
});
}),
resendTeamEmailVerification: authenticatedProcedure
.meta({ openapi: { method: 'POST', path: '/team/{teamId}/email/resend' } })
.input(ZResendTeamEmailVerificationMutationSchema)
.output(z.void())
.mutation(async ({ input, ctx }) => {
await resendTeamEmailVerification({
userId: ctx.user.id,
...input,
});
}),
resendTeamMemberInvitation: authenticatedProcedure
.meta({
openapi: { method: 'POST', path: '/team/{teamId}/member/invite/{invitationId}/resend' },
})
.input(ZResendTeamMemberInvitationMutationSchema)
.output(z.void())
.mutation(async ({ input, ctx }) => {
await resendTeamMemberInvitation({
userId: ctx.user.id,
userName: ctx.user.name ?? '',
...input,
});
}),
updateTeamBrandingSettings: authenticatedProcedure
.meta({ openapi: { method: 'PATCH', path: '/team/{teamId}/branding' } })
.input(ZUpdateTeamBrandingSettingsMutationSchema)
.output(ZUpdateTeamBrandingSettingsResponseSchema)
.mutation(async ({ ctx, input }) => {
const { teamId, settings } = input;
return await updateTeamBrandingSettings({
userId: ctx.user.id,
teamId,
settings,
});
}),
updateTeamDocumentSettings: authenticatedProcedure
.meta({ openapi: { method: 'PATCH', path: '/team/{teamId}/settings' } })
.input(ZUpdateTeamDocumentSettingsMutationSchema)
.output(ZUpdateTeamDocumentSettingsResponseSchema)
.mutation(async ({ ctx, input }) => {
const { teamId, settings } = input;
return await updateTeamDocumentSettings({
userId: ctx.user.id,
teamId,
settings,
});
}),
}); });

View File

@@ -1,4 +1,5 @@
import { TRPCError } from '@trpc/server'; import { TRPCError } from '@trpc/server';
import { z } from 'zod';
import { getServerLimits } from '@documenso/ee/server-only/limits/server'; import { getServerLimits } from '@documenso/ee/server-only/limits/server';
import { isValidLanguageCode } from '@documenso/lib/constants/i18n'; import { isValidLanguageCode } from '@documenso/lib/constants/i18n';
@@ -13,7 +14,6 @@ import { deleteTemplateDirectLink } from '@documenso/lib/server-only/template/de
import { duplicateTemplate } from '@documenso/lib/server-only/template/duplicate-template'; import { duplicateTemplate } from '@documenso/lib/server-only/template/duplicate-template';
import { findTemplates } from '@documenso/lib/server-only/template/find-templates'; import { findTemplates } from '@documenso/lib/server-only/template/find-templates';
import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id'; import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id';
import { getTemplateWithDetailsById } from '@documenso/lib/server-only/template/get-template-with-details-by-id';
import { moveTemplateToTeam } from '@documenso/lib/server-only/template/move-template-to-team'; import { moveTemplateToTeam } from '@documenso/lib/server-only/template/move-template-to-team';
import { toggleTemplateDirectLink } from '@documenso/lib/server-only/template/toggle-template-direct-link'; import { toggleTemplateDirectLink } from '@documenso/lib/server-only/template/toggle-template-direct-link';
import { updateTemplateSettings } from '@documenso/lib/server-only/template/update-template-settings'; import { updateTemplateSettings } from '@documenso/lib/server-only/template/update-template-settings';
@@ -30,7 +30,7 @@ import {
ZDeleteTemplateMutationSchema, ZDeleteTemplateMutationSchema,
ZDuplicateTemplateMutationSchema, ZDuplicateTemplateMutationSchema,
ZFindTemplatesQuerySchema, ZFindTemplatesQuerySchema,
ZGetTemplateWithDetailsByIdQuerySchema, ZGetTemplateByIdQuerySchema,
ZMoveTemplatesToTeamSchema, ZMoveTemplatesToTeamSchema,
ZSetSigningOrderForTemplateMutationSchema, ZSetSigningOrderForTemplateMutationSchema,
ZToggleTemplateDirectLinkMutationSchema, ZToggleTemplateDirectLinkMutationSchema,
@@ -39,8 +39,58 @@ import {
} from './schema'; } from './schema';
export const templateRouter = router({ export const templateRouter = router({
findTemplates: authenticatedProcedure
.meta({
openapi: {
method: 'GET',
path: '/template/find',
summary: 'Find templates',
description: 'Find templates based on a search criteria',
tags: ['Template'],
},
})
.input(ZFindTemplatesQuerySchema)
.output(z.unknown())
.query(async ({ input, ctx }) => {
return await findTemplates({
userId: ctx.user.id,
...input,
});
}),
getTemplateById: authenticatedProcedure
.meta({
openapi: {
method: 'GET',
path: '/template/{templateId}',
summary: 'Get template',
tags: ['Template'],
},
})
.input(ZGetTemplateByIdQuerySchema)
.output(z.unknown())
.query(async ({ input, ctx }) => {
const { templateId, teamId } = input;
return await getTemplateById({
id: templateId,
userId: ctx.user.id,
teamId,
});
}),
createTemplate: authenticatedProcedure createTemplate: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/template/create',
summary: 'Create template',
description: 'Create a new template',
tags: ['Template'],
},
})
.input(ZCreateTemplateMutationSchema) .input(ZCreateTemplateMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { teamId, title, templateDocumentDataId } = input; const { teamId, title, templateDocumentDataId } = input;
@@ -52,40 +102,89 @@ export const templateRouter = router({
}); });
}), }),
createDocumentFromDirectTemplate: maybeAuthenticatedProcedure updateTemplate: authenticatedProcedure
.input(ZCreateDocumentFromDirectTemplateMutationSchema) .meta({
openapi: {
method: 'POST',
path: '/template/{templateId}',
summary: 'Update template',
tags: ['Template'],
},
})
.input(ZUpdateTemplateSettingsMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { const { templateId, teamId, data, meta } = input;
directRecipientName,
directRecipientEmail, const userId = ctx.user.id;
directTemplateToken,
directTemplateExternalId,
signedFieldValues,
templateUpdatedAt,
} = input;
const requestMetadata = extractNextApiRequestMetadata(ctx.req); const requestMetadata = extractNextApiRequestMetadata(ctx.req);
return await createDocumentFromDirectTemplate({ return await updateTemplateSettings({
directRecipientName, userId,
directRecipientEmail, teamId,
directTemplateToken, templateId,
directTemplateExternalId, data,
signedFieldValues, meta: {
templateUpdatedAt, ...meta,
user: ctx.user language: isValidLanguageCode(meta?.language) ? meta?.language : undefined,
? { },
id: ctx.user.id,
name: ctx.user.name || undefined,
email: ctx.user.email,
}
: undefined,
requestMetadata, requestMetadata,
}); });
}), }),
duplicateTemplate: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/template/{templateId}/duplicate',
summary: 'Duplicate template',
tags: ['Template'],
},
})
.input(ZDuplicateTemplateMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => {
const { teamId, templateId } = input;
return await duplicateTemplate({
userId: ctx.user.id,
teamId,
templateId,
});
}),
deleteTemplate: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/template/{templateId}/delete',
summary: 'Delete template',
tags: ['Template'],
},
})
.input(ZDeleteTemplateMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => {
const { templateId, teamId } = input;
const userId = ctx.user.id;
await deleteTemplate({ userId, id: templateId, teamId });
}),
createDocumentFromTemplate: authenticatedProcedure createDocumentFromTemplate: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/template/{templateId}/use',
summary: 'Use template',
description: 'Use the template to create a document',
tags: ['Template'],
},
})
.input(ZCreateDocumentFromTemplateMutationSchema) .input(ZCreateDocumentFromTemplateMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { templateId, teamId, recipients } = input; const { templateId, teamId, recipients } = input;
@@ -121,60 +220,49 @@ export const templateRouter = router({
return document; return document;
}), }),
duplicateTemplate: authenticatedProcedure createDocumentFromDirectTemplate: maybeAuthenticatedProcedure
.input(ZDuplicateTemplateMutationSchema) .meta({
openapi: {
method: 'POST',
path: '/template/use',
summary: 'Use direct template',
description: 'Use a direct template to create a document',
tags: ['Template'],
},
})
.input(ZCreateDocumentFromDirectTemplateMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { teamId, templateId } = input; const {
directRecipientName,
return await duplicateTemplate({ directRecipientEmail,
userId: ctx.user.id, directTemplateToken,
teamId, directTemplateExternalId,
templateId, signedFieldValues,
}); templateUpdatedAt,
}), } = input;
deleteTemplate: authenticatedProcedure
.input(ZDeleteTemplateMutationSchema)
.mutation(async ({ input, ctx }) => {
const { id, teamId } = input;
const userId = ctx.user.id;
return await deleteTemplate({ userId, id, teamId });
}),
getTemplateWithDetailsById: authenticatedProcedure
.input(ZGetTemplateWithDetailsByIdQuerySchema)
.query(async ({ input, ctx }) => {
return await getTemplateWithDetailsById({
id: input.id,
userId: ctx.user.id,
});
}),
// Todo: Add API
updateTemplateSettings: authenticatedProcedure
.input(ZUpdateTemplateSettingsMutationSchema)
.mutation(async ({ input, ctx }) => {
const { templateId, teamId, data, meta } = input;
const userId = ctx.user.id;
const requestMetadata = extractNextApiRequestMetadata(ctx.req); const requestMetadata = extractNextApiRequestMetadata(ctx.req);
return await updateTemplateSettings({ return await createDocumentFromDirectTemplate({
userId, directRecipientName,
teamId, directRecipientEmail,
templateId, directTemplateToken,
data, directTemplateExternalId,
meta: { signedFieldValues,
...meta, templateUpdatedAt,
language: isValidLanguageCode(meta?.language) ? meta?.language : undefined, user: ctx.user
}, ? {
id: ctx.user.id,
name: ctx.user.name || undefined,
email: ctx.user.email,
}
: undefined,
requestMetadata, requestMetadata,
}); });
}), }),
// Internal endpoint for now.
setSigningOrderForTemplate: authenticatedProcedure setSigningOrderForTemplate: authenticatedProcedure
.input(ZSetSigningOrderForTemplateMutationSchema) .input(ZSetSigningOrderForTemplateMutationSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
@@ -190,17 +278,18 @@ export const templateRouter = router({
}); });
}), }),
findTemplates: authenticatedProcedure
.input(ZFindTemplatesQuerySchema)
.query(async ({ input, ctx }) => {
return await findTemplates({
userId: ctx.user.id,
...input,
});
}),
createTemplateDirectLink: authenticatedProcedure createTemplateDirectLink: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/template/{templateId}/direct/create',
summary: 'Create direct link',
description: 'Create a direct link for a template',
tags: ['Template'],
},
})
.input(ZCreateTemplateDirectLinkMutationSchema) .input(ZCreateTemplateDirectLinkMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { templateId, teamId, directRecipientId } = input; const { templateId, teamId, directRecipientId } = input;
@@ -220,17 +309,37 @@ export const templateRouter = router({
}), }),
deleteTemplateDirectLink: authenticatedProcedure deleteTemplateDirectLink: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/template/{templateId}/direct/delete',
summary: 'Delete direct link',
description: 'Delete a direct link for a template',
tags: ['Template'],
},
})
.input(ZDeleteTemplateDirectLinkMutationSchema) .input(ZDeleteTemplateDirectLinkMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { templateId } = input; const { templateId } = input;
const userId = ctx.user.id; const userId = ctx.user.id;
return await deleteTemplateDirectLink({ userId, templateId }); await deleteTemplateDirectLink({ userId, templateId });
}), }),
toggleTemplateDirectLink: authenticatedProcedure toggleTemplateDirectLink: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/template/{templateId}/direct/toggle',
summary: 'Toggle direct link',
description: 'Enable or disable a direct link for a template',
tags: ['Template'],
},
})
.input(ZToggleTemplateDirectLinkMutationSchema) .input(ZToggleTemplateDirectLinkMutationSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { templateId, enabled } = input; const { templateId, enabled } = input;
@@ -240,7 +349,17 @@ export const templateRouter = router({
}), }),
moveTemplateToTeam: authenticatedProcedure moveTemplateToTeam: authenticatedProcedure
.meta({
openapi: {
method: 'POST',
path: '/template/{templateId}/move',
summary: 'Move template',
description: 'Move a template to a team',
tags: ['Template'],
},
})
.input(ZMoveTemplatesToTeamSchema) .input(ZMoveTemplatesToTeamSchema)
.output(z.unknown())
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { templateId, teamId } = input; const { templateId, teamId } = input;
const userId = ctx.user.id; const userId = ctx.user.id;
@@ -252,16 +371,16 @@ export const templateRouter = router({
}); });
}), }),
// Internal endpoint for now.
updateTemplateTypedSignatureSettings: authenticatedProcedure updateTemplateTypedSignatureSettings: authenticatedProcedure
.input(ZUpdateTemplateTypedSignatureSettingsMutationSchema) .input(ZUpdateTemplateTypedSignatureSettingsMutationSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try {
const { templateId, teamId, typedSignatureEnabled } = input; const { templateId, teamId, typedSignatureEnabled } = input;
const template = await getTemplateById({ const template = await getTemplateById({
id: templateId, id: templateId,
teamId,
userId: ctx.user.id, userId: ctx.user.id,
teamId,
}).catch(() => null); }).catch(() => null);
if (!template) { if (!template) {
@@ -281,18 +400,5 @@ export const templateRouter = router({
}, },
requestMetadata: extractNextApiRequestMetadata(ctx.req), requestMetadata: extractNextApiRequestMetadata(ctx.req),
}); });
} catch (err) {
console.error(err);
if (err instanceof TRPCError) {
throw err;
}
throw new TRPCError({
code: 'BAD_REQUEST',
message:
'We were unable to update the settings for this template. Please try again later.',
});
}
}), }),
}); });

View File

@@ -70,7 +70,7 @@ export const ZToggleTemplateDirectLinkMutationSchema = z.object({
}); });
export const ZDeleteTemplateMutationSchema = z.object({ export const ZDeleteTemplateMutationSchema = z.object({
id: z.number().min(1), templateId: z.number().min(1),
teamId: z.number().optional(), teamId: z.number().optional(),
}); });
@@ -130,8 +130,9 @@ export const ZFindTemplatesQuerySchema = ZBaseTableSearchParamsSchema.extend({
type: z.nativeEnum(TemplateType).optional(), type: z.nativeEnum(TemplateType).optional(),
}); });
export const ZGetTemplateWithDetailsByIdQuerySchema = z.object({ export const ZGetTemplateByIdQuerySchema = z.object({
id: z.number().min(1), templateId: z.number().min(1),
teamId: z.number().optional(),
}); });
export const ZMoveTemplatesToTeamSchema = z.object({ export const ZMoveTemplatesToTeamSchema = z.object({
@@ -151,7 +152,5 @@ export type TCreateDocumentFromTemplateMutationSchema = z.infer<
>; >;
export type TDuplicateTemplateMutationSchema = z.infer<typeof ZDuplicateTemplateMutationSchema>; export type TDuplicateTemplateMutationSchema = z.infer<typeof ZDuplicateTemplateMutationSchema>;
export type TDeleteTemplateMutationSchema = z.infer<typeof ZDeleteTemplateMutationSchema>; export type TDeleteTemplateMutationSchema = z.infer<typeof ZDeleteTemplateMutationSchema>;
export type TGetTemplateWithDetailsByIdQuerySchema = z.infer< export type TGetTemplateByIdQuerySchema = z.infer<typeof ZGetTemplateByIdQuerySchema>;
typeof ZGetTemplateWithDetailsByIdQuerySchema
>;
export type TMoveTemplatesToSchema = z.infer<typeof ZMoveTemplatesToTeamSchema>; export type TMoveTemplatesToSchema = z.infer<typeof ZMoveTemplatesToTeamSchema>;

View File

@@ -168,9 +168,10 @@ export const FieldAdvancedSettings = forwardRef<HTMLDivElement, FieldAdvancedSet
const isDocumentPage = pathname?.includes('document'); const isDocumentPage = pathname?.includes('document');
const [errors, setErrors] = useState<string[]>([]); const [errors, setErrors] = useState<string[]>([]);
const { data: template } = trpc.template.getTemplateWithDetailsById.useQuery( const { data: template } = trpc.template.getTemplateById.useQuery(
{ {
id: Number(id), templateId: Number(id),
teamId,
}, },
{ {
enabled: isTemplatePage, enabled: isTemplatePage,
@@ -179,7 +180,7 @@ export const FieldAdvancedSettings = forwardRef<HTMLDivElement, FieldAdvancedSet
const { data: document } = trpc.document.getDocumentById.useQuery( const { data: document } = trpc.document.getDocumentById.useQuery(
{ {
id: Number(id), documentId: Number(id),
teamId, teamId,
}, },
{ {