Skip to content

Commit

Permalink
feat: implement data logic and functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
schettn committed Nov 11, 2023
1 parent 5079d58 commit cd50129
Show file tree
Hide file tree
Showing 31 changed files with 1,571 additions and 11,479 deletions.
1 change: 0 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ WORKDIR /app

COPY .sf/ ./.sf
COPY package.json .
COPY templates/ ./templates
# Copy prisma files
COPY prisma/schema.prisma ./prisma/schema.prisma

Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,18 @@
},
"dependencies": {
"@devoxa/prisma-relay-cursor-connection": "^3.1.0",
"@netsnek/prisma-repository": "^0.0.2",
"@prisma/client": "^5.2.0",
"@snek-at/function": "*",
"@snek-at/function-cli": "*",
"@snek-at/function-server": "*",
"@snek-functions/jwt": "*",
"deep-object-diff": "^1.1.9",
"dotenv": "^16.0.3",
"html-minifier": "^4.0.0",
"twig": "^1.16.0",
"prisma": "^5.2.0"
"isolated-vm": "^4.6.0",
"prisma": "^5.2.0",
"twig": "^1.16.0"
},
"devDependencies": {
"@types/html-minifier": "^4.0.2",
Expand Down
96 changes: 96 additions & 0 deletions prisma/migrations/20231105104113_initial/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
-- CreateEnum
CREATE TYPE "EmailAddressType" AS ENUM ('EMAIL_ADDRESS', 'EMAIL_ID', 'USER_ID');

-- CreateTable
CREATE TABLE "EmailTemplate" (
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
"content" TEXT NOT NULL,
"verifyReplyTo" BOOLEAN,
"transformer" TEXT,
"authorizationUserId" UUID NOT NULL,
"envelopeId" UUID NOT NULL,
"parentId" UUID,
"createdBy" UUID,
"resourceId" UUID,
"createdAt" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3),

CONSTRAINT "EmailTemplate_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "VariableDefinition" (
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
"name" TEXT NOT NULL,
"description" TEXT,
"defaultValue" TEXT NOT NULL,
"isRequired" BOOLEAN,
"isConstant" BOOLEAN,
"emailTemplateId" UUID,

CONSTRAINT "VariableDefinition_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "AuthorizationUser" (
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
"userId" UUID NOT NULL,
"authorization" TEXT NOT NULL,

CONSTRAINT "AuthorizationUser_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "EmailEnvelope" (
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
"subject" TEXT,
"fromId" UUID NOT NULL,
"replyToId" UUID NOT NULL,

CONSTRAINT "EmailEnvelope_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "EmailAddress" (
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
"value" TEXT NOT NULL,
"type" "EmailAddressType" NOT NULL,

CONSTRAINT "EmailAddress_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "_EmailAddressToEmailEnvelope" (
"A" UUID NOT NULL,
"B" UUID NOT NULL
);

-- CreateIndex
CREATE UNIQUE INDEX "_EmailAddressToEmailEnvelope_AB_unique" ON "_EmailAddressToEmailEnvelope"("A", "B");

-- CreateIndex
CREATE INDEX "_EmailAddressToEmailEnvelope_B_index" ON "_EmailAddressToEmailEnvelope"("B");

