diff --git a/apps/backend/src/api/routes/settings.controller.ts b/apps/backend/src/api/routes/settings.controller.ts index bcc5044e7..c18c96378 100644 --- a/apps/backend/src/api/routes/settings.controller.ts +++ b/apps/backend/src/api/routes/settings.controller.ts @@ -1,19 +1,25 @@ import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common'; import { GetOrgFromRequest } from '@gitroom/nestjs-libraries/user/org.from.request'; -import { Organization } from '@prisma/client'; +import { Organization, User } from '@prisma/client'; import { StarsService } from '@gitroom/nestjs-libraries/database/prisma/stars/stars.service'; import { CheckPolicies } from '@gitroom/backend/services/auth/permissions/permissions.ability'; import { OrganizationService } from '@gitroom/nestjs-libraries/database/prisma/organizations/organization.service'; import { AddTeamMemberDto } from '@gitroom/nestjs-libraries/dtos/settings/add.team.member.dto'; import { ApiTags } from '@nestjs/swagger'; -import { AuthorizationActions, Sections } from '@gitroom/backend/services/auth/permissions/permission.exception.class'; +import { + AuthorizationActions, + Sections, +} from '@gitroom/backend/services/auth/permissions/permission.exception.class'; +import { UsersService } from '@gitroom/nestjs-libraries/database/prisma/users/users.service'; +import { GetUserFromRequest } from '@gitroom/nestjs-libraries/user/user.from.request'; @ApiTags('Settings') @Controller('/settings') export class SettingsController { constructor( private _starsService: StarsService, - private _organizationService: OrganizationService + private _organizationService: OrganizationService, + private _usersService: UsersService ) {} @Get('/github') @@ -133,4 +139,25 @@ export class SettingsController { ) { return this._organizationService.deleteTeamMember(org, id); } + + @Get('/email-notifications') + async getEmailNotifications(@GetUserFromRequest() user: User) { + const userValue = await this._usersService.getEmailNotifications(user.id); + if (!userValue) { + return { enabled: false }; + } + return { enabled: userValue.emailNotifications }; + } + + @Post('/email-notifications') + @CheckPolicies( + [AuthorizationActions.Create, Sections.TEAM_MEMBERS], + [AuthorizationActions.Create, Sections.ADMIN] + ) + async updateEmailNotifications( + @GetUserFromRequest() user: User, + @Body('enabled') enabled: boolean + ) { + return this._usersService.updateEmailNotifications(user.id, enabled); + } } diff --git a/apps/frontend/src/components/layout/settings.component.tsx b/apps/frontend/src/components/layout/settings.component.tsx index ac43dc8b5..1b1af46df 100644 --- a/apps/frontend/src/components/layout/settings.component.tsx +++ b/apps/frontend/src/components/layout/settings.component.tsx @@ -30,6 +30,7 @@ import { SignaturesComponent } from '@gitroom/frontend/components/settings/signa import { Autopost } from '@gitroom/frontend/components/autopost/autopost'; import { useT } from '@gitroom/react/translation/get.transation.service.client'; import { SVGLine } from '@gitroom/frontend/components/launches/launches.component'; +import { EmailNotificationsComponent } from '../settings/email.notifications.component'; export const SettingsPopup: FC<{ getRef?: Ref; }> = (props) => { @@ -115,6 +116,7 @@ export const SettingsPopup: FC<{ if (user?.tier?.public_api && isGeneral && showLogout) { arr.push({ tab: 'api', label: t('public_api', 'Public API') }); } + arr.push({ tab: 'notifications', label: t('email_notifications', 'Notifications') }); return arr; }, [user, isGeneral, showLogout, t]); @@ -206,6 +208,12 @@ export const SettingsPopup: FC<{ )} + + {tab === 'notifications' && ( +
+ +
+ )} diff --git a/apps/frontend/src/components/settings/email.notifications.component.tsx b/apps/frontend/src/components/settings/email.notifications.component.tsx new file mode 100644 index 000000000..04f4aef72 --- /dev/null +++ b/apps/frontend/src/components/settings/email.notifications.component.tsx @@ -0,0 +1,76 @@ +import React, { FC, useCallback } from 'react'; +import { useFetch } from '@gitroom/helpers/utils/custom.fetch'; +import useSWR from 'swr'; +import { Button } from '@gitroom/react/form/button'; +import { useToaster } from '@gitroom/react/toaster/toaster'; +import { useT } from '@gitroom/react/translation/get.transation.service.client'; + +export const EmailNotificationsComponent: FC = () => { + const fetch = useFetch(); + const toast = useToaster(); + const t = useT(); + + const load = useCallback(async () => { + return (await fetch('/settings/email-notifications')).json(); + }, []); + + const { data, mutate } = useSWR('email-notifications', load); + + const toggle = useCallback(async () => { + try { + const res = await fetch('/settings/email-notifications', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + enabled: !data?.enabled, + }), + }); + + if (!res.ok) throw new Error('Failed to update'); + + toast.show( + t( + 'email_notifications_updated', + 'Email notifications updated successfully' + ), + 'success' + ); + mutate(); + } catch (err) { + toast.show( + t('email_notifications_failed', 'Failed to update email notifications'), + 'warning' + ); + } + }, [data, mutate]); + + return ( +
+

+ {t('email_notifications', 'Email Notifications')} +

+
+ {t( + 'control_email_settings', + 'Enable or disable whether you want to receive email notifications.' + )} +
+
+
+
+ {t('receive_emails', 'Receive emails?')} +
+
+ {t( + 'receive_emails_description', + 'You’ll be notified by email when necessary updates occur.' + )} +
+
+ +
+
+ ); +}; diff --git a/docker-compose.dev.yaml b/docker-compose.dev.yaml index e0f060844..c2543ffee 100644 --- a/docker-compose.dev.yaml +++ b/docker-compose.dev.yaml @@ -5,7 +5,7 @@ services: postiz-postgres: # ref: https://hub.docker.com/_/postgres - image: postgres:17-alpine # 17.0 + image: postgres:15 container_name: postiz-postgres restart: always environment: diff --git a/libraries/nestjs-libraries/src/database/prisma/migrations/20250728004456_init/migration.sql b/libraries/nestjs-libraries/src/database/prisma/migrations/20250728004456_init/migration.sql new file mode 100644 index 000000000..6d56927b2 --- /dev/null +++ b/libraries/nestjs-libraries/src/database/prisma/migrations/20250728004456_init/migration.sql @@ -0,0 +1,979 @@ +-- CreateEnum +CREATE TYPE "OrderStatus" AS ENUM ('PENDING', 'ACCEPTED', 'CANCELED', 'COMPLETED'); + +-- CreateEnum +CREATE TYPE "From" AS ENUM ('BUYER', 'SELLER'); + +-- CreateEnum +CREATE TYPE "State" AS ENUM ('QUEUE', 'PUBLISHED', 'ERROR', 'DRAFT'); + +-- CreateEnum +CREATE TYPE "SubscriptionTier" AS ENUM ('STANDARD', 'PRO', 'TEAM', 'ULTIMATE'); + +-- CreateEnum +CREATE TYPE "Period" AS ENUM ('MONTHLY', 'YEARLY'); + +-- CreateEnum +CREATE TYPE "Provider" AS ENUM ('LOCAL', 'GITHUB', 'GOOGLE', 'FARCASTER', 'WALLET', 'GENERIC'); + +-- CreateEnum +CREATE TYPE "Role" AS ENUM ('SUPERADMIN', 'ADMIN', 'USER'); + +-- CreateEnum +CREATE TYPE "APPROVED_SUBMIT_FOR_ORDER" AS ENUM ('NO', 'WAITING_CONFIRMATION', 'YES'); + +-- CreateTable +CREATE TABLE "Organization" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT, + "apiKey" TEXT, + "paymentId" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "allowTrial" BOOLEAN NOT NULL DEFAULT false, + "isTrailing" BOOLEAN NOT NULL DEFAULT false, + + CONSTRAINT "Organization_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Tags" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "color" TEXT NOT NULL, + "orgId" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Tags_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "TagsPosts" ( + "postId" TEXT NOT NULL, + "tagId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "TagsPosts_pkey" PRIMARY KEY ("postId","tagId") +); + +-- CreateTable +CREATE TABLE "User" ( + "id" TEXT NOT NULL, + "email" TEXT NOT NULL, + "password" TEXT, + "providerName" "Provider" NOT NULL, + "name" TEXT, + "lastName" TEXT, + "isSuperAdmin" BOOLEAN NOT NULL DEFAULT false, + "bio" TEXT, + "audience" INTEGER NOT NULL DEFAULT 0, + "pictureId" TEXT, + "providerId" TEXT, + "timezone" INTEGER NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "lastReadNotifications" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "inviteId" TEXT, + "activated" BOOLEAN NOT NULL DEFAULT true, + "marketplace" BOOLEAN NOT NULL DEFAULT true, + "account" TEXT, + "connectedAccount" BOOLEAN NOT NULL DEFAULT false, + "lastOnline" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "ip" TEXT, + "agent" TEXT, + "emailNotifications" BOOLEAN NOT NULL DEFAULT true, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "UsedCodes" ( + "id" TEXT NOT NULL, + "code" TEXT NOT NULL, + "orgId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "UsedCodes_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "UserOrganization" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "disabled" BOOLEAN NOT NULL DEFAULT false, + "role" "Role" NOT NULL DEFAULT 'USER', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "UserOrganization_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "GitHub" ( + "id" TEXT NOT NULL, + "login" TEXT, + "name" TEXT, + "token" TEXT NOT NULL, + "jobId" TEXT, + "organizationId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "GitHub_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Trending" ( + "id" TEXT NOT NULL, + "trendingList" TEXT NOT NULL, + "language" TEXT, + "hash" TEXT NOT NULL, + "date" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Trending_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "TrendingLog" ( + "id" TEXT NOT NULL, + "language" TEXT, + "date" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "TrendingLog_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ItemUser" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "key" TEXT NOT NULL, + + CONSTRAINT "ItemUser_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Star" ( + "id" TEXT NOT NULL, + "stars" INTEGER NOT NULL, + "totalStars" INTEGER NOT NULL, + "forks" INTEGER NOT NULL, + "totalForks" INTEGER NOT NULL, + "login" TEXT NOT NULL, + "date" DATE NOT NULL DEFAULT CURRENT_TIMESTAMP, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Star_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Media" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "path" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "thumbnail" TEXT, + "thumbnailTimestamp" INTEGER, + "alt" TEXT, + "fileSize" INTEGER NOT NULL DEFAULT 0, + "type" TEXT NOT NULL DEFAULT 'image', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "Media_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "SocialMediaAgency" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "name" TEXT NOT NULL, + "logoId" TEXT, + "website" TEXT, + "slug" TEXT, + "facebook" TEXT, + "instagram" TEXT, + "twitter" TEXT, + "linkedIn" TEXT, + "youtube" TEXT, + "tiktok" TEXT, + "otherSocialMedia" TEXT, + "shortDescription" TEXT NOT NULL, + "description" TEXT NOT NULL, + "approved" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "SocialMediaAgency_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "SocialMediaAgencyNiche" ( + "agencyId" TEXT NOT NULL, + "niche" TEXT NOT NULL, + + CONSTRAINT "SocialMediaAgencyNiche_pkey" PRIMARY KEY ("agencyId","niche") +); + +-- CreateTable +CREATE TABLE "Credits" ( + "id" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "credits" INTEGER NOT NULL, + "type" TEXT NOT NULL DEFAULT 'ai_images', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Credits_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Subscription" ( + "id" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "subscriptionTier" "SubscriptionTier" NOT NULL, + "identifier" TEXT, + "cancelAt" TIMESTAMP(3), + "period" "Period" NOT NULL, + "totalChannels" INTEGER NOT NULL, + "isLifetime" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "Subscription_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Customer" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "orgId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "Customer_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Integration" ( + "id" TEXT NOT NULL, + "internalId" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "name" TEXT NOT NULL, + "picture" TEXT, + "providerIdentifier" TEXT NOT NULL, + "type" TEXT NOT NULL, + "token" TEXT NOT NULL, + "disabled" BOOLEAN NOT NULL DEFAULT false, + "tokenExpiration" TIMESTAMP(3), + "refreshToken" TEXT, + "profile" TEXT, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3), + "inBetweenSteps" BOOLEAN NOT NULL DEFAULT false, + "refreshNeeded" BOOLEAN NOT NULL DEFAULT false, + "postingTimes" TEXT NOT NULL DEFAULT '[{"time":120}, {"time":400}, {"time":700}]', + "customInstanceDetails" TEXT, + "customerId" TEXT, + "rootInternalId" TEXT, + "additionalSettings" TEXT DEFAULT '[]', + + CONSTRAINT "Integration_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Signatures" ( + "id" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "content" TEXT NOT NULL, + "autoAdd" BOOLEAN NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "Signatures_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Comments" ( + "id" TEXT NOT NULL, + "content" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "postId" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "Comments_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Post" ( + "id" TEXT NOT NULL, + "state" "State" NOT NULL DEFAULT 'QUEUE', + "publishDate" TIMESTAMP(3) NOT NULL, + "organizationId" TEXT NOT NULL, + "integrationId" TEXT NOT NULL, + "content" TEXT NOT NULL, + "group" TEXT NOT NULL, + "title" TEXT, + "description" TEXT, + "parentPostId" TEXT, + "releaseId" TEXT, + "releaseURL" TEXT, + "settings" TEXT, + "image" TEXT, + "submittedForOrderId" TEXT, + "submittedForOrganizationId" TEXT, + "approvedSubmitForOrder" "APPROVED_SUBMIT_FOR_ORDER" NOT NULL DEFAULT 'NO', + "lastMessageId" TEXT, + "intervalInDays" INTEGER, + "error" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "Post_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Notifications" ( + "id" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "content" TEXT NOT NULL, + "link" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "Notifications_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "MessagesGroup" ( + "id" TEXT NOT NULL, + "buyerOrganizationId" TEXT NOT NULL, + "buyerId" TEXT NOT NULL, + "sellerId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "MessagesGroup_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "PayoutProblems" ( + "id" TEXT NOT NULL, + "status" TEXT NOT NULL, + "orderId" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "postId" TEXT, + "amount" INTEGER NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "PayoutProblems_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Orders" ( + "id" TEXT NOT NULL, + "buyerId" TEXT NOT NULL, + "sellerId" TEXT NOT NULL, + "status" "OrderStatus" NOT NULL, + "messageGroupId" TEXT NOT NULL, + "captureId" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Orders_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "OrderItems" ( + "id" TEXT NOT NULL, + "orderId" TEXT NOT NULL, + "integrationId" TEXT NOT NULL, + "quantity" INTEGER NOT NULL, + "price" INTEGER NOT NULL, + + CONSTRAINT "OrderItems_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Messages" ( + "id" TEXT NOT NULL, + "from" "From" NOT NULL, + "content" TEXT, + "groupId" TEXT NOT NULL, + "special" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "Messages_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Plugs" ( + "id" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "plugFunction" TEXT NOT NULL, + "data" TEXT NOT NULL, + "integrationId" TEXT NOT NULL, + "activated" BOOLEAN NOT NULL DEFAULT true, + + CONSTRAINT "Plugs_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ExisingPlugData" ( + "id" TEXT NOT NULL, + "integrationId" TEXT NOT NULL, + "methodName" TEXT NOT NULL, + "value" TEXT NOT NULL, + + CONSTRAINT "ExisingPlugData_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "PopularPosts" ( + "id" TEXT NOT NULL, + "category" TEXT NOT NULL, + "topic" TEXT NOT NULL, + "content" TEXT NOT NULL, + "hook" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "PopularPosts_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "IntegrationsWebhooks" ( + "integrationId" TEXT NOT NULL, + "webhookId" TEXT NOT NULL, + + CONSTRAINT "IntegrationsWebhooks_pkey" PRIMARY KEY ("integrationId","webhookId") +); + +-- CreateTable +CREATE TABLE "Webhooks" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "url" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Webhooks_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "AutoPost" ( + "id" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "title" TEXT NOT NULL, + "content" TEXT, + "onSlot" BOOLEAN NOT NULL, + "syncLast" BOOLEAN NOT NULL, + "url" TEXT NOT NULL, + "lastUrl" TEXT NOT NULL, + "active" BOOLEAN NOT NULL, + "addPicture" BOOLEAN NOT NULL, + "generateContent" BOOLEAN NOT NULL, + "integrations" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "AutoPost_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Sets" ( + "id" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "name" TEXT NOT NULL, + "content" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Sets_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ThirdParty" ( + "id" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "identifier" TEXT NOT NULL, + "name" TEXT NOT NULL, + "internalId" TEXT NOT NULL, + "apiKey" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3), + + CONSTRAINT "ThirdParty_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Errors" ( + "id" TEXT NOT NULL, + "message" TEXT NOT NULL, + "body" TEXT NOT NULL DEFAULT '{}', + "platform" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "postId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Errors_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "Tags_orgId_idx" ON "Tags"("orgId"); + +-- CreateIndex +CREATE INDEX "Tags_deletedAt_idx" ON "Tags"("deletedAt"); + +-- CreateIndex +CREATE UNIQUE INDEX "TagsPosts_postId_tagId_key" ON "TagsPosts"("postId", "tagId"); + +-- CreateIndex +CREATE INDEX "User_lastReadNotifications_idx" ON "User"("lastReadNotifications"); + +-- CreateIndex +CREATE INDEX "User_inviteId_idx" ON "User"("inviteId"); + +-- CreateIndex +CREATE INDEX "User_account_idx" ON "User"("account"); + +-- CreateIndex +CREATE INDEX "User_lastOnline_idx" ON "User"("lastOnline"); + +-- CreateIndex +CREATE INDEX "User_pictureId_idx" ON "User"("pictureId"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_providerName_key" ON "User"("email", "providerName"); + +-- CreateIndex +CREATE INDEX "UsedCodes_code_idx" ON "UsedCodes"("code"); + +-- CreateIndex +CREATE INDEX "UserOrganization_disabled_idx" ON "UserOrganization"("disabled"); + +-- CreateIndex +CREATE UNIQUE INDEX "UserOrganization_userId_organizationId_key" ON "UserOrganization"("userId", "organizationId"); + +-- CreateIndex +CREATE INDEX "GitHub_login_idx" ON "GitHub"("login"); + +-- CreateIndex +CREATE INDEX "GitHub_organizationId_idx" ON "GitHub"("organizationId"); + +-- CreateIndex +CREATE INDEX "Trending_hash_idx" ON "Trending"("hash"); + +-- CreateIndex +CREATE UNIQUE INDEX "Trending_language_key" ON "Trending"("language"); + +-- CreateIndex +CREATE INDEX "ItemUser_userId_idx" ON "ItemUser"("userId"); + +-- CreateIndex +CREATE INDEX "ItemUser_key_idx" ON "ItemUser"("key"); + +-- CreateIndex +CREATE UNIQUE INDEX "ItemUser_userId_key_key" ON "ItemUser"("userId", "key"); + +-- CreateIndex +CREATE UNIQUE INDEX "Star_login_date_key" ON "Star"("login", "date"); + +-- CreateIndex +CREATE INDEX "Media_name_idx" ON "Media"("name"); + +-- CreateIndex +CREATE INDEX "Media_organizationId_idx" ON "Media"("organizationId"); + +-- CreateIndex +CREATE INDEX "Media_type_idx" ON "Media"("type"); + +-- CreateIndex +CREATE UNIQUE INDEX "SocialMediaAgency_userId_key" ON "SocialMediaAgency"("userId"); + +-- CreateIndex +CREATE INDEX "SocialMediaAgency_userId_idx" ON "SocialMediaAgency"("userId"); + +-- CreateIndex +CREATE INDEX "SocialMediaAgency_deletedAt_idx" ON "SocialMediaAgency"("deletedAt"); + +-- CreateIndex +CREATE INDEX "SocialMediaAgency_id_idx" ON "SocialMediaAgency"("id"); + +-- CreateIndex +CREATE INDEX "Credits_organizationId_idx" ON "Credits"("organizationId"); + +-- CreateIndex +CREATE INDEX "Credits_createdAt_idx" ON "Credits"("createdAt"); + +-- CreateIndex +CREATE UNIQUE INDEX "Subscription_organizationId_key" ON "Subscription"("organizationId"); + +-- CreateIndex +CREATE INDEX "Subscription_organizationId_idx" ON "Subscription"("organizationId"); + +-- CreateIndex +CREATE INDEX "Subscription_deletedAt_idx" ON "Subscription"("deletedAt"); + +-- CreateIndex +CREATE UNIQUE INDEX "Customer_orgId_name_deletedAt_key" ON "Customer"("orgId", "name", "deletedAt"); + +-- CreateIndex +CREATE INDEX "Integration_rootInternalId_idx" ON "Integration"("rootInternalId"); + +-- CreateIndex +CREATE INDEX "Integration_updatedAt_idx" ON "Integration"("updatedAt"); + +-- CreateIndex +CREATE INDEX "Integration_deletedAt_idx" ON "Integration"("deletedAt"); + +-- CreateIndex +CREATE INDEX "Integration_customerId_idx" ON "Integration"("customerId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Integration_organizationId_internalId_key" ON "Integration"("organizationId", "internalId"); + +-- CreateIndex +CREATE INDEX "Signatures_createdAt_idx" ON "Signatures"("createdAt"); + +-- CreateIndex +CREATE INDEX "Signatures_organizationId_idx" ON "Signatures"("organizationId"); + +-- CreateIndex +CREATE INDEX "Signatures_deletedAt_idx" ON "Signatures"("deletedAt"); + +-- CreateIndex +CREATE INDEX "Comments_createdAt_idx" ON "Comments"("createdAt"); + +-- CreateIndex +CREATE INDEX "Comments_organizationId_idx" ON "Comments"("organizationId"); + +-- CreateIndex +CREATE INDEX "Comments_userId_idx" ON "Comments"("userId"); + +-- CreateIndex +CREATE INDEX "Comments_postId_idx" ON "Comments"("postId"); + +-- CreateIndex +CREATE INDEX "Comments_deletedAt_idx" ON "Comments"("deletedAt"); + +-- CreateIndex +CREATE INDEX "Post_group_idx" ON "Post"("group"); + +-- CreateIndex +CREATE INDEX "Post_deletedAt_idx" ON "Post"("deletedAt"); + +-- CreateIndex +CREATE INDEX "Post_publishDate_idx" ON "Post"("publishDate"); + +-- CreateIndex +CREATE INDEX "Post_state_idx" ON "Post"("state"); + +-- CreateIndex +CREATE INDEX "Post_organizationId_idx" ON "Post"("organizationId"); + +-- CreateIndex +CREATE INDEX "Post_parentPostId_idx" ON "Post"("parentPostId"); + +-- CreateIndex +CREATE INDEX "Post_submittedForOrderId_idx" ON "Post"("submittedForOrderId"); + +-- CreateIndex +CREATE INDEX "Post_intervalInDays_idx" ON "Post"("intervalInDays"); + +-- CreateIndex +CREATE INDEX "Post_approvedSubmitForOrder_idx" ON "Post"("approvedSubmitForOrder"); + +-- CreateIndex +CREATE INDEX "Post_lastMessageId_idx" ON "Post"("lastMessageId"); + +-- CreateIndex +CREATE INDEX "Post_createdAt_idx" ON "Post"("createdAt"); + +-- CreateIndex +CREATE INDEX "Post_updatedAt_idx" ON "Post"("updatedAt"); + +-- CreateIndex +CREATE INDEX "Post_releaseURL_idx" ON "Post"("releaseURL"); + +-- CreateIndex +CREATE INDEX "Post_integrationId_idx" ON "Post"("integrationId"); + +-- CreateIndex +CREATE INDEX "Notifications_createdAt_idx" ON "Notifications"("createdAt"); + +-- CreateIndex +CREATE INDEX "Notifications_organizationId_idx" ON "Notifications"("organizationId"); + +-- CreateIndex +CREATE INDEX "Notifications_deletedAt_idx" ON "Notifications"("deletedAt"); + +-- CreateIndex +CREATE INDEX "MessagesGroup_createdAt_idx" ON "MessagesGroup"("createdAt"); + +-- CreateIndex +CREATE INDEX "MessagesGroup_updatedAt_idx" ON "MessagesGroup"("updatedAt"); + +-- CreateIndex +CREATE INDEX "MessagesGroup_buyerOrganizationId_idx" ON "MessagesGroup"("buyerOrganizationId"); + +-- CreateIndex +CREATE UNIQUE INDEX "MessagesGroup_buyerId_sellerId_key" ON "MessagesGroup"("buyerId", "sellerId"); + +-- CreateIndex +CREATE INDEX "Orders_buyerId_idx" ON "Orders"("buyerId"); + +-- CreateIndex +CREATE INDEX "Orders_sellerId_idx" ON "Orders"("sellerId"); + +-- CreateIndex +CREATE INDEX "Orders_updatedAt_idx" ON "Orders"("updatedAt"); + +-- CreateIndex +CREATE INDEX "Orders_createdAt_idx" ON "Orders"("createdAt"); + +-- CreateIndex +CREATE INDEX "Orders_messageGroupId_idx" ON "Orders"("messageGroupId"); + +-- CreateIndex +CREATE INDEX "OrderItems_orderId_idx" ON "OrderItems"("orderId"); + +-- CreateIndex +CREATE INDEX "OrderItems_integrationId_idx" ON "OrderItems"("integrationId"); + +-- CreateIndex +CREATE INDEX "Messages_groupId_idx" ON "Messages"("groupId"); + +-- CreateIndex +CREATE INDEX "Messages_createdAt_idx" ON "Messages"("createdAt"); + +-- CreateIndex +CREATE INDEX "Messages_deletedAt_idx" ON "Messages"("deletedAt"); + +-- CreateIndex +CREATE INDEX "Plugs_organizationId_idx" ON "Plugs"("organizationId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Plugs_plugFunction_integrationId_key" ON "Plugs"("plugFunction", "integrationId"); + +-- CreateIndex +CREATE UNIQUE INDEX "ExisingPlugData_integrationId_methodName_value_key" ON "ExisingPlugData"("integrationId", "methodName", "value"); + +-- CreateIndex +CREATE INDEX "IntegrationsWebhooks_integrationId_idx" ON "IntegrationsWebhooks"("integrationId"); + +-- CreateIndex +CREATE INDEX "IntegrationsWebhooks_webhookId_idx" ON "IntegrationsWebhooks"("webhookId"); + +-- CreateIndex +CREATE UNIQUE INDEX "IntegrationsWebhooks_integrationId_webhookId_key" ON "IntegrationsWebhooks"("integrationId", "webhookId"); + +-- CreateIndex +CREATE INDEX "Webhooks_organizationId_idx" ON "Webhooks"("organizationId"); + +-- CreateIndex +CREATE INDEX "Webhooks_deletedAt_idx" ON "Webhooks"("deletedAt"); + +-- CreateIndex +CREATE INDEX "AutoPost_deletedAt_idx" ON "AutoPost"("deletedAt"); + +-- CreateIndex +CREATE INDEX "Sets_organizationId_idx" ON "Sets"("organizationId"); + +-- CreateIndex +CREATE INDEX "ThirdParty_organizationId_idx" ON "ThirdParty"("organizationId"); + +-- CreateIndex +CREATE INDEX "ThirdParty_deletedAt_idx" ON "ThirdParty"("deletedAt"); + +-- CreateIndex +CREATE UNIQUE INDEX "ThirdParty_organizationId_internalId_key" ON "ThirdParty"("organizationId", "internalId"); + +-- CreateIndex +CREATE INDEX "Errors_organizationId_idx" ON "Errors"("organizationId"); + +-- CreateIndex +CREATE INDEX "Errors_createdAt_idx" ON "Errors"("createdAt"); + +-- AddForeignKey +ALTER TABLE "Tags" ADD CONSTRAINT "Tags_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TagsPosts" ADD CONSTRAINT "TagsPosts_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TagsPosts" ADD CONSTRAINT "TagsPosts_tagId_fkey" FOREIGN KEY ("tagId") REFERENCES "Tags"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "User" ADD CONSTRAINT "User_pictureId_fkey" FOREIGN KEY ("pictureId") REFERENCES "Media"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UsedCodes" ADD CONSTRAINT "UsedCodes_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UserOrganization" ADD CONSTRAINT "UserOrganization_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UserOrganization" ADD CONSTRAINT "UserOrganization_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "GitHub" ADD CONSTRAINT "GitHub_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ItemUser" ADD CONSTRAINT "ItemUser_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Media" ADD CONSTRAINT "Media_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "SocialMediaAgency" ADD CONSTRAINT "SocialMediaAgency_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "SocialMediaAgency" ADD CONSTRAINT "SocialMediaAgency_logoId_fkey" FOREIGN KEY ("logoId") REFERENCES "Media"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "SocialMediaAgencyNiche" ADD CONSTRAINT "SocialMediaAgencyNiche_agencyId_fkey" FOREIGN KEY ("agencyId") REFERENCES "SocialMediaAgency"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Credits" ADD CONSTRAINT "Credits_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Subscription" ADD CONSTRAINT "Subscription_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Customer" ADD CONSTRAINT "Customer_orgId_fkey" FOREIGN KEY ("orgId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Integration" ADD CONSTRAINT "Integration_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Integration" ADD CONSTRAINT "Integration_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Signatures" ADD CONSTRAINT "Signatures_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Comments" ADD CONSTRAINT "Comments_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Comments" ADD CONSTRAINT "Comments_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Comments" ADD CONSTRAINT "Comments_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Post" ADD CONSTRAINT "Post_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Post" ADD CONSTRAINT "Post_integrationId_fkey" FOREIGN KEY ("integrationId") REFERENCES "Integration"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Post" ADD CONSTRAINT "Post_parentPostId_fkey" FOREIGN KEY ("parentPostId") REFERENCES "Post"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Post" ADD CONSTRAINT "Post_submittedForOrderId_fkey" FOREIGN KEY ("submittedForOrderId") REFERENCES "Orders"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Post" ADD CONSTRAINT "Post_submittedForOrganizationId_fkey" FOREIGN KEY ("submittedForOrganizationId") REFERENCES "Organization"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Post" ADD CONSTRAINT "Post_lastMessageId_fkey" FOREIGN KEY ("lastMessageId") REFERENCES "Messages"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Notifications" ADD CONSTRAINT "Notifications_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MessagesGroup" ADD CONSTRAINT "MessagesGroup_buyerOrganizationId_fkey" FOREIGN KEY ("buyerOrganizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MessagesGroup" ADD CONSTRAINT "MessagesGroup_buyerId_fkey" FOREIGN KEY ("buyerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MessagesGroup" ADD CONSTRAINT "MessagesGroup_sellerId_fkey" FOREIGN KEY ("sellerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "PayoutProblems" ADD CONSTRAINT "PayoutProblems_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "Orders"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "PayoutProblems" ADD CONSTRAINT "PayoutProblems_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "PayoutProblems" ADD CONSTRAINT "PayoutProblems_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Orders" ADD CONSTRAINT "Orders_buyerId_fkey" FOREIGN KEY ("buyerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Orders" ADD CONSTRAINT "Orders_sellerId_fkey" FOREIGN KEY ("sellerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Orders" ADD CONSTRAINT "Orders_messageGroupId_fkey" FOREIGN KEY ("messageGroupId") REFERENCES "MessagesGroup"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "OrderItems" ADD CONSTRAINT "OrderItems_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "Orders"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "OrderItems" ADD CONSTRAINT "OrderItems_integrationId_fkey" FOREIGN KEY ("integrationId") REFERENCES "Integration"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Messages" ADD CONSTRAINT "Messages_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES "MessagesGroup"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Plugs" ADD CONSTRAINT "Plugs_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Plugs" ADD CONSTRAINT "Plugs_integrationId_fkey" FOREIGN KEY ("integrationId") REFERENCES "Integration"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ExisingPlugData" ADD CONSTRAINT "ExisingPlugData_integrationId_fkey" FOREIGN KEY ("integrationId") REFERENCES "Integration"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "IntegrationsWebhooks" ADD CONSTRAINT "IntegrationsWebhooks_integrationId_fkey" FOREIGN KEY ("integrationId") REFERENCES "Integration"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "IntegrationsWebhooks" ADD CONSTRAINT "IntegrationsWebhooks_webhookId_fkey" FOREIGN KEY ("webhookId") REFERENCES "Webhooks"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Webhooks" ADD CONSTRAINT "Webhooks_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AutoPost" ADD CONSTRAINT "AutoPost_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Sets" ADD CONSTRAINT "Sets_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ThirdParty" ADD CONSTRAINT "ThirdParty_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Errors" ADD CONSTRAINT "Errors_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Errors" ADD CONSTRAINT "Errors_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/libraries/nestjs-libraries/src/database/prisma/migrations/migration_lock.toml b/libraries/nestjs-libraries/src/database/prisma/migrations/migration_lock.toml new file mode 100644 index 000000000..044d57cdb --- /dev/null +++ b/libraries/nestjs-libraries/src/database/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (e.g., Git) +provider = "postgresql" diff --git a/libraries/nestjs-libraries/src/database/prisma/notifications/notification.service.ts b/libraries/nestjs-libraries/src/database/prisma/notifications/notification.service.ts index c100e8321..04fd75b56 100644 --- a/libraries/nestjs-libraries/src/database/prisma/notifications/notification.service.ts +++ b/libraries/nestjs-libraries/src/database/prisma/notifications/notification.service.ts @@ -83,7 +83,9 @@ export class NotificationService { async sendEmailsToOrg(orgId: string, subject: string, message: string) { const userOrg = await this._organizationRepository.getAllUsersOrgs(orgId); for (const user of userOrg?.users || []) { - await this.sendEmail(user.user.email, subject, message); + if (user.user.emailNotifications) { + await this.sendEmail(user.user.email, subject, message); + } } } diff --git a/libraries/nestjs-libraries/src/database/prisma/organizations/organization.repository.ts b/libraries/nestjs-libraries/src/database/prisma/organizations/organization.repository.ts index 919c7b7af..03fa91189 100644 --- a/libraries/nestjs-libraries/src/database/prisma/organizations/organization.repository.ts +++ b/libraries/nestjs-libraries/src/database/prisma/organizations/organization.repository.ts @@ -293,6 +293,7 @@ export class OrganizationRepository { select: { email: true, id: true, + emailNotifications: true }, }, }, diff --git a/libraries/nestjs-libraries/src/database/prisma/schema.prisma b/libraries/nestjs-libraries/src/database/prisma/schema.prisma index 4a5dbdd29..382662e4c 100644 --- a/libraries/nestjs-libraries/src/database/prisma/schema.prisma +++ b/libraries/nestjs-libraries/src/database/prisma/schema.prisma @@ -104,6 +104,8 @@ model User { agencies SocialMediaAgency[] ip String? agent String? + emailNotifications Boolean @default(true) + @@unique([email, providerName]) @@index([lastReadNotifications]) diff --git a/libraries/nestjs-libraries/src/database/prisma/users/users.repository.ts b/libraries/nestjs-libraries/src/database/prisma/users/users.repository.ts index 2df553384..540b6ef2d 100644 --- a/libraries/nestjs-libraries/src/database/prisma/users/users.repository.ts +++ b/libraries/nestjs-libraries/src/database/prisma/users/users.repository.ts @@ -119,6 +119,22 @@ export class UsersRepository { }); } + getEmailNotifications(id: string) { + return this._user.model.user.findUnique({ + where: { id }, + select: { + emailNotifications: true, + }, + }); +} + + updateEmailNotifications(id: string, enabled: boolean) { + return this._user.model.user.update({ + where: { id }, + data: { emailNotifications: enabled }, + }); + } + async getPersonal(userId: string) { const user = await this._user.model.user.findUnique({ where: { diff --git a/libraries/nestjs-libraries/src/database/prisma/users/users.service.ts b/libraries/nestjs-libraries/src/database/prisma/users/users.service.ts index e7580632e..dac054dd2 100644 --- a/libraries/nestjs-libraries/src/database/prisma/users/users.service.ts +++ b/libraries/nestjs-libraries/src/database/prisma/users/users.service.ts @@ -55,4 +55,12 @@ export class UsersService { changePersonal(userId: string, body: UserDetailDto) { return this._usersRepository.changePersonal(userId, body); } + + getEmailNotifications(id: string) { + return this._usersRepository.getEmailNotifications(id); +} + + updateEmailNotifications(id: string, enabled: boolean) { + return this._usersRepository.updateEmailNotifications(id, enabled); + } }