feat: create a banner with custom text by admin

This commit is contained in:
Ephraim Atta-Duncan
2024-02-22 20:13:17 +00:00
parent 15e191f62d
commit c436559787
15 changed files with 291 additions and 12 deletions

View File

@ -1,5 +1,5 @@
import { prisma } from '@documenso/prisma';
import { Role } from '@documenso/prisma/client';
import type { Role } from '@documenso/prisma/client';
export type UpdateUserOptions = {
id: number;

View File

@ -0,0 +1,11 @@
'use server';
import { prisma } from '@documenso/prisma';
export const getBanner = async () => {
return await prisma.banner.findUnique({
where: {
id: 1,
},
});
};

View File

@ -0,0 +1,28 @@
'use server';
import { prisma } from '@documenso/prisma';
import { Role } from '@documenso/prisma/client';
export type UpdateUserOptions = {
userId: number;
show?: boolean;
text?: string | undefined;
};
export const upsertBanner = async ({ userId, show, text }: UpdateUserOptions) => {
const user = await prisma.user.findUnique({
where: {
id: userId,
},
});
if (!user?.roles.includes(Role.ADMIN)) {
throw Error('You are unauthorised to perform this action');
}
return await prisma.banner.upsert({
where: { id: 1, user: {} },
update: { show, text },
create: { show, text: text ?? '' },
});
};

View File

@ -0,0 +1,12 @@
-- CreateTable
CREATE TABLE "Banner" (
"id" SERIAL NOT NULL,
"text" TEXT NOT NULL,
"customHTML" TEXT NOT NULL,
"userId" INTEGER,
CONSTRAINT "Banner_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE "Banner" ADD CONSTRAINT "Banner_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Banner" ADD COLUMN "show" BOOLEAN NOT NULL DEFAULT false;

View File

@ -0,0 +1,8 @@
/*
Warnings:
- You are about to drop the column `customHTML` on the `Banner` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE "Banner" DROP COLUMN "customHTML";

View File

@ -47,6 +47,7 @@ model User {
VerificationToken VerificationToken[]
Template Template[]
securityAuditLogs UserSecurityAuditLog[]
Banner Banner[]
@@index([email])
}
@ -210,15 +211,15 @@ model DocumentData {
}
model DocumentMeta {
id String @id @default(cuid())
subject String?
message String?
timezone String? @default("Etc/UTC") @db.Text
password String?
dateFormat String? @default("yyyy-MM-dd hh:mm a") @db.Text
documentId Int @unique
document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
redirectUrl String?
id String @id @default(cuid())
subject String?
message String?
timezone String? @default("Etc/UTC") @db.Text
password String?
dateFormat String? @default("yyyy-MM-dd hh:mm a") @db.Text
documentId Int @unique
document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
redirectUrl String?
}
enum ReadStatus {
@ -450,3 +451,11 @@ model Template {
@@unique([templateDocumentDataId])
}
model Banner {
id Int @id @default(autoincrement())
text String
show Boolean @default(false)
user User? @relation(fields: [userId], references: [id])
userId Int?
}

View File

@ -0,0 +1,27 @@
import { TRPCError } from '@trpc/server';
import { upsertBanner } from '@documenso/lib/server-only/banner/upsert-banner';
import { adminProcedure, router } from '../trpc';
import { ZCreateBannerByAdminSchema } from './schema';
export const bannerRouter = router({
updateBanner: adminProcedure
.input(ZCreateBannerByAdminSchema)
.mutation(async ({ input, ctx }) => {
const { show, text } = input;
try {
return await upsertBanner({
userId: ctx.user.id,
show,
text,
});
} catch (err) {
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'We were unable to update your banner. Please try again.',
});
}
}),
});

View File

@ -0,0 +1,8 @@
import z from 'zod';
export const ZCreateBannerByAdminSchema = z.object({
text: z.string().optional(),
show: z.boolean().optional(),
});
export type TCreateBannerByAdminSchema = z.infer<typeof ZCreateBannerByAdminSchema>;

View File

@ -1,5 +1,6 @@
import { adminRouter } from './admin-router/router';
import { authRouter } from './auth-router/router';
import { bannerRouter } from './banner-router/router';
import { cryptoRouter } from './crypto/router';
import { documentRouter } from './document-router/router';
import { fieldRouter } from './field-router/router';
@ -14,6 +15,7 @@ import { twoFactorAuthenticationRouter } from './two-factor-authentication-route
export const appRouter = router({
auth: authRouter,
banner: bannerRouter,
crypto: cryptoRouter,
profile: profileRouter,
document: documentRouter,