-- AddForeignKey
ALTER TABLE "EmailTemplate" ADD CONSTRAINT "EmailTemplate_authorizationUserId_fkey" FOREIGN KEY ("authorizationUserId") REFERENCES "AuthorizationUser"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "EmailTemplate" ADD CONSTRAINT "EmailTemplate_envelopeId_fkey" FOREIGN KEY ("envelopeId") REFERENCES "EmailEnvelope"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "EmailTemplate" ADD CONSTRAINT "EmailTemplate_parentId_fkey" FOREIGN KEY ("parentId") REFERENCES "EmailTemplate"("id") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "VariableDefinition" ADD CONSTRAINT "VariableDefinition_emailTemplateId_fkey" FOREIGN KEY ("emailTemplateId") REFERENCES "EmailTemplate"("id") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "EmailEnvelope" ADD CONSTRAINT "EmailEnvelope_fromId_fkey" FOREIGN KEY ("fromId") REFERENCES "EmailAddress"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "EmailEnvelope" ADD CONSTRAINT "EmailEnvelope_replyToId_fkey" FOREIGN KEY ("replyToId") REFERENCES "EmailAddress"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_EmailAddressToEmailEnvelope" ADD CONSTRAINT "_EmailAddressToEmailEnvelope_A_fkey" FOREIGN KEY ("A") REFERENCES "EmailAddress"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_EmailAddressToEmailEnvelope" ADD CONSTRAINT "_EmailAddressToEmailEnvelope_B_fkey" FOREIGN KEY ("B") REFERENCES "EmailEnvelope"("id") ON DELETE CASCADE ON UPDATE CASCADE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Warnings:
- Made the column `createdAt` on table `EmailTemplate` required. This step will fail if there are existing NULL values in that column.
- Made the column `updatedAt` on table `EmailTemplate` required. This step will fail if there are existing NULL values in that column.
*/
-- DropForeignKey
ALTER TABLE "EmailEnvelope" DROP CONSTRAINT "EmailEnvelope_fromId_fkey";

-- DropForeignKey
ALTER TABLE "EmailEnvelope" DROP CONSTRAINT "EmailEnvelope_replyToId_fkey";

-- DropForeignKey
ALTER TABLE "EmailTemplate" DROP CONSTRAINT "EmailTemplate_authorizationUserId_fkey";

-- DropForeignKey
ALTER TABLE "EmailTemplate" DROP CONSTRAINT "EmailTemplate_envelopeId_fkey";

-- AlterTable
ALTER TABLE "EmailEnvelope" ALTER COLUMN "fromId" DROP NOT NULL,
ALTER COLUMN "replyToId" DROP NOT NULL;

-- AlterTable
ALTER TABLE "EmailTemplate" ALTER COLUMN "authorizationUserId" DROP NOT NULL,
ALTER COLUMN "envelopeId" DROP NOT NULL,
ALTER COLUMN "createdAt" SET NOT NULL,
ALTER COLUMN "updatedAt" SET NOT NULL;

-- AddForeignKey
ALTER TABLE "EmailTemplate" ADD CONSTRAINT "EmailTemplate_authorizationUserId_fkey" FOREIGN KEY ("authorizationUserId") REFERENCES "AuthorizationUser"("id") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "EmailTemplate" ADD CONSTRAINT "EmailTemplate_envelopeId_fkey" FOREIGN KEY ("envelopeId") REFERENCES "EmailEnvelope"("id") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "EmailEnvelope" ADD CONSTRAINT "EmailEnvelope_fromId_fkey" FOREIGN KEY ("fromId") REFERENCES "EmailAddress"("id") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "EmailEnvelope" ADD CONSTRAINT "EmailEnvelope_replyToId_fkey" FOREIGN KEY ("replyToId") REFERENCES "EmailAddress"("id") ON DELETE SET NULL ON UPDATE CASCADE;
10 changes: 10 additions & 0 deletions prisma/migrations/20231106191208_iam_required/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
Warnings:
- Made the column `createdBy` on table `EmailTemplate` required. This step will fail if there are existing NULL values in that column.
- Made the column `resourceId` on table `EmailTemplate` required. This step will fail if there are existing NULL values in that column.
*/
-- AlterTable
ALTER TABLE "EmailTemplate" ALTER COLUMN "createdBy" SET NOT NULL,
ALTER COLUMN "resourceId" SET NOT NULL;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "VariableDefinition" ALTER COLUMN "defaultValue" DROP NOT NULL;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "EmailTemplate" ADD COLUMN "description" TEXT NOT NULL DEFAULT '';
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "EmailTemplate" ALTER COLUMN "description" DROP DEFAULT;
3 changes: 3 additions & 0 deletions prisma/migrations/migration_lock.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"
88 changes: 88 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

generator client {
provider = "prisma-client-js"
}

