feat: add public profiles

This commit is contained in:
David Nguyen
2024-06-06 14:46:48 +10:00
parent d11a68fc4c
commit 5514dad4d8
43 changed files with 2067 additions and 137 deletions

View File

@ -88,9 +88,9 @@ export const profileRouter = router({
.input(ZUpdatePublicProfileMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { url } = input;
const { url, bio, enabled } = input;
if (IS_BILLING_ENABLED() && url.length < 6) {
if (IS_BILLING_ENABLED() && url !== undefined && url.length < 6) {
const subscriptions = await getSubscriptionsByUserId({
userId: ctx.user.id,
}).then((subscriptions) =>
@ -107,7 +107,11 @@ export const profileRouter = router({
const user = await updatePublicProfile({
userId: ctx.user.id,
url,
data: {
url,
bio,
enabled,
},
});
return { success: true, url: user.url };

View File

@ -2,6 +2,8 @@ import { z } from 'zod';
import { ZCurrentPasswordSchema, ZPasswordSchema } from '../auth-router/schema';
export const MAX_PROFILE_BIO_LENGTH = 256;
export const ZFindUserSecurityAuditLogsSchema = z.object({
page: z.number().optional(),
perPage: z.number().optional(),
@ -17,6 +19,8 @@ export const ZUpdateProfileMutationSchema = z.object({
});
export const ZUpdatePublicProfileMutationSchema = z.object({
bio: z.string().max(MAX_PROFILE_BIO_LENGTH).optional(),
enabled: z.boolean().optional(),
url: z
.string()
.trim()
@ -24,7 +28,8 @@ export const ZUpdatePublicProfileMutationSchema = z.object({
.min(1, { message: 'Please enter a valid username.' })
.regex(/^[a-z0-9-]+$/, {
message: 'Username can only container alphanumeric characters and dashes.',
}),
})
.optional(),
});
export const ZUpdatePasswordMutationSchema = z.object({

View File

@ -1,5 +1,7 @@
import { TRPCError } from '@trpc/server';
import { getTeamPrices } from '@documenso/ee/server-only/stripe/get-team-prices';
import { AppError } 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 { createTeam } from '@documenso/lib/server-only/team/create-team';
import { createTeamBillingPortal } from '@documenso/lib/server-only/team/create-team-billing-portal';
@ -30,6 +32,7 @@ import { resendTeamMemberInvitation } from '@documenso/lib/server-only/team/rese
import { updateTeam } from '@documenso/lib/server-only/team/update-team';
import { updateTeamEmail } from '@documenso/lib/server-only/team/update-team-email';
import { updateTeamMember } from '@documenso/lib/server-only/team/update-team-member';
import { updateTeamPublicProfile } from '@documenso/lib/server-only/team/update-team-public-profile';
import { authenticatedProcedure, router } from '../trpc';
import {
@ -60,6 +63,7 @@ import {
ZUpdateTeamEmailMutationSchema,
ZUpdateTeamMemberMutationSchema,
ZUpdateTeamMutationSchema,
ZUpdateTeamPublicProfileMutationSchema,
} from './schema';
export const teamRouter = router({
@ -459,6 +463,39 @@ export const teamRouter = router({
}
}),
updateTeamPublicProfile: authenticatedProcedure
.input(ZUpdateTeamPublicProfileMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { teamId, bio, enabled } = input;
const team = await updateTeamPublicProfile({
userId: ctx.user.id,
teamId,
data: {
bio,
enabled,
},
});
return { success: true, url: team.url };
} catch (err) {
console.error(err);
const error = AppError.parseError(err);
if (error.code !== AppErrorCode.UNKNOWN_ERROR) {
throw AppError.parseErrorToTRPCError(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
.input(ZRequestTeamOwnerhsipTransferMutationSchema)
.mutation(async ({ input, ctx }) => {

View File

@ -3,6 +3,8 @@ import { z } from 'zod';
import { PROTECTED_TEAM_URLS } from '@documenso/lib/constants/teams';
import { TeamMemberRole } from '@documenso/prisma/client';
import { ZUpdatePublicProfileMutationSchema } from '../profile-router/schema';
// Consider refactoring to use ZBaseTableSearchParamsSchema.
const GenericFindQuerySchema = z.object({
term: z.string().optional(),
@ -162,6 +164,13 @@ export const ZUpdateTeamMemberMutationSchema = z.object({
}),
});
export const ZUpdateTeamPublicProfileMutationSchema = ZUpdatePublicProfileMutationSchema.pick({
bio: true,
enabled: true,
}).extend({
teamId: z.number(),
});
export const ZRequestTeamOwnerhsipTransferMutationSchema = z.object({
teamId: z.number(),
newOwnerUserId: z.number(),

View File

@ -10,6 +10,7 @@ import { createTemplateDirectLink } from '@documenso/lib/server-only/template/cr
import { deleteTemplate } from '@documenso/lib/server-only/template/delete-template';
import { deleteTemplateDirectLink } from '@documenso/lib/server-only/template/delete-template-direct-link';
import { duplicateTemplate } from '@documenso/lib/server-only/template/duplicate-template';
import { findTemplates } from '@documenso/lib/server-only/template/find-templates';
import { getTemplateWithDetailsById } from '@documenso/lib/server-only/template/get-template-with-details-by-id';
import { toggleTemplateDirectLink } from '@documenso/lib/server-only/template/toggle-template-direct-link';
import { updateTemplateSettings } from '@documenso/lib/server-only/template/update-template-settings';
@ -25,6 +26,7 @@ import {
ZDeleteTemplateDirectLinkMutationSchema,
ZDeleteTemplateMutationSchema,
ZDuplicateTemplateMutationSchema,
ZFindTemplatesQuerySchema,
ZGetTemplateWithDetailsByIdQuerySchema,
ZToggleTemplateDirectLinkMutationSchema,
ZUpdateTemplateSettingsMutationSchema,
@ -214,6 +216,21 @@ export const templateRouter = router({
}
}),
findTemplates: authenticatedProcedure
.input(ZFindTemplatesQuerySchema)
.query(async ({ input, ctx }) => {
try {
return await findTemplates({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
}),
createTemplateDirectLink: authenticatedProcedure
.input(ZCreateTemplateDirectLinkMutationSchema)
.mutation(async ({ input, ctx }) => {

View File

@ -5,6 +5,8 @@ import {
ZDocumentAccessAuthTypesSchema,
ZDocumentActionAuthTypesSchema,
} from '@documenso/lib/types/document-auth';
import { ZBaseTableSearchParamsSchema } from '@documenso/lib/types/search-params';
import { TemplateType } from '@documenso/prisma/client';
import { ZSignFieldWithTokenMutationSchema } from '../field-router/schema';
@ -62,6 +64,9 @@ export const ZDeleteTemplateMutationSchema = z.object({
id: z.number().min(1),
});
export const MAX_TEMPLATE_PUBLIC_TITLE_LENGTH = 50;
export const MAX_TEMPLATE_PUBLIC_DESCRIPTION_LENGTH = 256;
export const ZUpdateTemplateSettingsMutationSchema = z.object({
templateId: z.number(),
teamId: z.number().min(1).optional(),
@ -69,19 +74,34 @@ export const ZUpdateTemplateSettingsMutationSchema = z.object({
title: z.string().min(1).optional(),
globalAccessAuth: ZDocumentAccessAuthTypesSchema.nullable().optional(),
globalActionAuth: ZDocumentActionAuthTypesSchema.nullable().optional(),
}),
meta: z.object({
subject: z.string(),
message: z.string(),
timezone: z.string(),
dateFormat: z.string(),
redirectUrl: z
publicTitle: z.string().trim().min(1).max(MAX_TEMPLATE_PUBLIC_TITLE_LENGTH).optional(),
publicDescription: z
.string()
.optional()
.refine((value) => value === undefined || value === '' || URL_REGEX.test(value), {
message: 'Please enter a valid URL',
}),
.trim()
.min(1)
.max(MAX_TEMPLATE_PUBLIC_DESCRIPTION_LENGTH)
.optional(),
type: z.nativeEnum(TemplateType).optional(),
}),
meta: z
.object({
subject: z.string(),
message: z.string(),
timezone: z.string(),
dateFormat: z.string(),
redirectUrl: z
.string()
.optional()
.refine((value) => value === undefined || value === '' || URL_REGEX.test(value), {
message: 'Please enter a valid URL',
}),
})
.optional(),
});
export const ZFindTemplatesQuerySchema = ZBaseTableSearchParamsSchema.extend({
teamId: z.number().optional(),
type: z.nativeEnum(TemplateType).optional(),
});
export const ZGetTemplateWithDetailsByIdQuerySchema = z.object({