mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 08:13:56 +10:00
feat: add more template API endpoints (#1198)
## Description
Update the API endpoint to support more actions for templates
## Changes Made
Add the following endpoints for templates:
- Get template
- Get templates
- Delete template
Get template(s) returns associated recipients and fields.
UI:
- Updated template delete button to have the destructive delete variant
## Testing Performed
Tested endpoints via /api/v1/openapi
Tested deleting templates via UI manually
## Test data
<details>
<summary>Delete template response</summary>
```json
{
"id": 32,
"type": "PRIVATE",
"title": "documenso-supporter-pledge.pdf",
"userId": 3,
"teamId": null,
"templateDocumentDataId": "clxva9b4h0001rrh7v0wdw97h",
"createdAt": "2024-06-26T03:35:45.065Z",
"updatedAt": "2024-06-26T03:35:45.065Z"
}
```
</details>
<details>
<summary>Get template response</summary>
```json
{
"id": 28,
"type": "PRIVATE",
"title": "blank_long.pdf",
"userId": 3,
"teamId": null,
"templateDocumentDataId": "clxu4vyty0003rrr52ue5ee4d",
"createdAt": "2024-06-25T08:17:38.418Z",
"updatedAt": "2024-06-26T03:36:33.890Z",
"templateMeta": {
"id": "clxvaacte0004rrh7s2k910nw",
"subject": "",
"message": "",
"timezone": "Australia/Melbourne",
"dateFormat": "yyyy-MM-dd hh:mm a",
"templateId": 28,
"redirectUrl": ""
},
"directLink": {
"token": "tBJHVFR75sC8m6hPfBTZd",
"enabled": true
},
"templateDocumentData": {
"id": "clxu4vyty0003rrr52ue5ee4d",
"type": "BYTES_64",
"data": "<PDF DATA>"
},
"Field": [
{
"id": 327,
"recipientId": 357,
"type": "SIGNATURE",
"page": 1,
"positionX": "55.8431952662722",
"positionY": "21.39588100686499",
"width": "29.58579881656805",
"height": "6.864988558352403"
},
{
"id": 328,
"recipientId": 357,
"type": "EMAIL",
"page": 1,
"positionX": "28.03254437869823",
"positionY": "72.99771167048056",
"width": "29.58579881656805",
"height": "6.864988558352403"
}
],
"Recipient": [
{
"id": 357,
"email": "direct.link@documenso.com",
"name": "Direct link recipient",
"authOptions": {
"accessAuth": null,
"actionAuth": null
},
"role": "SIGNER"
},
{
"id": 359,
"email": "example@documenso.com",
"name": "Example User",
"authOptions": {
"accessAuth": null,
"actionAuth": null
},
"role": "SIGNER"
}
]
}
```
</details>
<details>
<summary>Get templates response</summary>
```json
{
"templates": [
{
"id": 33,
"type": "PRIVATE",
"title": "documenso-supporter-pledge.pdf",
"userId": 3,
"teamId": null,
"templateDocumentDataId": "clxva9oaj0003rrh7hwdyg60o",
"createdAt": "2024-06-26T03:36:02.130Z",
"updatedAt": "2024-06-26T03:36:02.130Z",
"directLink": null,
"Field": [],
"Recipient": []
},
{
"id": 28,
"type": "PRIVATE",
"title": "blank_long.pdf",
"userId": 3,
"teamId": null,
"templateDocumentDataId": "clxu4vyty0003rrr52ue5ee4d",
"createdAt": "2024-06-25T08:17:38.418Z",
"updatedAt": "2024-06-26T03:36:33.890Z",
"directLink": {
"token": "tBJHVFR75sC8m6hPfBTZd",
"enabled": true
},
"Field": [
{
"id": 327,
"recipientId": 357,
"type": "SIGNATURE",
"page": 1,
"positionX": "55.8431952662722",
"positionY": "21.39588100686499",
"width": "29.58579881656805",
"height": "6.864988558352403"
},
{
"id": 328,
"recipientId": 357,
"type": "EMAIL",
"page": 1,
"positionX": "28.03254437869823",
"positionY": "72.99771167048056",
"width": "29.58579881656805",
"height": "6.864988558352403"
}
],
"Recipient": [
{
"id": 357,
"email": "direct.link@documenso.com",
"name": "Direct link recipient",
"authOptions": {
"accessAuth": null,
"actionAuth": null
},
"role": "SIGNER"
},
{
"id": 359,
"email": "example@documenso.com",
"name": "Example User",
"authOptions": {
"accessAuth": null,
"actionAuth": null
},
"role": "SIGNER"
}
]
}
],
"totalPages": 2
}
```
</details>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Added support for team-based template deletion in the dashboard.
- Enhanced API to manage templates, including fetching and deleting
templates by team ID.
- **Bug Fixes**
- Improved error handling for template operations, ensuring better
feedback when templates are not found.
- **Refactor**
- Updated various components and functions to include `teamId` for more
robust template management.
- **Documentation**
- Expanded schema definitions to detail new structures for template and
team interactions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@ -97,6 +97,7 @@ export const DataTableActionDropdown = ({
|
|||||||
|
|
||||||
<DeleteTemplateDialog
|
<DeleteTemplateDialog
|
||||||
id={row.id}
|
id={row.id}
|
||||||
|
teamId={row.teamId || undefined}
|
||||||
open={isDeleteDialogOpen}
|
open={isDeleteDialogOpen}
|
||||||
onOpenChange={setDeleteDialogOpen}
|
onOpenChange={setDeleteDialogOpen}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -14,11 +14,17 @@ import { useToast } from '@documenso/ui/primitives/use-toast';
|
|||||||
|
|
||||||
type DeleteTemplateDialogProps = {
|
type DeleteTemplateDialogProps = {
|
||||||
id: number;
|
id: number;
|
||||||
|
teamId?: number;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onOpenChange: (_open: boolean) => void;
|
onOpenChange: (_open: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DeleteTemplateDialog = ({ id, open, onOpenChange }: DeleteTemplateDialogProps) => {
|
export const DeleteTemplateDialog = ({
|
||||||
|
id,
|
||||||
|
teamId,
|
||||||
|
open,
|
||||||
|
onOpenChange,
|
||||||
|
}: DeleteTemplateDialogProps) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
@ -67,7 +73,12 @@ export const DeleteTemplateDialog = ({ id, open, onOpenChange }: DeleteTemplateD
|
|||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button type="button" loading={isLoading} onClick={async () => deleteTemplate({ id })}>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="destructive"
|
||||||
|
loading={isLoading}
|
||||||
|
onClick={async () => deleteTemplate({ id, teamId })}
|
||||||
|
>
|
||||||
Delete
|
Delete
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|||||||
@ -15,10 +15,15 @@ import {
|
|||||||
ZGenerateDocumentFromTemplateMutationResponseSchema,
|
ZGenerateDocumentFromTemplateMutationResponseSchema,
|
||||||
ZGenerateDocumentFromTemplateMutationSchema,
|
ZGenerateDocumentFromTemplateMutationSchema,
|
||||||
ZGetDocumentsQuerySchema,
|
ZGetDocumentsQuerySchema,
|
||||||
|
ZGetTemplatesQuerySchema,
|
||||||
|
ZNoBodyMutationSchema,
|
||||||
ZSendDocumentForSigningMutationSchema,
|
ZSendDocumentForSigningMutationSchema,
|
||||||
|
ZSuccessfulDeleteTemplateResponseSchema,
|
||||||
ZSuccessfulDocumentResponseSchema,
|
ZSuccessfulDocumentResponseSchema,
|
||||||
ZSuccessfulFieldResponseSchema,
|
ZSuccessfulFieldResponseSchema,
|
||||||
ZSuccessfulGetDocumentResponseSchema,
|
ZSuccessfulGetDocumentResponseSchema,
|
||||||
|
ZSuccessfulGetTemplateResponseSchema,
|
||||||
|
ZSuccessfulGetTemplatesResponseSchema,
|
||||||
ZSuccessfulRecipientResponseSchema,
|
ZSuccessfulRecipientResponseSchema,
|
||||||
ZSuccessfulResponseSchema,
|
ZSuccessfulResponseSchema,
|
||||||
ZSuccessfulSigningResponseSchema,
|
ZSuccessfulSigningResponseSchema,
|
||||||
@ -77,6 +82,41 @@ export const ApiContractV1 = c.router(
|
|||||||
summary: 'Upload a new document and get a presigned URL',
|
summary: 'Upload a new document and get a presigned URL',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
deleteTemplate: {
|
||||||
|
method: 'DELETE',
|
||||||
|
path: '/api/v1/templates/:id',
|
||||||
|
body: ZNoBodyMutationSchema,
|
||||||
|
responses: {
|
||||||
|
200: ZSuccessfulDeleteTemplateResponseSchema,
|
||||||
|
401: ZUnsuccessfulResponseSchema,
|
||||||
|
404: ZUnsuccessfulResponseSchema,
|
||||||
|
},
|
||||||
|
summary: 'Delete a template',
|
||||||
|
},
|
||||||
|
|
||||||
|
getTemplate: {
|
||||||
|
method: 'GET',
|
||||||
|
path: '/api/v1/templates/:id',
|
||||||
|
responses: {
|
||||||
|
200: ZSuccessfulGetTemplateResponseSchema,
|
||||||
|
401: ZUnsuccessfulResponseSchema,
|
||||||
|
404: ZUnsuccessfulResponseSchema,
|
||||||
|
},
|
||||||
|
summary: 'Get a single template',
|
||||||
|
},
|
||||||
|
|
||||||
|
getTemplates: {
|
||||||
|
method: 'GET',
|
||||||
|
path: '/api/v1/templates',
|
||||||
|
query: ZGetTemplatesQuerySchema,
|
||||||
|
responses: {
|
||||||
|
200: ZSuccessfulGetTemplatesResponseSchema,
|
||||||
|
401: ZUnsuccessfulResponseSchema,
|
||||||
|
404: ZUnsuccessfulResponseSchema,
|
||||||
|
},
|
||||||
|
summary: 'Get all templates',
|
||||||
|
},
|
||||||
|
|
||||||
createDocumentFromTemplate: {
|
createDocumentFromTemplate: {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
path: '/api/v1/templates/:templateId/create-document',
|
path: '/api/v1/templates/:templateId/create-document',
|
||||||
|
|||||||
@ -24,6 +24,9 @@ import { updateRecipient } from '@documenso/lib/server-only/recipient/update-rec
|
|||||||
import type { CreateDocumentFromTemplateResponse } from '@documenso/lib/server-only/template/create-document-from-template';
|
import type { CreateDocumentFromTemplateResponse } from '@documenso/lib/server-only/template/create-document-from-template';
|
||||||
import { createDocumentFromTemplate } from '@documenso/lib/server-only/template/create-document-from-template';
|
import { createDocumentFromTemplate } from '@documenso/lib/server-only/template/create-document-from-template';
|
||||||
import { createDocumentFromTemplateLegacy } from '@documenso/lib/server-only/template/create-document-from-template-legacy';
|
import { createDocumentFromTemplateLegacy } from '@documenso/lib/server-only/template/create-document-from-template-legacy';
|
||||||
|
import { deleteTemplate } from '@documenso/lib/server-only/template/delete-template';
|
||||||
|
import { findTemplates } from '@documenso/lib/server-only/template/find-templates';
|
||||||
|
import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id';
|
||||||
import { extractNextApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
import { extractNextApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
||||||
import { getFile } from '@documenso/lib/universal/upload/get-file';
|
import { getFile } from '@documenso/lib/universal/upload/get-file';
|
||||||
import { putPdfFile } from '@documenso/lib/universal/upload/put-file';
|
import { putPdfFile } from '@documenso/lib/universal/upload/put-file';
|
||||||
@ -277,6 +280,73 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
deleteTemplate: authenticatedMiddleware(async (args, user, team) => {
|
||||||
|
const { id: templateId } = args.params;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const deletedTemplate = await deleteTemplate({
|
||||||
|
id: Number(templateId),
|
||||||
|
userId: user.id,
|
||||||
|
teamId: team?.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: 200,
|
||||||
|
body: deletedTemplate,
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
status: 404,
|
||||||
|
body: {
|
||||||
|
message: 'Template not found',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
getTemplate: authenticatedMiddleware(async (args, user, team) => {
|
||||||
|
const { id: templateId } = args.params;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const template = await getTemplateById({
|
||||||
|
id: Number(templateId),
|
||||||
|
userId: user.id,
|
||||||
|
teamId: team?.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: 200,
|
||||||
|
body: template,
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
return AppError.toRestAPIError(err);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
getTemplates: authenticatedMiddleware(async (args, user, team) => {
|
||||||
|
const page = Number(args.query.page) || 1;
|
||||||
|
const perPage = Number(args.query.perPage) || 10;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { templates, totalPages } = await findTemplates({
|
||||||
|
page,
|
||||||
|
perPage,
|
||||||
|
userId: user.id,
|
||||||
|
teamId: team?.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: 200,
|
||||||
|
body: {
|
||||||
|
templates,
|
||||||
|
totalPages,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
return AppError.toRestAPIError(err);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
createDocumentFromTemplate: authenticatedMiddleware(async (args, user, team) => {
|
createDocumentFromTemplate: authenticatedMiddleware(async (args, user, team) => {
|
||||||
const { body, params } = args;
|
const { body, params } = args;
|
||||||
|
|
||||||
|
|||||||
@ -2,13 +2,17 @@ import { z } from 'zod';
|
|||||||
|
|
||||||
import { ZUrlSchema } from '@documenso/lib/schemas/common';
|
import { ZUrlSchema } from '@documenso/lib/schemas/common';
|
||||||
import {
|
import {
|
||||||
|
DocumentDataType,
|
||||||
FieldType,
|
FieldType,
|
||||||
ReadStatus,
|
ReadStatus,
|
||||||
RecipientRole,
|
RecipientRole,
|
||||||
SendStatus,
|
SendStatus,
|
||||||
SigningStatus,
|
SigningStatus,
|
||||||
|
TemplateType,
|
||||||
} from '@documenso/prisma/client';
|
} from '@documenso/prisma/client';
|
||||||
|
|
||||||
|
export const ZNoBodyMutationSchema = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Documents
|
* Documents
|
||||||
*/
|
*/
|
||||||
@ -315,3 +319,106 @@ export const ZUnsuccessfulResponseSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export type TUnsuccessfulResponseSchema = z.infer<typeof ZUnsuccessfulResponseSchema>;
|
export type TUnsuccessfulResponseSchema = z.infer<typeof ZUnsuccessfulResponseSchema>;
|
||||||
|
|
||||||
|
export const ZTemplateMetaSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
subject: z.string().nullish(),
|
||||||
|
message: z.string().nullish(),
|
||||||
|
timezone: z.string().nullish(),
|
||||||
|
dateFormat: z.string().nullish(),
|
||||||
|
templateId: z.number(),
|
||||||
|
redirectUrl: z.string().nullish(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ZTemplateSchema = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
type: z.nativeEnum(TemplateType),
|
||||||
|
title: z.string(),
|
||||||
|
userId: z.number(),
|
||||||
|
teamId: z.number().nullish(),
|
||||||
|
templateDocumentDataId: z.string(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ZRecipientSchema = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
documentId: z.number().nullish(),
|
||||||
|
templateId: z.number().nullish(),
|
||||||
|
email: z.string().email().min(1),
|
||||||
|
name: z.string(),
|
||||||
|
token: z.string(),
|
||||||
|
documentDeletedAt: z.date().nullish(),
|
||||||
|
expired: z.date().nullish(),
|
||||||
|
signedAt: z.date().nullish(),
|
||||||
|
authOptions: z.unknown(),
|
||||||
|
role: z.nativeEnum(RecipientRole),
|
||||||
|
readStatus: z.nativeEnum(ReadStatus),
|
||||||
|
signingStatus: z.nativeEnum(SigningStatus),
|
||||||
|
sendStatus: z.nativeEnum(SendStatus),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ZFieldSchema = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
secondaryId: z.string(),
|
||||||
|
documentId: z.number().nullish(),
|
||||||
|
templateId: z.number().nullish(),
|
||||||
|
recipientId: z.number(),
|
||||||
|
type: z.nativeEnum(FieldType),
|
||||||
|
page: z.number(),
|
||||||
|
positionX: z.unknown(),
|
||||||
|
positionY: z.unknown(),
|
||||||
|
width: z.unknown(),
|
||||||
|
height: z.unknown(),
|
||||||
|
customText: z.string(),
|
||||||
|
inserted: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ZTemplateWithDataSchema = ZTemplateSchema.extend({
|
||||||
|
templateMeta: ZTemplateMetaSchema.nullish(),
|
||||||
|
directLink: z
|
||||||
|
.object({
|
||||||
|
token: z.string(),
|
||||||
|
enabled: z.boolean(),
|
||||||
|
})
|
||||||
|
.nullable(),
|
||||||
|
templateDocumentData: z.object({
|
||||||
|
id: z.string(),
|
||||||
|
type: z.nativeEnum(DocumentDataType),
|
||||||
|
data: z.string(),
|
||||||
|
}),
|
||||||
|
Field: ZFieldSchema.pick({
|
||||||
|
id: true,
|
||||||
|
recipientId: true,
|
||||||
|
type: true,
|
||||||
|
page: true,
|
||||||
|
positionX: true,
|
||||||
|
positionY: true,
|
||||||
|
width: true,
|
||||||
|
height: true,
|
||||||
|
}).array(),
|
||||||
|
Recipient: ZRecipientSchema.pick({
|
||||||
|
id: true,
|
||||||
|
email: true,
|
||||||
|
name: true,
|
||||||
|
authOptions: true,
|
||||||
|
role: true,
|
||||||
|
}).array(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ZSuccessfulGetTemplateResponseSchema = ZTemplateWithDataSchema;
|
||||||
|
|
||||||
|
export const ZSuccessfulDeleteTemplateResponseSchema = ZTemplateSchema;
|
||||||
|
|
||||||
|
export const ZSuccessfulGetTemplatesResponseSchema = z.object({
|
||||||
|
templates: ZTemplateWithDataSchema.omit({
|
||||||
|
templateDocumentData: true,
|
||||||
|
templateMeta: true,
|
||||||
|
}).array(),
|
||||||
|
totalPages: z.number(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ZGetTemplatesQuerySchema = z.object({
|
||||||
|
page: z.coerce.number().min(1).optional().default(1),
|
||||||
|
perPage: z.coerce.number().min(1).optional().default(1),
|
||||||
|
});
|
||||||
|
|||||||
@ -5,26 +5,33 @@ import { prisma } from '@documenso/prisma';
|
|||||||
export type DeleteTemplateOptions = {
|
export type DeleteTemplateOptions = {
|
||||||
id: number;
|
id: number;
|
||||||
userId: number;
|
userId: number;
|
||||||
|
teamId?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteTemplate = async ({ id, userId }: DeleteTemplateOptions) => {
|
export const deleteTemplate = async ({ id, userId, teamId }: DeleteTemplateOptions) => {
|
||||||
return await prisma.template.delete({
|
return await prisma.template.delete({
|
||||||
where: {
|
where: {
|
||||||
id,
|
id,
|
||||||
OR: [
|
OR:
|
||||||
{
|
teamId === undefined
|
||||||
userId,
|
? [
|
||||||
},
|
{
|
||||||
{
|
|
||||||
team: {
|
|
||||||
members: {
|
|
||||||
some: {
|
|
||||||
userId,
|
userId,
|
||||||
|
teamId: null,
|
||||||
},
|
},
|
||||||
},
|
]
|
||||||
},
|
: [
|
||||||
},
|
{
|
||||||
],
|
teamId,
|
||||||
|
team: {
|
||||||
|
members: {
|
||||||
|
some: {
|
||||||
|
userId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,34 +1,53 @@
|
|||||||
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 { AppError, AppErrorCode } from '../../errors/app-error';
|
||||||
|
|
||||||
export interface GetTemplateByIdOptions {
|
export interface GetTemplateByIdOptions {
|
||||||
id: number;
|
id: number;
|
||||||
userId: number;
|
userId: number;
|
||||||
|
teamId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getTemplateById = async ({ id, userId }: GetTemplateByIdOptions) => {
|
export const getTemplateById = async ({ id, userId, teamId }: GetTemplateByIdOptions) => {
|
||||||
const whereFilter: Prisma.TemplateWhereInput = {
|
const whereFilter: Prisma.TemplateWhereInput = {
|
||||||
id,
|
id,
|
||||||
OR: [
|
OR:
|
||||||
{
|
teamId === undefined
|
||||||
userId,
|
? [
|
||||||
},
|
{
|
||||||
{
|
|
||||||
team: {
|
|
||||||
members: {
|
|
||||||
some: {
|
|
||||||
userId,
|
userId,
|
||||||
|
teamId: null,
|
||||||
},
|
},
|
||||||
},
|
]
|
||||||
},
|
: [
|
||||||
},
|
{
|
||||||
],
|
teamId,
|
||||||
|
team: {
|
||||||
|
members: {
|
||||||
|
some: {
|
||||||
|
userId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
return await prisma.template.findFirstOrThrow({
|
const template = await prisma.template.findFirst({
|
||||||
where: whereFilter,
|
where: whereFilter,
|
||||||
include: {
|
include: {
|
||||||
|
directLink: true,
|
||||||
templateDocumentData: true,
|
templateDocumentData: true,
|
||||||
|
templateMeta: true,
|
||||||
|
Recipient: true,
|
||||||
|
Field: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!template) {
|
||||||
|
throw new AppError(AppErrorCode.NOT_FOUND, 'Template not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return template;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -151,11 +151,11 @@ export const templateRouter = router({
|
|||||||
.input(ZDeleteTemplateMutationSchema)
|
.input(ZDeleteTemplateMutationSchema)
|
||||||
.mutation(async ({ input, ctx }) => {
|
.mutation(async ({ input, ctx }) => {
|
||||||
try {
|
try {
|
||||||
const { id } = input;
|
const { id, teamId } = input;
|
||||||
|
|
||||||
const userId = ctx.user.id;
|
const userId = ctx.user.id;
|
||||||
|
|
||||||
return await deleteTemplate({ userId, id });
|
return await deleteTemplate({ userId, id, teamId });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|
||||||
|
|||||||
@ -60,6 +60,7 @@ export const ZToggleTemplateDirectLinkMutationSchema = z.object({
|
|||||||
|
|
||||||
export const ZDeleteTemplateMutationSchema = z.object({
|
export const ZDeleteTemplateMutationSchema = z.object({
|
||||||
id: z.number().min(1),
|
id: z.number().min(1),
|
||||||
|
teamId: z.number().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ZUpdateTemplateSettingsMutationSchema = z.object({
|
export const ZUpdateTemplateSettingsMutationSchema = z.object({
|
||||||
|
|||||||
Reference in New Issue
Block a user