diff --git a/apps/api/src/domain/generated/campaignApplication/dto/connect-campaignApplication.dto.ts b/apps/api/src/domain/generated/campaignApplication/dto/connect-campaignApplication.dto.ts new file mode 100644 index 000000000..076c452d9 --- /dev/null +++ b/apps/api/src/domain/generated/campaignApplication/dto/connect-campaignApplication.dto.ts @@ -0,0 +1,4 @@ +export class ConnectCampaignApplicationDto { + id?: string + organizerEmail?: string +} diff --git a/apps/api/src/domain/generated/campaignApplication/dto/create-campaignApplication.dto.ts b/apps/api/src/domain/generated/campaignApplication/dto/create-campaignApplication.dto.ts new file mode 100644 index 000000000..64443e2fc --- /dev/null +++ b/apps/api/src/domain/generated/campaignApplication/dto/create-campaignApplication.dto.ts @@ -0,0 +1,22 @@ +import { CampaignTypeCategory } from '@prisma/client' +import { ApiProperty } from '@nestjs/swagger' + +export class CreateCampaignApplicationDto { + organizerName: string + organizerEmail?: string + organizerPhone?: string + beneficiary: string + organizerBeneficiaryRel: string + campaignName: string + goal: string + history?: string + amount: string + description?: string + campaignGuarantee?: string + otherFinanceSources?: string + otherNotes?: string + @ApiProperty({ enum: CampaignTypeCategory }) + category?: CampaignTypeCategory + ticketURL?: string + archived?: boolean +} diff --git a/apps/api/src/domain/generated/campaignApplication/dto/index.ts b/apps/api/src/domain/generated/campaignApplication/dto/index.ts new file mode 100644 index 000000000..9ddb125ab --- /dev/null +++ b/apps/api/src/domain/generated/campaignApplication/dto/index.ts @@ -0,0 +1,3 @@ +export * from './connect-campaignApplication.dto' +export * from './create-campaignApplication.dto' +export * from './update-campaignApplication.dto' diff --git a/apps/api/src/domain/generated/campaignApplication/dto/update-campaignApplication.dto.ts b/apps/api/src/domain/generated/campaignApplication/dto/update-campaignApplication.dto.ts new file mode 100644 index 000000000..f80c13dc6 --- /dev/null +++ b/apps/api/src/domain/generated/campaignApplication/dto/update-campaignApplication.dto.ts @@ -0,0 +1,22 @@ +import { CampaignTypeCategory } from '@prisma/client' +import { ApiProperty } from '@nestjs/swagger' + +export class UpdateCampaignApplicationDto { + organizerName?: string + organizerEmail?: string + organizerPhone?: string + beneficiary?: string + organizerBeneficiaryRel?: string + campaignName?: string + goal?: string + history?: string + amount?: string + description?: string + campaignGuarantee?: string + otherFinanceSources?: string + otherNotes?: string + @ApiProperty({ enum: CampaignTypeCategory }) + category?: CampaignTypeCategory + ticketURL?: string + archived?: boolean +} diff --git a/apps/api/src/domain/generated/campaignApplication/entities/campaignApplication.entity.ts b/apps/api/src/domain/generated/campaignApplication/entities/campaignApplication.entity.ts new file mode 100644 index 000000000..db325d737 --- /dev/null +++ b/apps/api/src/domain/generated/campaignApplication/entities/campaignApplication.entity.ts @@ -0,0 +1,29 @@ +import { CampaignApplicationState, CampaignTypeCategory } from '@prisma/client' +import { Organizer } from '../../organizer/entities/organizer.entity' +import { CampaignApplicationFile } from '../../campaignApplicationFile/entities/campaignApplicationFile.entity' + +export class CampaignApplication { + id: string + createdAt: Date + updatedAt: Date | null + organizerId: string | null + organizer?: Organizer | null + organizerName: string + organizerEmail: string | null + organizerPhone: string | null + beneficiary: string + organizerBeneficiaryRel: string + campaignName: string + goal: string + history: string | null + amount: string + description: string | null + documents?: CampaignApplicationFile[] + campaignGuarantee: string | null + otherFinanceSources: string | null + otherNotes: string | null + state: CampaignApplicationState + category: CampaignTypeCategory | null + ticketURL: string | null + archived: boolean | null +} diff --git a/apps/api/src/domain/generated/campaignApplication/entities/index.ts b/apps/api/src/domain/generated/campaignApplication/entities/index.ts new file mode 100644 index 000000000..179072066 --- /dev/null +++ b/apps/api/src/domain/generated/campaignApplication/entities/index.ts @@ -0,0 +1 @@ +export * from './campaignApplication.entity' diff --git a/apps/api/src/domain/generated/campaignApplicationFile/dto/connect-campaignApplicationFile.dto.ts b/apps/api/src/domain/generated/campaignApplicationFile/dto/connect-campaignApplicationFile.dto.ts new file mode 100644 index 000000000..7408bee03 --- /dev/null +++ b/apps/api/src/domain/generated/campaignApplicationFile/dto/connect-campaignApplicationFile.dto.ts @@ -0,0 +1,3 @@ +export class ConnectCampaignApplicationFileDto { + id: string +} diff --git a/apps/api/src/domain/generated/campaignApplicationFile/dto/create-campaignApplicationFile.dto.ts b/apps/api/src/domain/generated/campaignApplicationFile/dto/create-campaignApplicationFile.dto.ts new file mode 100644 index 000000000..854d351ce --- /dev/null +++ b/apps/api/src/domain/generated/campaignApplicationFile/dto/create-campaignApplicationFile.dto.ts @@ -0,0 +1,11 @@ +import { CampaignApplicationFileRole } from '@prisma/client' +import { ApiProperty } from '@nestjs/swagger' + +export class CreateCampaignApplicationFileDto { + filename: string + campaignApplicationId: string + personId: string + mimetype: string + @ApiProperty({ enum: CampaignApplicationFileRole }) + role: CampaignApplicationFileRole +} diff --git a/apps/api/src/domain/generated/campaignApplicationFile/dto/index.ts b/apps/api/src/domain/generated/campaignApplicationFile/dto/index.ts new file mode 100644 index 000000000..85562986f --- /dev/null +++ b/apps/api/src/domain/generated/campaignApplicationFile/dto/index.ts @@ -0,0 +1,3 @@ +export * from './connect-campaignApplicationFile.dto' +export * from './create-campaignApplicationFile.dto' +export * from './update-campaignApplicationFile.dto' diff --git a/apps/api/src/domain/generated/campaignApplicationFile/dto/update-campaignApplicationFile.dto.ts b/apps/api/src/domain/generated/campaignApplicationFile/dto/update-campaignApplicationFile.dto.ts new file mode 100644 index 000000000..247faad15 --- /dev/null +++ b/apps/api/src/domain/generated/campaignApplicationFile/dto/update-campaignApplicationFile.dto.ts @@ -0,0 +1,11 @@ +import { CampaignApplicationFileRole } from '@prisma/client' +import { ApiProperty } from '@nestjs/swagger' + +export class UpdateCampaignApplicationFileDto { + filename?: string + campaignApplicationId?: string + personId?: string + mimetype?: string + @ApiProperty({ enum: CampaignApplicationFileRole }) + role?: CampaignApplicationFileRole +} diff --git a/apps/api/src/domain/generated/campaignApplicationFile/entities/campaignApplicationFile.entity.ts b/apps/api/src/domain/generated/campaignApplicationFile/entities/campaignApplicationFile.entity.ts new file mode 100644 index 000000000..314a52a70 --- /dev/null +++ b/apps/api/src/domain/generated/campaignApplicationFile/entities/campaignApplicationFile.entity.ts @@ -0,0 +1,12 @@ +import { CampaignApplicationFileRole } from '@prisma/client' +import { CampaignApplication } from '../../campaignApplication/entities/campaignApplication.entity' + +export class CampaignApplicationFile { + id: string + filename: string + campaignApplicationId: string + personId: string + mimetype: string + role: CampaignApplicationFileRole + campaignApplication?: CampaignApplication[] +} diff --git a/apps/api/src/domain/generated/campaignApplicationFile/entities/index.ts b/apps/api/src/domain/generated/campaignApplicationFile/entities/index.ts new file mode 100644 index 000000000..8b4c48a7f --- /dev/null +++ b/apps/api/src/domain/generated/campaignApplicationFile/entities/index.ts @@ -0,0 +1 @@ +export * from './campaignApplicationFile.entity' diff --git a/apps/api/src/domain/generated/organizer/entities/organizer.entity.ts b/apps/api/src/domain/generated/organizer/entities/organizer.entity.ts index 0380fd930..bb0874863 100644 --- a/apps/api/src/domain/generated/organizer/entities/organizer.entity.ts +++ b/apps/api/src/domain/generated/organizer/entities/organizer.entity.ts @@ -1,6 +1,7 @@ import { Person } from '../../person/entities/person.entity' import { Beneficiary } from '../../beneficiary/entities/beneficiary.entity' import { Campaign } from '../../campaign/entities/campaign.entity' +import { CampaignApplication } from '../../campaignApplication/entities/campaignApplication.entity' export class Organizer { id: string @@ -10,4 +11,5 @@ export class Organizer { person?: Person beneficiaries?: Beneficiary[] campaigns?: Campaign[] + campaignApplication?: CampaignApplication[] } diff --git a/migrations/20240615135940_add_campaign_application/migration.sql b/migrations/20240615135940_add_campaign_application/migration.sql new file mode 100644 index 000000000..5b4a293a1 --- /dev/null +++ b/migrations/20240615135940_add_campaign_application/migration.sql @@ -0,0 +1,68 @@ +-- CreateEnum +CREATE TYPE "CampaignApplicationState" AS ENUM ('review', 'requestInfo', 'forCommitteeReview', 'approved', 'denied', 'abandoned'); + +-- CreateEnum +CREATE TYPE "CampaignApplicationFileRole" AS ENUM ('document', 'image'); + +-- CreateTable +CREATE TABLE "campaign_applications" ( + "id" UUID NOT NULL DEFAULT gen_random_uuid(), + "created_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMPTZ(6), + "organizer_id" UUID NOT NULL, + "organizer_name" VARCHAR(200) NOT NULL, + "organizer_email" CITEXT, + "organizer_phone" VARCHAR(50), + "beneficiary" VARCHAR(1500) NOT NULL, + "organizer_beneficiary_relationship" TEXT NOT NULL, + "campaign_name" VARCHAR(200) NOT NULL, + "goal" TEXT NOT NULL, + "history" TEXT, + "amount" VARCHAR(200) NOT NULL, + "description" TEXT, + "campaignGuarantee" VARCHAR(500), + "otherFinanceSources" TEXT, + "otherNotes" TEXT, + "state" "CampaignApplicationState" NOT NULL DEFAULT 'review', + "category" "campaign_type_category" DEFAULT 'others', + "ticketURL" VARCHAR(500), + "archived" BOOLEAN DEFAULT false, + + CONSTRAINT "campaign_applications_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "campaign_application_files" ( + "id" UUID NOT NULL DEFAULT gen_random_uuid(), + "filename" VARCHAR(200) NOT NULL, + "campaign_application_id" UUID NOT NULL, + "person_id" UUID NOT NULL, + "mimetype" VARCHAR(100) NOT NULL, + "role" "CampaignApplicationFileRole" NOT NULL, + + CONSTRAINT "campaign_application_files_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "_CampaignApplicationToCampaignApplicationFile" ( + "A" UUID NOT NULL, + "B" UUID NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "campaign_applications_organizer_email_key" ON "campaign_applications"("organizer_email"); + +-- CreateIndex +CREATE UNIQUE INDEX "_CampaignApplicationToCampaignApplicationFile_AB_unique" ON "_CampaignApplicationToCampaignApplicationFile"("A", "B"); + +-- CreateIndex +CREATE INDEX "_CampaignApplicationToCampaignApplicationFile_B_index" ON "_CampaignApplicationToCampaignApplicationFile"("B"); + +-- AddForeignKey +ALTER TABLE "campaign_applications" ADD CONSTRAINT "campaign_applications_organizer_id_fkey" FOREIGN KEY ("organizer_id") REFERENCES "organizers"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_CampaignApplicationToCampaignApplicationFile" ADD CONSTRAINT "_CampaignApplicationToCampaignApplicationFile_A_fkey" FOREIGN KEY ("A") REFERENCES "campaign_applications"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_CampaignApplicationToCampaignApplicationFile" ADD CONSTRAINT "_CampaignApplicationToCampaignApplicationFile_B_fkey" FOREIGN KEY ("B") REFERENCES "campaign_application_files"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/podkrepi.dbml b/podkrepi.dbml index f16494f66..30dc8acd9 100644 --- a/podkrepi.dbml +++ b/podkrepi.dbml @@ -88,6 +88,7 @@ Table organizers { person people [not null] beneficiaries beneficiaries [not null] campaigns campaigns [not null] + campaignApplication campaign_applications [not null] Note: 'Organizer is the person who manages the campaign on behalf of the Beneficiary' } @@ -575,6 +576,42 @@ Table bank_transactions_files { personId String [not null] } +Table campaign_applications { + id String [pk] + createdAt DateTime [default: `now()`, not null] + updatedAt DateTime + organizerId String [not null] + organizer organizers + organizerName String [not null] + organizerEmail String [unique] + organizerPhone String + beneficiary String [not null] + organizerBeneficiaryRel String [not null] + campaignName String [not null] + goal String [not null] + history String + amount String [not null] + description String + documents campaign_application_files [not null] + campaignGuarantee String + otherFinanceSources String + otherNotes String + state CampaignApplicationState [not null, default: 'review'] + category CampaignTypeCategory [default: 'others'] + ticketURL String + archived Boolean [default: false] +} + +Table campaign_application_files { + id String [pk] + filename String [not null] + campaignApplicationId String [not null] + personId String [not null] + mimetype String [not null] + role CampaignApplicationFileRole [not null] + campaignApplication campaign_applications [not null] +} + Enum BeneficiaryType { individual company @@ -819,6 +856,20 @@ Enum EmailType { raised100 } +Enum CampaignApplicationState { + review + requestInfo + forCommitteeReview + approved + denied + abandoned +} + +Enum CampaignApplicationFileRole { + document + image +} + Ref: people.companyId - companies.id Ref: affiliates.companyId - companies.id @@ -933,4 +984,6 @@ Ref: expense_files.expenseId > expenses.id Ref: expense_files.uploaderId > people.id -Ref: documents.ownerId > people.id \ No newline at end of file +Ref: documents.ownerId > people.id + +Ref: campaign_applications.organizerId > organizers.id \ No newline at end of file diff --git a/schema.prisma b/schema.prisma index 89dc2b28a..131271cab 100644 --- a/schema.prisma +++ b/schema.prisma @@ -115,13 +115,14 @@ model Affiliate { /// Organizer is the person who manages the campaign on behalf of the Beneficiary model Organizer { - id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid - personId String @unique @map("person_id") @db.Uuid - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6) - person Person @relation(fields: [personId], references: [id]) - beneficiaries Beneficiary[] - campaigns Campaign[] + id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid + personId String @unique @map("person_id") @db.Uuid + createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6) + person Person @relation(fields: [personId], references: [id]) + beneficiaries Beneficiary[] + campaigns Campaign[] + campaignApplication CampaignApplication[] @@map("organizers") } @@ -1004,3 +1005,64 @@ enum EmailType { @@map("email_type") } + +/// CampaignApplication represents a request for a new campaign - it is not a Campaign yet and has to proove it needs to be +model CampaignApplication { + id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid + createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6) + + // organizer editable fields + // need to be logged in to create a campaign application + organizerId String @map("organizer_id") @db.Uuid + organizer Organizer? @relation(fields: [organizerId], references: [id]) + organizerName String @map("organizer_name") @db.VarChar(200) + organizerEmail String? @unique @map("organizer_email") @db.Citext + organizerPhone String? @map("organizer_phone") @db.VarChar(50) + // will create a beneficiary after approve of campaign application + beneficiary String @db.VarChar(1500) + organizerBeneficiaryRel String @map("organizer_beneficiary_relationship") @db.Text + campaignName String @map("campaign_name") @db.VarChar(200) + goal String @db.Text + history String? @db.Text + amount String @db.VarChar(200) + description String? @db.Text + documents CampaignApplicationFile[] + campaignGuarantee String? @db.VarChar(500) + otherFinanceSources String? @db.Text + otherNotes String? @db.Text + + // operator editable fields + state CampaignApplicationState @default(review) + category CampaignTypeCategory? @default(others) + ticketURL String? @db.VarChar(500) + archived Boolean? @default(false) + + @@map("campaign_applications") +} + +enum CampaignApplicationState { + review + requestInfo + forCommitteeReview + approved + denied + abandoned +} + +model CampaignApplicationFile { + id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid + filename String @db.VarChar(200) + campaignApplicationId String @map("campaign_application_id") @db.Uuid + personId String @map("person_id") @db.Uuid + mimetype String @db.VarChar(100) + role CampaignApplicationFileRole + campaignApplication CampaignApplication[] + + @@map("campaign_application_files") +} + +enum CampaignApplicationFileRole { + document + image +}