model EmailTemplate {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
description String
content String
verifyReplyTo Boolean?
transformer String?
authorizationUser AuthorizationUser? @relation(fields: [authorizationUserId], references: [id])
authorizationUserId String? @db.Uuid
envelope EmailEnvelope? @relation(fields: [envelopeId], references: [id])
envelopeId String? @db.Uuid
parent EmailTemplate? @relation("EmailTemplateParent", fields: [parentId], references: [id])
parentId String? @db.Uuid
linked EmailTemplate[] @relation("EmailTemplateParent")
variables VariableDefinition[]
// IAM data
createdBy String @db.Uuid
resourceId String @db.Uuid
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

model VariableDefinition {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
name String
description String?
defaultValue String?
isRequired Boolean?
isConstant Boolean?
EmailTemplate EmailTemplate? @relation(fields: [emailTemplateId], references: [id])
emailTemplateId String? @db.Uuid
}

model AuthorizationUser {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
userId String @db.Uuid
// @sf-hide
authorization String
EmailTemplate EmailTemplate[]
}

model EmailEnvelope {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
subject String?
EmailTemplate EmailTemplate[]
from EmailAddress? @relation("FromEnvelopes", fields: [fromId], references: [id])
fromId String? @db.Uuid
replyTo EmailAddress? @relation("ReplyToEnvelopes", fields: [replyToId], references: [id])
replyToId String? @db.Uuid
to EmailAddress[]
}

model EmailAddress {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
value String
type EmailAddressType
ToEnvelopes EmailEnvelope[]
FromEnvelopes EmailEnvelope[] @relation("FromEnvelopes")
ReplyToEnvelopes EmailEnvelope[] @relation("ReplyToEnvelopes")
}

enum EmailAddressType {
EMAIL_ADDRESS
EMAIL_ID
USER_ID
}
26 changes: 24 additions & 2 deletions src/decorators.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { decorator } from "@snek-at/function";
import { requireAdminForResource } from "@snek-functions/jwt";
import { Context, decorator } from "@snek-at/function";
import {
AuthenticationContext,
AuthenticationRequiredError,
requireAdminForResource,
requireAnyAuth,
} from "@snek-functions/jwt";

export const requireAdminOnMailpress = decorator(async (context, args) => {
const ctx = await requireAdminForResource(context, [
Expand All @@ -8,3 +13,20 @@ export const requireAdminOnMailpress = decorator(async (context, args) => {

return ctx;
});

export const optionalAnyAuth = decorator(async (context, args) => {
let ctx: Context<{
auth?: AuthenticationContext["auth"];
multiAuth?: AuthenticationContext["multiAuth"];
}> = context;

try {
ctx = await requireAnyAuth(context, args);
} catch (e) {
if (!(e instanceof AuthenticationRequiredError)) {
throw e;
}
}

return ctx;
});
43 changes: 0 additions & 43 deletions src/email-template-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,24 +79,6 @@ export interface TemplateVariableValues {
}

export class EmailTemplateFactory {
private static templates: TemplateMetadata[] = [];

private static getTemplateMetadata(id: string): TemplateMetadata {
const metadata = EmailTemplateFactory.templates.find(
(metadata) => metadata.id === id
);

if (!metadata) {
throw new TemplateNotFoundError(id);
}

return metadata;
}

private static getAllTemplatesMetadata(): TemplateMetadata[] {
return [...EmailTemplateFactory.templates];
}

private static minifyRenderedTemplate(template: string): string {
const result = minify(template, {
collapseWhitespace: true,
Expand All @@ -112,31 +94,6 @@ export class EmailTemplateFactory {
return result;
}

static createTemplate(id: string, template: EmailTemplate): EmailTemplate {
if (EmailTemplateFactory.templates.some((metadata) => metadata.id === id)) {
throw new TemplateAlreadyExistsError(id);
}

const metadata: TemplateMetadata = {
id,
template,
};

EmailTemplateFactory.templates.push(metadata);

return template;
}

static getTemplate(id: string): EmailTemplate {
return EmailTemplateFactory.getTemplateMetadata(id).template;
}

static getTemplates() {
return EmailTemplateFactory.getAllTemplatesMetadata().map(
(metadata) => metadata.template
);
}

private static getContext(
template: EmailTemplate,
values: TemplateVariableValues
Expand Down
Loading

0 comments on commit cd50129

Please sign in to comment.