diff --git a/packages/core/.gitignore b/packages/core/.gitignore index 0e74ee0bf..6d8f1a8c9 100644 --- a/packages/core/.gitignore +++ b/packages/core/.gitignore @@ -2,5 +2,7 @@ .env.staging .env.production +prisma/schema.prisma + **/secrets/* diff --git a/packages/core/package.json b/packages/core/package.json index cf4df893c..5ee83f17c 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -7,7 +7,9 @@ "dev": "yarn compile:watch", "compile": "tsc -p tsconfig.json && yarn fix:paths", "compile:watch": "tsc-watch --onSuccess \"yarn fix:paths\"", - "fix:paths": "tscpaths -p tsconfig.json -s ./src -o ./dist" + "fix:paths": "tscpaths -p tsconfig.json -s ./src -o ./dist", + "create:schema": "find prisma -name '*.prisma' -not -name \"schema.prisma\" -exec cat {} + > prisma/schema.prisma && prisma format", + "create:migration": "yarn create:schema && prisma migrate dev" }, "devDependencies": { "@types/request-ip": "^0.0.35", diff --git a/packages/core/prisma/base.prisma b/packages/core/prisma/base.prisma new file mode 100644 index 000000000..2421b6e05 --- /dev/null +++ b/packages/core/prisma/base.prisma @@ -0,0 +1,15 @@ +datasource db { + provider = "postgresql" + url = env("Database.Url") +} + +generator client { + provider = "prisma-client-js" +} + +// ---- Shared + +enum FundingType { + OneTime + Monthly +} \ No newline at end of file diff --git a/packages/core/prisma/migrations/20210410091827_initial_discussions_migration/migration.sql b/packages/core/prisma/migrations/20210410091827_initial_discussions_migration/migration.sql new file mode 100644 index 000000000..cb235202b --- /dev/null +++ b/packages/core/prisma/migrations/20210410091827_initial_discussions_migration/migration.sql @@ -0,0 +1,55 @@ +-- CreateEnum +CREATE TYPE "DiscussionType" AS ENUM ('ProposalDiscussion', 'CommonDiscussion'); + +-- CreateEnum +CREATE TYPE "DiscussionSubscriptionType" AS ENUM ('AllNotifications', 'OnlyMentions', 'NoNotification'); + +-- CreateEnum +CREATE TYPE "DiscussionMessageType" AS ENUM ('Message'); + +-- CreateTable +CREATE TABLE "Discussion" +( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "topic" TEXT NOT NULL, + "description" TEXT NOT NULL, + "latestMessage" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "DiscussionSubscription" +( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "latestMessageSeen" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "type" "DiscussionSubscriptionType" NOT NULL DEFAULT E'AllNotifications', + "discussionId" TEXT NOT NULL, + + PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "DiscussionMessage" +( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "type" "DiscussionMessageType" NOT NULL DEFAULT E'Message', + "message" TEXT NOT NULL, + "discussionId" TEXT, + + PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "DiscussionSubscription" + ADD FOREIGN KEY ("discussionId") REFERENCES "Discussion" ("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "DiscussionMessage" + ADD FOREIGN KEY ("discussionId") REFERENCES "Discussion" ("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/packages/core/prisma/migrations/20210412050840_discussion_links_migration/migration.sql b/packages/core/prisma/migrations/20210412050840_discussion_links_migration/migration.sql new file mode 100644 index 000000000..8ede2a148 --- /dev/null +++ b/packages/core/prisma/migrations/20210412050840_discussion_links_migration/migration.sql @@ -0,0 +1,26 @@ +/* + Warnings: + + - You are about to drop the column `latestMessageSeen` on the `DiscussionSubscription` table. All the data in the column will be lost. + - Added the required column `userId` to the `DiscussionMessage` table without a default value. This is not possible if the table is not empty. + - Made the column `discussionId` on table `DiscussionMessage` required. This step will fail if there are existing NULL values in that column. + - Added the required column `userId` to the `DiscussionSubscription` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "DiscussionMessage" + ADD COLUMN "userId" TEXT NOT NULL, + ALTER COLUMN "discussionId" SET NOT NULL; + +-- AlterTable +ALTER TABLE "DiscussionSubscription" + DROP COLUMN "latestMessageSeen", + ADD COLUMN "userId" TEXT NOT NULL; + +-- AddForeignKey +ALTER TABLE "DiscussionMessage" + ADD FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "DiscussionSubscription" + ADD FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/packages/core/prisma/migrations/20210412051108_proposal_common_discussion/migration.sql b/packages/core/prisma/migrations/20210412051108_proposal_common_discussion/migration.sql new file mode 100644 index 000000000..6e812fec5 --- /dev/null +++ b/packages/core/prisma/migrations/20210412051108_proposal_common_discussion/migration.sql @@ -0,0 +1,18 @@ +/* + Warnings: + + - Added the required column `commonId` to the `Discussion` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "Discussion" + ADD COLUMN "commonId" TEXT NOT NULL, + ADD COLUMN "proposalId" TEXT; + +-- AddForeignKey +ALTER TABLE "Discussion" + ADD FOREIGN KEY ("commonId") REFERENCES "Common" ("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Discussion" + ADD FOREIGN KEY ("proposalId") REFERENCES "Proposal" ("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/packages/core/prisma/migrations/20210412052009_discussion_creator/migration.sql b/packages/core/prisma/migrations/20210412052009_discussion_creator/migration.sql new file mode 100644 index 000000000..4f9270e95 --- /dev/null +++ b/packages/core/prisma/migrations/20210412052009_discussion_creator/migration.sql @@ -0,0 +1,13 @@ +/* + Warnings: + + - Added the required column `userId` to the `Discussion` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "Discussion" + ADD COLUMN "userId" TEXT NOT NULL; + +-- AddForeignKey +ALTER TABLE "Discussion" + ADD FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/packages/core/prisma/migrations/20210412052219_discussion_event_types/migration.sql b/packages/core/prisma/migrations/20210412052219_discussion_event_types/migration.sql new file mode 100644 index 000000000..37a4da8e7 --- /dev/null +++ b/packages/core/prisma/migrations/20210412052219_discussion_event_types/migration.sql @@ -0,0 +1,11 @@ +-- AlterEnum +-- This migration adds more than one value to an enum. +-- With PostgreSQL versions 11 and earlier, this is not possible +-- in a single migration. This can be worked around by creating +-- multiple migrations, each migration adding only one value to +-- the enum. + + +ALTER TYPE "EventType" ADD VALUE 'DiscussionCreated'; +ALTER TYPE "EventType" ADD VALUE 'DiscussionMessageCreated'; +ALTER TYPE "EventType" ADD VALUE 'DiscussionSubscriptionCreated'; diff --git a/packages/core/prisma/migrations/20210412053758_discussion_type/migration.sql b/packages/core/prisma/migrations/20210412053758_discussion_type/migration.sql new file mode 100644 index 000000000..800a8a095 --- /dev/null +++ b/packages/core/prisma/migrations/20210412053758_discussion_type/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - Added the required column `type` to the `Discussion` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "Discussion" ADD COLUMN "type" "DiscussionType" NOT NULL; diff --git a/packages/core/prisma/migrations/20210413051920_discussion_subscription_type_changed_event_added/migration.sql b/packages/core/prisma/migrations/20210413051920_discussion_subscription_type_changed_event_added/migration.sql new file mode 100644 index 000000000..e07d5f6f9 --- /dev/null +++ b/packages/core/prisma/migrations/20210413051920_discussion_subscription_type_changed_event_added/migration.sql @@ -0,0 +1,2 @@ +-- AlterEnum +ALTER TYPE "EventType" ADD VALUE 'DiscussionSubscriptionTypeChanged'; diff --git a/packages/core/prisma/models/all.prisma b/packages/core/prisma/models/all.prisma new file mode 100644 index 000000000..3ffee3a29 --- /dev/null +++ b/packages/core/prisma/models/all.prisma @@ -0,0 +1,107 @@ +model Payment { + id String @id @default(uuid()) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + processed Boolean @default(false) + processedError Boolean @default(false) + + type PaymentType + status PaymentStatus @default(NotAttempted) + + circlePaymentStatus PaymentCircleStatus? + circlePaymentId String? + + amount Int + + card Card @relation(fields: [cardId], references: [id]) + + user User @relation(fields: [userId], references: [id]) + common Common @relation(fields: [commonId], references: [id]) + + join JoinProposal @relation(fields: [joinId], references: [id]) + subscription Subscription? @relation(fields: [subscriptionId], references: [id]) + + subscriptionId String? + joinId String + + userId String + commonId String + + cardId String +} + +enum PaymentType { + OneTimePayment + + SubscriptionInitialPayment + SubscriptionSequentialPayment +} + +enum PaymentCircleStatus { + pending + failed + confirmed + paid +} + +enum PaymentStatus { + NotAttempted + Pending + Successful + Unsuccessful +} + +model Card { + id String @id @default(uuid()) + + circleCardId String + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + digits String + network CardNetwork + + cvvCheck String + avsCheck String + + + user User @relation(fields: [userId], references: [id]) + payments Payment[] + + proposal JoinProposal[] + subscriptions Subscription[] + + billingDetails CardBillingDetail? + + userId String +} + +enum CardNetwork { + VISA + MASTERCARD +} + +model CardBillingDetail { + id String @id @default(uuid()) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + name String + + line1 String + line2 String? + + city String + country String + district String? + postalCode String + + card Card @relation(fields: [cardId], references: [id]) + + cardId String +} + diff --git a/packages/core/prisma/models/commons/Common.prisma b/packages/core/prisma/models/commons/Common.prisma new file mode 100644 index 000000000..be68913fa --- /dev/null +++ b/packages/core/prisma/models/commons/Common.prisma @@ -0,0 +1,27 @@ +model Common { + id String @id @default(uuid()) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + name String + + balance Int @default(0) + raised Int @default(0) + + whitelisted Boolean @default(false) + + fundingType FundingType + fundingMinimumAmount Int + + events Event[] + members CommonMember[] + + payments Payment[] + subscriptions Subscription[] + + proposals Proposal[] + discussions Discussion[] +} + + diff --git a/packages/core/prisma/models/commons/CommonMember.prisma b/packages/core/prisma/models/commons/CommonMember.prisma new file mode 100644 index 000000000..884637514 --- /dev/null +++ b/packages/core/prisma/models/commons/CommonMember.prisma @@ -0,0 +1,20 @@ +model CommonMember { + id String @id @default(uuid()) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + common Common @relation(fields: [commonId], references: [id]) + user User @relation(fields: [userId], references: [id]) + + roles CommonMemberRole[] + + proposals Proposal[] + + commonId String + userId String + + Vote Vote[] + + @@unique([userId, commonId]) +} diff --git a/packages/core/prisma/models/commons/enums/CommonMemberRole.prisma b/packages/core/prisma/models/commons/enums/CommonMemberRole.prisma new file mode 100644 index 000000000..853f2b13e --- /dev/null +++ b/packages/core/prisma/models/commons/enums/CommonMemberRole.prisma @@ -0,0 +1,3 @@ +enum CommonMemberRole { + Founder +} diff --git a/packages/core/prisma/models/discussions/Discussion.prisma b/packages/core/prisma/models/discussions/Discussion.prisma new file mode 100644 index 000000000..2a6bb11c6 --- /dev/null +++ b/packages/core/prisma/models/discussions/Discussion.prisma @@ -0,0 +1,20 @@ +model Discussion { + id String @id @default(uuid()) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + type DiscussionType + + topic String + description String + + latestMessage DateTime @default(now()) + + user User + common Common + proposal Proposal? + + messages DiscussionMessage[] + subscriptions DiscussionSubscription[] +} diff --git a/packages/core/prisma/models/discussions/DiscussionMessage.prisma b/packages/core/prisma/models/discussions/DiscussionMessage.prisma new file mode 100644 index 000000000..02509f3c2 --- /dev/null +++ b/packages/core/prisma/models/discussions/DiscussionMessage.prisma @@ -0,0 +1,15 @@ +model DiscussionMessage { + id String @id @default(uuid()) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + type DiscussionMessageType @default(Message) + message String + + discussion Discussion @relation(fields: [discussionId], references: [id]) + user User @relation(fields: [userId], references: [id]) + + discussionId String + userId String +} \ No newline at end of file diff --git a/packages/core/prisma/models/discussions/DiscussionSubscription.prisma b/packages/core/prisma/models/discussions/DiscussionSubscription.prisma new file mode 100644 index 000000000..02dbc31ec --- /dev/null +++ b/packages/core/prisma/models/discussions/DiscussionSubscription.prisma @@ -0,0 +1,14 @@ +model DiscussionSubscription { + id String @id @default(uuid()) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + type DiscussionSubscriptionType @default(AllNotifications) + + userId String + discussionId String + + user User @relation(fields: [userId], references: [id]) + discussion Discussion @relation(fields: [discussionId], references: [id]) +} diff --git a/packages/core/prisma/models/discussions/enums/DiscussionMessageType.prisma b/packages/core/prisma/models/discussions/enums/DiscussionMessageType.prisma new file mode 100644 index 000000000..af067fbbf --- /dev/null +++ b/packages/core/prisma/models/discussions/enums/DiscussionMessageType.prisma @@ -0,0 +1,3 @@ +enum DiscussionMessageType { + Message +} diff --git a/packages/core/prisma/models/discussions/enums/DiscussionSubscriptionType.prisma b/packages/core/prisma/models/discussions/enums/DiscussionSubscriptionType.prisma new file mode 100644 index 000000000..04f70124a --- /dev/null +++ b/packages/core/prisma/models/discussions/enums/DiscussionSubscriptionType.prisma @@ -0,0 +1,6 @@ +enum DiscussionSubscriptionType { + AllNotifications + OnlyMentions + NoNotification +} + diff --git a/packages/core/prisma/models/discussions/enums/DiscussionType.prisma b/packages/core/prisma/models/discussions/enums/DiscussionType.prisma new file mode 100644 index 000000000..04afa6f03 --- /dev/null +++ b/packages/core/prisma/models/discussions/enums/DiscussionType.prisma @@ -0,0 +1,4 @@ +enum DiscussionType { + ProposalDiscussion + CommonDiscussion +} diff --git a/packages/core/prisma/models/events/Event.prisma b/packages/core/prisma/models/events/Event.prisma new file mode 100644 index 000000000..b8324df06 --- /dev/null +++ b/packages/core/prisma/models/events/Event.prisma @@ -0,0 +1,16 @@ +model Event { + id String @id @default(uuid()) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + type EventType + + payload Json? + + commonId String? + userId String? + + common Common? @relation(fields: [commonId], references: [id]) + user User? @relation(fields: [userId], references: [id]) +} \ No newline at end of file diff --git a/packages/core/prisma/models/events/EventType.prisma b/packages/core/prisma/models/events/EventType.prisma new file mode 100644 index 000000000..12b45be33 --- /dev/null +++ b/packages/core/prisma/models/events/EventType.prisma @@ -0,0 +1,36 @@ +enum EventType { + CommonCreated + + CommonMemberCreated + CommonMemberRoleAdded + CommonMemberRoleRemoved + + JoinRequestCreated + JoinRequestAccepted + JoinRequestRejected + + FundingRequestCreated + FundingRequestAccepted + FundingRequestRejected + + CardCreated + CardCvvVerificationPassed + CardCvvVerificationFailed + + PaymentCreated + PaymentSucceeded + PaymentFailed + + ProposalMajorityReached + ProposalExpired + + VoteCreated + + UserCreated + + DiscussionCreated + DiscussionMessageCreated + DiscussionSubscriptionCreated + + DiscussionSubscriptionTypeChanged +} \ No newline at end of file diff --git a/packages/core/prisma/models/proposals/FundingProposal.prisma b/packages/core/prisma/models/proposals/FundingProposal.prisma new file mode 100644 index 000000000..ab806e9a3 --- /dev/null +++ b/packages/core/prisma/models/proposals/FundingProposal.prisma @@ -0,0 +1,15 @@ +model FundingProposal { + id String @id @default(uuid()) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + proposal Proposal? + + amount Int + + + fundingState FundingState @default(NotEligible) + + // @todo Payout +} diff --git a/packages/core/prisma/models/proposals/JoinProposal.prisma b/packages/core/prisma/models/proposals/JoinProposal.prisma new file mode 100644 index 000000000..29ba06784 --- /dev/null +++ b/packages/core/prisma/models/proposals/JoinProposal.prisma @@ -0,0 +1,20 @@ +model JoinProposal { + id String @id @default(uuid()) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + funding Int + fundingType FundingType + paymentState ProposalPaymentState @default(NotAttempted) + + card Card @relation(fields: [cardId], references: [id]) + payment Payment[] + proposal Proposal? + subscription Subscription? @relation(fields: [subscriptionId], references: [id]) + + cardId String + subscriptionId String? +} + + diff --git a/packages/core/prisma/models/proposals/Proposal.prisma b/packages/core/prisma/models/proposals/Proposal.prisma new file mode 100644 index 000000000..ccc11c2cd --- /dev/null +++ b/packages/core/prisma/models/proposals/Proposal.prisma @@ -0,0 +1,42 @@ +model Proposal { + id String @id @default(uuid()) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + expiresAt DateTime + + title String? + description String? + + link Json? + files Json? + images Json? + + ipAddress String? + + votes Vote[] + + type ProposalType + state ProposalState @default(Countdown) + + votesFor Int @default(0) + votesAgainst Int @default(0) + + discussions Discussion[] + + join JoinProposal? @relation(fields: [joinId], references: [id]) + funding FundingProposal? @relation(fields: [fundingId], references: [id]) + + user User @relation(fields: [userId], references: [id]) + common Common @relation(fields: [commonId], references: [id]) + commonMember CommonMember? @relation(fields: [commonMemberId], references: [id]) + + + joinId String? @unique + fundingId String? @unique + + userId String + commonId String + commonMemberId String? +} \ No newline at end of file diff --git a/packages/core/prisma/models/proposals/ProposalVote.prisma b/packages/core/prisma/models/proposals/ProposalVote.prisma new file mode 100644 index 000000000..0702d3bc3 --- /dev/null +++ b/packages/core/prisma/models/proposals/ProposalVote.prisma @@ -0,0 +1,17 @@ +model Vote { + id String @id @default(uuid()) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + outcome VoteOutcome + + proposal Proposal @relation(fields: [proposalId], references: [id]) + commonMember CommonMember @relation(fields: [commonMemberId], references: [id]) + + commonMemberId String + proposalId String + + @@unique([commonMemberId, proposalId]) +} + diff --git a/packages/core/prisma/models/proposals/enums/ProposalFundingState.prisma b/packages/core/prisma/models/proposals/enums/ProposalFundingState.prisma new file mode 100644 index 000000000..843f2e17a --- /dev/null +++ b/packages/core/prisma/models/proposals/enums/ProposalFundingState.prisma @@ -0,0 +1,12 @@ +enum FundingState { + NotEligible + Eligible + + AwaitingApproval + Pending + Completed + Confirmed +} + + + diff --git a/packages/core/prisma/models/proposals/enums/ProposalPaymentState.prisma b/packages/core/prisma/models/proposals/enums/ProposalPaymentState.prisma new file mode 100644 index 000000000..92a0c31ec --- /dev/null +++ b/packages/core/prisma/models/proposals/enums/ProposalPaymentState.prisma @@ -0,0 +1,7 @@ +enum ProposalPaymentState { + NotAttempted + Pending + + Successful + Unsuccessful +} \ No newline at end of file diff --git a/packages/core/prisma/models/proposals/enums/ProposalState.prisma b/packages/core/prisma/models/proposals/enums/ProposalState.prisma new file mode 100644 index 000000000..dde6a4cda --- /dev/null +++ b/packages/core/prisma/models/proposals/enums/ProposalState.prisma @@ -0,0 +1,8 @@ +enum ProposalState { + Countdown + + Finalizing + + Rejected + Accepted +} \ No newline at end of file diff --git a/packages/core/prisma/models/proposals/enums/ProposalType.prisma b/packages/core/prisma/models/proposals/enums/ProposalType.prisma new file mode 100644 index 000000000..81ea25afa --- /dev/null +++ b/packages/core/prisma/models/proposals/enums/ProposalType.prisma @@ -0,0 +1,4 @@ +enum ProposalType { + FundingRequest + JoinRequest +} diff --git a/packages/core/prisma/models/proposals/enums/ProposalVoteOutcome.prisma b/packages/core/prisma/models/proposals/enums/ProposalVoteOutcome.prisma new file mode 100644 index 000000000..6bcb2699e --- /dev/null +++ b/packages/core/prisma/models/proposals/enums/ProposalVoteOutcome.prisma @@ -0,0 +1,4 @@ +enum VoteOutcome { + Approve + Condemn +} \ No newline at end of file diff --git a/packages/core/prisma/models/subscriptions/Subscription.prisma b/packages/core/prisma/models/subscriptions/Subscription.prisma new file mode 100644 index 000000000..65b95b14e --- /dev/null +++ b/packages/core/prisma/models/subscriptions/Subscription.prisma @@ -0,0 +1,30 @@ +model Subscription { + id String @id @default(uuid()) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + card Card @relation(fields: [cardId], references: [id]) + join JoinProposal? + + + user User @relation(fields: [userId], references: [id]) + common Common @relation(fields: [commonId], references: [id]) + + payments Payment[] + + amount Int + + paymentStatus SubscriptionPaymentStatus @default(AwaitingInitialPayment) + status SubscriptionStatus @default(Pending) + + dueDate DateTime + chargedAt DateTime? + + voided Boolean @default(false) + + cardId String + + userId String + commonId String +} \ No newline at end of file diff --git a/packages/core/prisma/models/subscriptions/enums/SubscriptionPaymentStatus.prisma b/packages/core/prisma/models/subscriptions/enums/SubscriptionPaymentStatus.prisma new file mode 100644 index 000000000..657f915ff --- /dev/null +++ b/packages/core/prisma/models/subscriptions/enums/SubscriptionPaymentStatus.prisma @@ -0,0 +1,8 @@ +enum SubscriptionPaymentStatus { + AwaitingInitialPayment + + Pending + + Successful + Unsuccessful +} diff --git a/packages/core/prisma/models/subscriptions/enums/SubscriptionStatus.prisma b/packages/core/prisma/models/subscriptions/enums/SubscriptionStatus.prisma new file mode 100644 index 000000000..fb777551f --- /dev/null +++ b/packages/core/prisma/models/subscriptions/enums/SubscriptionStatus.prisma @@ -0,0 +1,10 @@ +enum SubscriptionStatus { + Pending + + Active + + PaymentFailed + + CanceledByUser + CanceledByPaymentFailure +} \ No newline at end of file diff --git a/packages/core/prisma/models/users/User.prisma b/packages/core/prisma/models/users/User.prisma new file mode 100644 index 000000000..db46042b6 --- /dev/null +++ b/packages/core/prisma/models/users/User.prisma @@ -0,0 +1,24 @@ +model User { + id String @id + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + firstName String + lastName String + + email String @unique + emailVerified Boolean @default(false) + + cards Card[] + events Event[] + memberships CommonMember[] + + payments Payment[] + proposals Proposal[] + subscriptions Subscription[] + + discussionSubscriptions DiscussionSubscription[] + discussionMessages DiscussionMessage[] + discussions Discussion[] +} \ No newline at end of file diff --git a/packages/core/prisma/schema.prisma b/packages/core/prisma/schema.prisma deleted file mode 100644 index 5b04b9cef..000000000 --- a/packages/core/prisma/schema.prisma +++ /dev/null @@ -1,438 +0,0 @@ -// This is your Prisma schema file, -// learn more about it in the docs: https://pris.ly/d/prisma-schema - -datasource db { - provider = "postgresql" - url = env("Database.Url") -} - -generator client { - provider = "prisma-client-js" -} - -// ---- Shared - -enum FundingType { - OneTime - Monthly -} - -// ---- User related stuff - -model User { - id String @id - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - firstName String - lastName String - - email String @unique - emailVerified Boolean @default(false) - - cards Card[] - events Event[] - memberships CommonMember[] - - payments Payment[] - proposals Proposal[] - subscriptions Subscription[] -} - -// ---- Common related stuff - -model Common { - id String @id @default(uuid()) - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - name String - - balance Int @default(0) - raised Int @default(0) - - whitelisted Boolean @default(false) - - fundingType FundingType - fundingMinimumAmount Int - - events Event[] - members CommonMember[] - - payments Payment[] - subscriptions Subscription[] - - proposals Proposal[] -} - -model CommonMember { - id String @id @default(uuid()) - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - common Common @relation(fields: [commonId], references: [id]) - user User @relation(fields: [userId], references: [id]) - - roles CommonMemberRole[] - - proposals Proposal[] - - commonId String - userId String - - Vote Vote[] - - @@unique([userId, commonId]) -} - -enum CommonMemberRole { - Founder -} - -// ---- Proposals - -model JoinProposal { - id String @id @default(uuid()) - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - funding Int - fundingType FundingType - paymentState ProposalPaymentState @default(NotAttempted) - - card Card @relation(fields: [cardId], references: [id]) - payment Payment[] - proposal Proposal? - subscription Subscription? @relation(fields: [subscriptionId], references: [id]) - - cardId String - subscriptionId String? -} - -model FundingProposal { - id String @id @default(uuid()) - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - proposal Proposal? - - amount Int - - - fundingState FundingState @default(NotEligible) - - // @todo Payout -} - -enum FundingState { - NotEligible - Eligible - - AwaitingApproval - Pending - Completed - Confirmed -} - -model Proposal { - id String @id @default(uuid()) - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - expiresAt DateTime - - title String? - description String? - - link Json? - files Json? - images Json? - - ipAddress String? - - votes Vote[] - - type ProposalType - state ProposalState @default(Countdown) - - votesFor Int @default(0) - votesAgainst Int @default(0) - - join JoinProposal? @relation(fields: [joinId], references: [id]) - funding FundingProposal? @relation(fields: [fundingId], references: [id]) - - user User @relation(fields: [userId], references: [id]) - common Common @relation(fields: [commonId], references: [id]) - commonMember CommonMember? @relation(fields: [commonMemberId], references: [id]) - - - joinId String? @unique - fundingId String? @unique - - userId String - commonId String - commonMemberId String? -} - -enum ProposalType { - FundingRequest - JoinRequest -} - -enum ProposalState { - Countdown - - Finalizing - - Rejected - Accepted -} - -enum ProposalPaymentState { - NotAttempted - Pending - - Successful - Unsuccessful -} - -// ---- Subscriptions -model Subscription { - id String @id @default(uuid()) - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - card Card @relation(fields: [cardId], references: [id]) - join JoinProposal? - - - user User @relation(fields: [userId], references: [id]) - common Common @relation(fields: [commonId], references: [id]) - - payments Payment[] - - amount Int - - paymentStatus SubscriptionPaymentStatus @default(AwaitingInitialPayment) - status SubscriptionStatus @default(Pending) - - dueDate DateTime - chargedAt DateTime? - - voided Boolean @default(false) - - cardId String - - userId String - commonId String -} - -enum SubscriptionPaymentStatus { - AwaitingInitialPayment - - Pending - - Successful - Unsuccessful -} - -enum SubscriptionStatus { - Pending - - Active - - PaymentFailed - - CanceledByUser - CanceledByPaymentFailure -} - -// ---- Votes - -model Vote { - id String @id @default(uuid()) - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - outcome VoteOutcome - - proposal Proposal @relation(fields: [proposalId], references: [id]) - commonMember CommonMember @relation(fields: [commonMemberId], references: [id]) - - commonMemberId String - proposalId String - - @@unique([commonMemberId, proposalId]) -} - -enum VoteOutcome { - Approve - Condemn -} - -// ---- Payments and cards - -model Payment { - id String @id @default(uuid()) - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - processed Boolean @default(false) - processedError Boolean @default(false) - - type PaymentType - status PaymentStatus @default(NotAttempted) - - circlePaymentStatus PaymentCircleStatus? - circlePaymentId String? - - amount Int - - card Card @relation(fields: [cardId], references: [id]) - - user User @relation(fields: [userId], references: [id]) - common Common @relation(fields: [commonId], references: [id]) - - join JoinProposal @relation(fields: [joinId], references: [id]) - subscription Subscription? @relation(fields: [subscriptionId], references: [id]) - - subscriptionId String? - joinId String - - userId String - commonId String - - cardId String -} - -enum PaymentType { - OneTimePayment - - SubscriptionInitialPayment - SubscriptionSequentialPayment -} - -enum PaymentCircleStatus { - pending - failed - confirmed - paid -} - -enum PaymentStatus { - NotAttempted - Pending - Successful - Unsuccessful -} - -model Card { - id String @id @default(uuid()) - - circleCardId String - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - digits String - network CardNetwork - - cvvCheck String - avsCheck String - - - user User @relation(fields: [userId], references: [id]) - payments Payment[] - - proposal JoinProposal[] - subscriptions Subscription[] - - billingDetails CardBillingDetail? - - userId String -} - -enum CardNetwork { - VISA - MASTERCARD -} - -model CardBillingDetail { - id String @id @default(uuid()) - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - name String - - line1 String - line2 String? - - city String - country String - district String? - postalCode String - - card Card @relation(fields: [cardId], references: [id]) - - cardId String -} - -// ---- Events - -model Event { - id String @id @default(uuid()) - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - type EventType - - payload Json? - - commonId String? - userId String? - - common Common? @relation(fields: [commonId], references: [id]) - user User? @relation(fields: [userId], references: [id]) -} - -enum EventType { - CommonCreated - - CommonMemberCreated - CommonMemberRoleAdded - CommonMemberRoleRemoved - - JoinRequestCreated - JoinRequestAccepted - JoinRequestRejected - - FundingRequestCreated - FundingRequestAccepted - FundingRequestRejected - - CardCreated - CardCvvVerificationPassed - CardCvvVerificationFailed - - PaymentCreated - PaymentSucceeded - PaymentFailed - - ProposalMajorityReached - ProposalExpired - - VoteCreated - - UserCreated -} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 40795ec0b..2903ba897 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -6,6 +6,9 @@ FirebaseToolkit.InitializeFirebase(); export { prisma } from '@toolkits'; export { logger } from '@logger'; +// Domain +export { CommonError } from '@errors'; + // Services export { cardService } from './services/cards'; @@ -15,5 +18,6 @@ export { eventService } from './services/events'; export { commonService } from './services/commons'; export { paymentService } from './services/payments'; export { proposalService } from './services/proposals'; +export { discussionService } from './services/discussions'; export { FirebaseToolkit }; \ No newline at end of file diff --git a/packages/core/src/services/cards/commands/createCardCommand.ts b/packages/core/src/services/cards/commands/createCardCommand.ts index 8979757bc..495d0bf62 100644 --- a/packages/core/src/services/cards/commands/createCardCommand.ts +++ b/packages/core/src/services/cards/commands/createCardCommand.ts @@ -88,7 +88,7 @@ export const createCardCommand = async (command: z.infer): Promis }); // Create event for the card - await eventService.create({ + eventService.create({ type: EventType.CardCreated, userId }); diff --git a/packages/core/src/services/cards/commands/verifyCardCommand.ts b/packages/core/src/services/cards/commands/verifyCardCommand.ts index 45e3a4a15..f9cc4564e 100644 --- a/packages/core/src/services/cards/commands/verifyCardCommand.ts +++ b/packages/core/src/services/cards/commands/verifyCardCommand.ts @@ -67,7 +67,7 @@ export const verifyCardCommand = async (card: Card, customOptions?: Partial }); // Create event - await eventService.create({ + eventService.create({ type: EventType.CommonMemberRoleAdded, commonId: memberEntity.commonId, userId: memberEntity.userId, diff --git a/packages/core/src/services/commons/command/createCommonCommand.ts b/packages/core/src/services/commons/command/createCommonCommand.ts index d68fe333e..e5e816fbd 100644 --- a/packages/core/src/services/commons/command/createCommonCommand.ts +++ b/packages/core/src/services/commons/command/createCommonCommand.ts @@ -37,7 +37,7 @@ export const createCommonCommand = async (command: z.infer): Prom }); // Create event for the common creation - await eventService.create({ + eventService.create({ type: EventType.CommonCreated, commonId: common.id, userId: command.founderId diff --git a/packages/core/src/services/commons/command/createCommonMemberCommand.ts b/packages/core/src/services/commons/command/createCommonMemberCommand.ts index 439f89f19..1839870f9 100644 --- a/packages/core/src/services/commons/command/createCommonMemberCommand.ts +++ b/packages/core/src/services/commons/command/createCommonMemberCommand.ts @@ -41,7 +41,7 @@ export const createCommonMemberCommand = async (command: z.infer) }); // Create event for the new member - await eventService.create({ + eventService.create({ type: EventType.CommonMemberCreated, commonId: command.commonId, userId: command.userId, diff --git a/packages/core/src/services/discussions/core/commands/createDiscussionCommand.ts b/packages/core/src/services/discussions/core/commands/createDiscussionCommand.ts new file mode 100644 index 000000000..048c37f16 --- /dev/null +++ b/packages/core/src/services/discussions/core/commands/createDiscussionCommand.ts @@ -0,0 +1,108 @@ +import * as z from 'zod'; +import { Discussion, EventType, DiscussionType } from '@prisma/client'; + +import { prisma } from '@toolkits'; +import { CommonError } from '@errors'; +import { eventService } from '@services'; +import { createDiscussionSubscriptionCommand } from '../../subscriptions/createDiscussionSubscriptionCommand'; +import { canCreateProposalDiscussionQuery } from '../queries/canCreateProposalDiscussionQuery'; + +const schema = z.object({ + commonId: z.string() + .uuid(), + + proposalId: z.string() + .uuid() + .optional() + .nullable(), + + userId: z.string() + .nonempty(), + + topic: z.string() + .nonempty(), + + description: z.string() + .nonempty() +}); + +/** + * Creates new discussion for a common or proposal. The userId must me of a + * user that is common member of that common, or the common of that proposal + * + * @param payload + */ +export const createDiscussionCommand = async (payload: z.infer): Promise => { + // Validate the payload + schema.parse(payload); + + // Check if the user is common member + if ( + !(await prisma.commonMember.count({ + where: { + userId: payload.userId, + commonId: payload.commonId + } + })) + ) { + throw new CommonError('Cannot create discussion in a common that you are not member of!'); + } + + // If there is proposal do some more checks + if (payload.proposalId) { + // Check if that proposal is from the same common + if ( + !(await prisma.proposal.count({ + where: { + id: payload.proposalId, + commonId: payload.commonId + } + })) + ) { + throw new CommonError('Proposal Common Mismatch', { + description: 'The proposal is not from the common' + }); + } + + // Check if the maximum allowed discussions for one + // proposals has been reached + if (!(await canCreateProposalDiscussionQuery(payload.proposalId))) { + throw new CommonError('The maximum discussions per proposal has been reached!'); + } + } + + // Create the discussion + const discussion = await prisma.discussion.create({ + data: { + userId: payload.userId, + commonId: payload.commonId, + proposalId: payload.proposalId, + + topic: payload.topic.trim(), + description: payload.description.trim(), + + type: payload.proposalId + ? DiscussionType.ProposalDiscussion + : DiscussionType.CommonDiscussion + } + }); + + // Create event about the discussion creation + eventService.create({ + type: EventType.DiscussionCreated, + commonId: payload.commonId, + userId: payload.userId, + payload: { + discussionId: discussion.id + } + }); + + // Subscribe the creator to the discussion + await createDiscussionSubscriptionCommand({ + discussionId: discussion.id, + userId: discussion.userId + }); + + // Return the created discussion + return discussion; +}; \ No newline at end of file diff --git a/packages/core/src/services/discussions/core/queries/canCreateProposalDiscussionQuery.ts b/packages/core/src/services/discussions/core/queries/canCreateProposalDiscussionQuery.ts new file mode 100644 index 000000000..37f28291a --- /dev/null +++ b/packages/core/src/services/discussions/core/queries/canCreateProposalDiscussionQuery.ts @@ -0,0 +1,18 @@ +import { prisma } from '@toolkits'; + +/** + * Checks if the current limit for discussions for proposal + * has been reached + * + * @param proposalId - The ID of the proposal for which we are creating new discussion + */ +export const canCreateProposalDiscussionQuery = async (proposalId: string): Promise => { + const maximumAllowed = process.env['Constraints.Discussions.MaxPerProposal'] || 5; + const currentDiscussionCount = await prisma.discussion.count({ + where: { + proposalId + } + }); + + return currentDiscussionCount < maximumAllowed; +}; \ No newline at end of file diff --git a/packages/core/src/services/discussions/index.ts b/packages/core/src/services/discussions/index.ts new file mode 100644 index 000000000..ae52b66b0 --- /dev/null +++ b/packages/core/src/services/discussions/index.ts @@ -0,0 +1,35 @@ +import { createDiscussionCommand } from './core/commands/createDiscussionCommand'; + +import { createDiscussionSubscriptionCommand } from './subscriptions/createDiscussionSubscriptionCommand'; +import { changeDiscussionSubscriptionTypeCommand } from './subscriptions/changeDiscussionSubscriptionTypeCommand'; + +import { createDiscussionMessageCommand } from './messages/createDiscussionMessageCommand'; + +export const discussionService = { + /** + * Create new discussion for the common, + * or for proposal + */ + create: createDiscussionCommand, + + subscription: { + /** + * Create notification subscription for discussion + */ + create: createDiscussionSubscriptionCommand, + + /** + * Updates the type of the subscription in the backing store. Please note + * that this function does not check if the user has permission to update + * the specified subscription + */ + changeType: changeDiscussionSubscriptionTypeCommand + }, + + messages: { + /** + * Create new message in discussion + */ + create: createDiscussionMessageCommand + } +}; \ No newline at end of file diff --git a/packages/core/src/services/discussions/messages/createDiscussionMessageCommand.ts b/packages/core/src/services/discussions/messages/createDiscussionMessageCommand.ts new file mode 100644 index 000000000..749b3c253 --- /dev/null +++ b/packages/core/src/services/discussions/messages/createDiscussionMessageCommand.ts @@ -0,0 +1,75 @@ +import * as z from 'zod'; +import { DiscussionMessage, DiscussionMessageType, EventType } from '@prisma/client'; + +import { prisma } from '@toolkits'; +import { CommonError } from '@errors'; +import { eventService } from '@services'; + +const schema = z.object({ + userId: z.string() + .nonempty(), + + discussionId: z.string() + .uuid() + .nonempty(), + + message: z.string() + .nonempty(), + + messageType: z.enum(Object.keys(DiscussionMessageType) as [(keyof typeof DiscussionMessageType)]) + .optional() +}); + +export const createDiscussionMessageCommand = async (payload: z.infer): Promise => { + // Validate the payload + schema.parse(payload); + + // Check if the user can create messages in that discussion + const member = await prisma.commonMember.findFirst({ + where: { + userId: payload.userId, + common: { + discussions: { + some: { + id: payload.discussionId + } + } + } + }, + select: { + commonId: true, + userId: true + } + }); + + if (!member) { + throw new CommonError( + 'Cannot create discussion message in discussion that is' + + 'in common that you are not member of' + ); + } + + // Create the message + const message = await prisma.discussionMessage.create({ + data: { + discussionId: payload.discussionId, + userId: payload.userId, + + message: payload.message, + type: payload.messageType || DiscussionMessageType.Message + } + }); + + // Create event about the message @todo Types + eventService.create({ + type: EventType.DiscussionMessageCreated, + userId: member.userId, + commonId: member.commonId, + payload: { + messageId: message.id + } + }); + + // Return the created message + return message; +}; \ No newline at end of file diff --git a/packages/core/src/services/discussions/subscriptions/changeDiscussionSubscriptionTypeCommand.ts b/packages/core/src/services/discussions/subscriptions/changeDiscussionSubscriptionTypeCommand.ts new file mode 100644 index 000000000..2b91f8eaa --- /dev/null +++ b/packages/core/src/services/discussions/subscriptions/changeDiscussionSubscriptionTypeCommand.ts @@ -0,0 +1,52 @@ +import * as z from 'zod'; +import { DiscussionSubscription, DiscussionSubscriptionType } from '@prisma/client'; + +import { prisma } from '@toolkits'; +import { eventService } from '@services'; + +const schema = z.object({ + id: z.string() + .nonempty() + .uuid(), + + type: z.enum(Object.keys(DiscussionSubscriptionType) as [(keyof typeof DiscussionSubscriptionType)]) +}); + +/** + * Updates the type of the subscription in the backing store. Please note + * that this function does not check if the user has permission to update + * the specified subscription + * + * @param payload - The update payload + * + * @returns The updated subscription + */ +export const changeDiscussionSubscriptionTypeCommand = async (payload: z.infer): Promise => { + // Validate the payload + schema.parse(payload); + + // Update the subscription + const updatedSubscription = await prisma.discussionSubscription + .update({ + data: { + type: payload.type + }, + + where: { + id: payload.id + } + }); + + // Crete event + await eventService.create({ + type: 'DiscussionSubscriptionTypeChanged', + userId: updatedSubscription.userId, + payload: { + discussionId: updatedSubscription.discussionId, + updatedType: updatedSubscription.type + } + }); + + // Return the updated subscription + return updatedSubscription; +}; \ No newline at end of file diff --git a/packages/core/src/services/discussions/subscriptions/createDiscussionSubscriptionCommand.ts b/packages/core/src/services/discussions/subscriptions/createDiscussionSubscriptionCommand.ts new file mode 100644 index 000000000..7fd96eaf7 --- /dev/null +++ b/packages/core/src/services/discussions/subscriptions/createDiscussionSubscriptionCommand.ts @@ -0,0 +1,46 @@ +import * as z from 'zod'; +import { DiscussionSubscription, DiscussionSubscriptionType, EventType } from '@prisma/client'; + +import { prisma } from '@toolkits'; +import { eventService } from '@services'; + +const schema = z.object({ + discussionId: z.string() + .uuid() + .nonempty(), + + userId: z.string() + .nonempty(), + + subscriptionType: z.enum(Object.keys(DiscussionSubscriptionType) as [(keyof typeof DiscussionSubscriptionType)]) + .nullable() + .optional() +}); + +export const createDiscussionSubscriptionCommand = async (payload: z.infer): Promise => { + // Validate the payload + schema.parse(payload); + + // Create the subscription + const subscription = await prisma.discussionSubscription.create({ + data: { + discussionId: payload.discussionId, + userId: payload.userId, + + type: payload.subscriptionType || DiscussionSubscriptionType.AllNotifications + } + }); + + + // Create event + eventService.create({ + type: EventType.DiscussionSubscriptionCreated, + userId: payload.userId, + payload: { + discussionId: payload.discussionId + } + }); + + // Return the created subscription + return subscription; +}; \ No newline at end of file diff --git a/packages/core/src/services/events/commands/createEventCommand.ts b/packages/core/src/services/events/commands/createEventCommand.ts index 1313a0a32..b47219288 100644 --- a/packages/core/src/services/events/commands/createEventCommand.ts +++ b/packages/core/src/services/events/commands/createEventCommand.ts @@ -20,6 +20,6 @@ const schema = z.object({ ]) }); -export const createEventCommand = async (command: z.infer): Promise => { +export const createEventCommand = (command: z.infer): void => { worker.addEventJob('create', command); }; \ No newline at end of file diff --git a/packages/core/src/services/index.ts b/packages/core/src/services/index.ts index 74203117a..db0e3d18f 100644 --- a/packages/core/src/services/index.ts +++ b/packages/core/src/services/index.ts @@ -4,4 +4,5 @@ export { cardService } from './cards'; export { eventService } from './events'; export { commonService } from './commons'; export { paymentService } from './payments'; +export { discussionService } from './discussions'; export { joinProposalService, proposalService } from './proposals'; diff --git a/packages/core/src/services/payments/commands/createPaymentCommand.ts b/packages/core/src/services/payments/commands/createPaymentCommand.ts index 79c9a064d..0a4b01d31 100644 --- a/packages/core/src/services/payments/commands/createPaymentCommand.ts +++ b/packages/core/src/services/payments/commands/createPaymentCommand.ts @@ -108,7 +108,7 @@ export const createPaymentCommand = async (command: z.infer): Pro }); // Create event - await eventService.create({ + eventService.create({ type: EventType.PaymentCreated, userId: command.connect.userId, commonId: command.connect.commonId diff --git a/packages/core/src/services/proposals/funding/command/createFundingProposalCommand.ts b/packages/core/src/services/proposals/funding/command/createFundingProposalCommand.ts index dc832a04e..078a33ee5 100644 --- a/packages/core/src/services/proposals/funding/command/createFundingProposalCommand.ts +++ b/packages/core/src/services/proposals/funding/command/createFundingProposalCommand.ts @@ -127,7 +127,7 @@ export const createFundingProposalCommand = async (command: z.infer) }); // Create event - await eventService.create({ + eventService.create({ type: EventType.JoinRequestCreated, commonId: command.commonId, userId: command.userId diff --git a/packages/core/src/services/proposals/join/command/process/processApprovedOneTimeJoinRequest.ts b/packages/core/src/services/proposals/join/command/process/processApprovedOneTimeJoinRequest.ts index a1cbbf825..8363137cc 100644 --- a/packages/core/src/services/proposals/join/command/process/processApprovedOneTimeJoinRequest.ts +++ b/packages/core/src/services/proposals/join/command/process/processApprovedOneTimeJoinRequest.ts @@ -17,7 +17,7 @@ export const processApprovedOneTimeJoinRequestCommand = async (proposalId: strin }); // Create event - await eventService.create({ + eventService.create({ type: EventType.JoinRequestAccepted, userId: proposal.userId, commonId: proposal.commonId, diff --git a/packages/core/src/services/proposals/join/command/process/processApprovedSubscriptionJoinRequest.ts b/packages/core/src/services/proposals/join/command/process/processApprovedSubscriptionJoinRequest.ts index 2421525c4..a5346922f 100644 --- a/packages/core/src/services/proposals/join/command/process/processApprovedSubscriptionJoinRequest.ts +++ b/packages/core/src/services/proposals/join/command/process/processApprovedSubscriptionJoinRequest.ts @@ -25,7 +25,7 @@ export const processApprovedSubscriptionJoinRequest = async (proposalId: string) }); // Create event - await eventService.create({ + eventService.create({ type: EventType.JoinRequestAccepted, userId: proposal.userId, commonId: proposal.commonId, diff --git a/packages/core/src/services/proposals/join/command/process/processRejectedJoinRequest.ts b/packages/core/src/services/proposals/join/command/process/processRejectedJoinRequest.ts index cc2e8df4a..826e293d3 100644 --- a/packages/core/src/services/proposals/join/command/process/processRejectedJoinRequest.ts +++ b/packages/core/src/services/proposals/join/command/process/processRejectedJoinRequest.ts @@ -14,7 +14,7 @@ export const processRejectedJoinRequest = async (proposalId: string): Promise) => Promise): Promis } // Create event for the creation of the vote - await eventService.create({ + eventService.create({ type: EventType.VoteCreated, userId: command.userId, commonId diff --git a/packages/firebase/functions/src/core/graph/schema/commons/types/CommonMetadata.type.ts b/packages/firebase/functions/src/core/graph/schema/commons/types/CommonMetadata.type.ts index e98e7f2d6..2d7a180dc 100644 --- a/packages/firebase/functions/src/core/graph/schema/commons/types/CommonMetadata.type.ts +++ b/packages/firebase/functions/src/core/graph/schema/commons/types/CommonMetadata.type.ts @@ -11,5 +11,5 @@ export const CommonMetadataType = objectType({ t.field('contributionType', { type: CommonContributionTypeEnum }); - }, + } }); \ No newline at end of file diff --git a/packages/graphql/src/generated/nexus-typegen.ts b/packages/graphql/src/generated/nexus-typegen.ts index 25ccf8109..281561051 100644 --- a/packages/graphql/src/generated/nexus-typegen.ts +++ b/packages/graphql/src/generated/nexus-typegen.ts @@ -22,6 +22,10 @@ declare global { * The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */ json(fieldName: FieldName, opts?: core.CommonInputFieldConfig): void // "JSON"; + /** + * A field whose value is a generic Universally Unique Identifier: https://en.wikipedia.org/wiki/Universally_unique_identifier. + */ + uuid(fieldName: FieldName, opts?: core.CommonInputFieldConfig): void // "UUID"; } } declare global { @@ -38,6 +42,10 @@ declare global { * The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */ json(fieldName: FieldName, ...opts: core.ScalarOutSpread): void // "JSON"; + /** + * A field whose value is a generic Universally Unique Identifier: https://en.wikipedia.org/wiki/Universally_unique_identifier. + */ + uuid(fieldName: FieldName, ...opts: core.ScalarOutSpread): void // "UUID"; } } @@ -74,6 +82,16 @@ export interface NexusGenInputs { fundingType: NexusGenEnums['FundingType']; // FundingType! name: string; // String! } + CreateDiscussionInput: { // input type + commonId: string; // ID! + description: string; // String! + proposalId?: string | null; // ID + topic: string; // String! + } + CreateDiscussionMessageInput: { // input type + discussionId: string; // ID! + message: string; // String! + } CreateFundingProposalInput: { // input type amount: number; // Int! commonId: string; // ID! @@ -100,6 +118,14 @@ export interface NexusGenInputs { outcome: NexusGenEnums['VoteOutcome']; // VoteOutcome! proposalId: string; // ID! } + DiscussionMessagesOrderByInput: { // input type + createdAt?: NexusGenEnums['SortOrder'] | null; // SortOrder + updatedAt?: NexusGenEnums['SortOrder'] | null; // SortOrder + } + DiscussionSubscriptionOrderByInput: { // input type + createdAt?: NexusGenEnums['SortOrder'] | null; // SortOrder + updatedAt?: NexusGenEnums['SortOrder'] | null; // SortOrder + } EventOrderByInput: { // input type createdAt?: NexusGenEnums['SortOrder'] | null; // SortOrder type?: NexusGenEnums['SortOrder'] | null; // SortOrder @@ -122,6 +148,9 @@ export interface NexusGenInputs { ProposalWhereInput: { // input type type?: NexusGenEnums['ProposalType'] | null; // ProposalType } + ProposalWhereUniqueInput: { // input type + id: NexusGenScalars['UUID']; // UUID! + } StringFilter: { // input type contains?: string | null; // String endsWith?: string | null; // String @@ -138,7 +167,10 @@ export interface NexusGenInputs { export interface NexusGenEnums { CommonMemberRole: 'Founder' - EventType: 'CardCreated' | 'CardCvvVerificationFailed' | 'CardCvvVerificationPassed' | 'CommonCreated' | 'CommonMemberCreated' | 'CommonMemberRoleAdded' | 'CommonMemberRoleRemoved' | 'FundingRequestAccepted' | 'FundingRequestCreated' | 'FundingRequestRejected' | 'JoinRequestAccepted' | 'JoinRequestCreated' | 'JoinRequestRejected' | 'PaymentCreated' | 'PaymentFailed' | 'PaymentSucceeded' | 'ProposalExpired' | 'ProposalMajorityReached' | 'UserCreated' | 'VoteCreated' + DiscussionMessageType: 'Message' + DiscussionSubscriptionType: 'AllNotifications' | 'NoNotification' | 'OnlyMentions' + DiscussionType: 'CommonDiscussion' | 'ProposalDiscussion' + EventType: 'CardCreated' | 'CardCvvVerificationFailed' | 'CardCvvVerificationPassed' | 'CommonCreated' | 'CommonMemberCreated' | 'CommonMemberRoleAdded' | 'CommonMemberRoleRemoved' | 'DiscussionCreated' | 'DiscussionMessageCreated' | 'DiscussionSubscriptionCreated' | 'DiscussionSubscriptionTypeChanged' | 'FundingRequestAccepted' | 'FundingRequestCreated' | 'FundingRequestRejected' | 'JoinRequestAccepted' | 'JoinRequestCreated' | 'JoinRequestRejected' | 'PaymentCreated' | 'PaymentFailed' | 'PaymentSucceeded' | 'ProposalExpired' | 'ProposalMajorityReached' | 'UserCreated' | 'VoteCreated' FundingType: 'Monthly' | 'OneTime' ProposalType: 'FundingRequest' | 'JoinRequest' SortOrder: 'asc' | 'desc' @@ -154,6 +186,7 @@ export interface NexusGenScalars { DateTime: any JSON: any URL: any + UUID: any } export interface NexusGenObjects { @@ -175,6 +208,30 @@ export interface NexusGenObjects { roles: NexusGenEnums['CommonMemberRole'][]; // [CommonMemberRole!]! userId: string; // ID! } + Discussion: { // root type + createdAt: NexusGenScalars['DateTime']; // DateTime! + description: string; // String! + id: NexusGenScalars['UUID']; // UUID! + latestMessage: NexusGenScalars['DateTime']; // DateTime! + topic: string; // String! + type: NexusGenEnums['DiscussionType']; // DiscussionType! + updatedAt: NexusGenScalars['DateTime']; // DateTime! + } + DiscussionMessage: { // root type + createdAt: NexusGenScalars['DateTime']; // DateTime! + id: NexusGenScalars['UUID']; // UUID! + message: string; // String! + type: NexusGenEnums['DiscussionMessageType']; // DiscussionMessageType! + updatedAt: NexusGenScalars['DateTime']; // DateTime! + } + DiscussionSubscription: { // root type + createdAt: NexusGenScalars['DateTime']; // DateTime! + discussionId: NexusGenScalars['UUID']; // UUID! + id: NexusGenScalars['UUID']; // UUID! + type: NexusGenEnums['DiscussionSubscriptionType']; // DiscussionSubscriptionType! + updatedAt: NexusGenScalars['DateTime']; // DateTime! + userId: string; // String! + } Event: { // root type commonId?: string | null; // ID createdAt: NexusGenScalars['DateTime']; // DateTime! @@ -221,12 +278,13 @@ export interface NexusGenObjects { } export interface NexusGenInterfaces { + BaseEntity: NexusGenRootTypes['Discussion'] | NexusGenRootTypes['DiscussionMessage'] | NexusGenRootTypes['DiscussionSubscription']; } export interface NexusGenUnions { } -export type NexusGenRootTypes = NexusGenObjects +export type NexusGenRootTypes = NexusGenInterfaces & NexusGenObjects export type NexusGenAllTypes = NexusGenRootTypes & NexusGenScalars & NexusGenEnums @@ -238,6 +296,7 @@ export interface NexusGenFieldTypes { } Common: { // field return type createdAt: NexusGenScalars['DateTime']; // DateTime! + discussions: NexusGenRootTypes['Discussion'][]; // [Discussion!]! events: NexusGenRootTypes['Event'][]; // [Event!]! id: string; // ID! members: Array; // [CommonMember]! @@ -250,10 +309,37 @@ export interface NexusGenFieldTypes { common: NexusGenRootTypes['Common'] | null; // Common commonId: string; // ID! id: string; // ID! + proposals: NexusGenRootTypes['Proposal'][]; // [Proposal!]! roles: NexusGenEnums['CommonMemberRole'][]; // [CommonMemberRole!]! user: NexusGenRootTypes['User'] | null; // User userId: string; // ID! } + Discussion: { // field return type + createdAt: NexusGenScalars['DateTime']; // DateTime! + description: string; // String! + id: NexusGenScalars['UUID']; // UUID! + latestMessage: NexusGenScalars['DateTime']; // DateTime! + messages: NexusGenRootTypes['DiscussionMessage'][]; // [DiscussionMessage!]! + topic: string; // String! + type: NexusGenEnums['DiscussionType']; // DiscussionType! + updatedAt: NexusGenScalars['DateTime']; // DateTime! + } + DiscussionMessage: { // field return type + createdAt: NexusGenScalars['DateTime']; // DateTime! + id: NexusGenScalars['UUID']; // UUID! + message: string; // String! + type: NexusGenEnums['DiscussionMessageType']; // DiscussionMessageType! + updatedAt: NexusGenScalars['DateTime']; // DateTime! + } + DiscussionSubscription: { // field return type + createdAt: NexusGenScalars['DateTime']; // DateTime! + discussion: NexusGenRootTypes['Discussion']; // Discussion! + discussionId: NexusGenScalars['UUID']; // UUID! + id: NexusGenScalars['UUID']; // UUID! + type: NexusGenEnums['DiscussionSubscriptionType']; // DiscussionSubscriptionType! + updatedAt: NexusGenScalars['DateTime']; // DateTime! + userId: string; // String! + } Event: { // field return type commonId: string | null; // ID createdAt: NexusGenScalars['DateTime']; // DateTime! @@ -278,8 +364,11 @@ export interface NexusGenFieldTypes { url: string; // String! } Mutation: { // field return type + changeDiscussionSubscriptionType: NexusGenRootTypes['DiscussionSubscription'] | null; // DiscussionSubscription createCard: NexusGenRootTypes['Card']; // Card! createCommon: NexusGenRootTypes['Common']; // Common! + createDiscussion: NexusGenRootTypes['Discussion']; // Discussion! + createDiscussionMessage: NexusGenRootTypes['DiscussionMessage']; // DiscussionMessage! createFundingProposal: NexusGenRootTypes['FundingProposal']; // FundingProposal! createJoinProposal: NexusGenRootTypes['JoinProposal']; // JoinProposal! createUser: NexusGenRootTypes['User']; // User! @@ -288,17 +377,21 @@ export interface NexusGenFieldTypes { } Proposal: { // field return type createdAt: NexusGenScalars['DateTime']; // DateTime! + discussions: NexusGenRootTypes['Discussion'][]; // [Discussion!]! id: string; // ID! type: NexusGenEnums['ProposalType']; // ProposalType! updatedAt: NexusGenScalars['DateTime']; // DateTime! } Query: { // field return type common: NexusGenRootTypes['Common'] | null; // Common + discussion: NexusGenRootTypes['Discussion'] | null; // Discussion generateUserAuthToken: string; // String! + proposal: NexusGenRootTypes['Proposal'] | null; // Proposal user: NexusGenRootTypes['User'] | null; // User } User: { // field return type createdAt: NexusGenScalars['DateTime']; // DateTime! + discussionSubscriptions: NexusGenRootTypes['DiscussionSubscription'][]; // [DiscussionSubscription!]! displayName: string; // String! events: NexusGenRootTypes['Event'][]; // [Event!]! firstName: string; // String! @@ -312,6 +405,11 @@ export interface NexusGenFieldTypes { id: string; // ID! updatedAt: NexusGenScalars['DateTime']; // DateTime! } + BaseEntity: { // field return type + createdAt: NexusGenScalars['DateTime']; // DateTime! + id: NexusGenScalars['UUID']; // UUID! + updatedAt: NexusGenScalars['DateTime']; // DateTime! + } } export interface NexusGenFieldTypeNames { @@ -322,6 +420,7 @@ export interface NexusGenFieldTypeNames { } Common: { // field return type name createdAt: 'DateTime' + discussions: 'Discussion' events: 'Event' id: 'ID' members: 'CommonMember' @@ -334,10 +433,37 @@ export interface NexusGenFieldTypeNames { common: 'Common' commonId: 'ID' id: 'ID' + proposals: 'Proposal' roles: 'CommonMemberRole' user: 'User' userId: 'ID' } + Discussion: { // field return type name + createdAt: 'DateTime' + description: 'String' + id: 'UUID' + latestMessage: 'DateTime' + messages: 'DiscussionMessage' + topic: 'String' + type: 'DiscussionType' + updatedAt: 'DateTime' + } + DiscussionMessage: { // field return type name + createdAt: 'DateTime' + id: 'UUID' + message: 'String' + type: 'DiscussionMessageType' + updatedAt: 'DateTime' + } + DiscussionSubscription: { // field return type name + createdAt: 'DateTime' + discussion: 'Discussion' + discussionId: 'UUID' + id: 'UUID' + type: 'DiscussionSubscriptionType' + updatedAt: 'DateTime' + userId: 'String' + } Event: { // field return type name commonId: 'ID' createdAt: 'DateTime' @@ -362,8 +488,11 @@ export interface NexusGenFieldTypeNames { url: 'String' } Mutation: { // field return type name + changeDiscussionSubscriptionType: 'DiscussionSubscription' createCard: 'Card' createCommon: 'Common' + createDiscussion: 'Discussion' + createDiscussionMessage: 'DiscussionMessage' createFundingProposal: 'FundingProposal' createJoinProposal: 'JoinProposal' createUser: 'User' @@ -372,17 +501,21 @@ export interface NexusGenFieldTypeNames { } Proposal: { // field return type name createdAt: 'DateTime' + discussions: 'Discussion' id: 'ID' type: 'ProposalType' updatedAt: 'DateTime' } Query: { // field return type name common: 'Common' + discussion: 'Discussion' generateUserAuthToken: 'String' + proposal: 'Proposal' user: 'User' } User: { // field return type name createdAt: 'DateTime' + discussionSubscriptions: 'DiscussionSubscription' displayName: 'String' events: 'Event' firstName: 'String' @@ -396,10 +529,19 @@ export interface NexusGenFieldTypeNames { id: 'ID' updatedAt: 'DateTime' } + BaseEntity: { // field return type name + createdAt: 'DateTime' + id: 'UUID' + updatedAt: 'DateTime' + } } export interface NexusGenArgTypes { Common: { + discussions: { // args + skip?: number | null; // Int + take?: number | null; // Int + } events: { // args orderBy?: NexusGenInputs['EventOrderByInput'] | null; // EventOrderByInput skip?: number | null; // Int @@ -416,13 +558,37 @@ export interface NexusGenArgTypes { where?: NexusGenInputs['ProposalWhereInput'] | null; // ProposalWhereInput } } + CommonMember: { + proposals: { // args + skip?: number | null; // Int + take: number | null; // Int + where?: NexusGenInputs['ProposalWhereInput'] | null; // ProposalWhereInput + } + } + Discussion: { + messages: { // args + orderBy: NexusGenInputs['DiscussionMessagesOrderByInput'] | null; // DiscussionMessagesOrderByInput + skip?: number | null; // Int + take: number | null; // Int + } + } Mutation: { + changeDiscussionSubscriptionType: { // args + id: string; // ID! + type: NexusGenEnums['DiscussionSubscriptionType']; // DiscussionSubscriptionType! + } createCard: { // args input: NexusGenInputs['CreateCardInput']; // CreateCardInput! } createCommon: { // args input: NexusGenInputs['CreateCommonInput']; // CreateCommonInput! } + createDiscussion: { // args + input: NexusGenInputs['CreateDiscussionInput']; // CreateDiscussionInput! + } + createDiscussionMessage: { // args + input: NexusGenInputs['CreateDiscussionMessageInput']; // CreateDiscussionMessageInput! + } createFundingProposal: { // args input: NexusGenInputs['CreateFundingProposalInput']; // CreateFundingProposalInput! } @@ -439,18 +605,35 @@ export interface NexusGenArgTypes { proposalId: string; // ID! } } + Proposal: { + discussions: { // args + skip?: number | null; // Int + take?: number | null; // Int + } + } Query: { common: { // args where: NexusGenInputs['CommonWhereUniqueInput']; // CommonWhereUniqueInput! } + discussion: { // args + id: string; // ID! + } generateUserAuthToken: { // args authId: string; // String! } + proposal: { // args + where: NexusGenInputs['ProposalWhereUniqueInput']; // ProposalWhereUniqueInput! + } user: { // args userId?: string | null; // ID } } User: { + discussionSubscriptions: { // args + orderBy?: NexusGenInputs['DiscussionSubscriptionOrderByInput'] | null; // DiscussionSubscriptionOrderByInput + skip?: number | null; // Int + take: number | null; // Int + } events: { // args orderBy?: NexusGenInputs['EventOrderByInput'] | null; // EventOrderByInput skip?: number | null; // Int @@ -465,9 +648,13 @@ export interface NexusGenArgTypes { } export interface NexusGenAbstractTypeMembers { + BaseEntity: 'Discussion' | 'DiscussionMessage' | 'DiscussionSubscription' } export interface NexusGenTypeInterfaces { + Discussion: 'BaseEntity' + DiscussionMessage: 'BaseEntity' + DiscussionSubscription: 'BaseEntity' } export type NexusGenObjectNames = keyof NexusGenObjects; @@ -476,7 +663,7 @@ export type NexusGenInputNames = keyof NexusGenInputs; export type NexusGenEnumNames = keyof NexusGenEnums; -export type NexusGenInterfaceNames = never; +export type NexusGenInterfaceNames = keyof NexusGenInterfaces; export type NexusGenScalarNames = keyof NexusGenScalars; @@ -484,7 +671,7 @@ export type NexusGenUnionNames = never; export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never; -export type NexusGenAbstractsUsingStrategyResolveType = never; +export type NexusGenAbstractsUsingStrategyResolveType = "BaseEntity"; export type NexusGenFeaturesConfig = { abstractTypeStrategies: { diff --git a/packages/graphql/src/generated/schema.graphql b/packages/graphql/src/generated/schema.graphql index 480b9480b..cff34fda8 100644 --- a/packages/graphql/src/generated/schema.graphql +++ b/packages/graphql/src/generated/schema.graphql @@ -2,6 +2,17 @@ ### Do not make changes to this file directly +interface BaseEntity { + """The date, at which the item was created""" + createdAt: DateTime! + + """The main identifier of the item""" + id: UUID! + + """The date, at which the item was last modified""" + updatedAt: DateTime! +} + input BillingDetailsInput { city: String! country: String! @@ -13,42 +24,44 @@ input BillingDetailsInput { } type Card { - """The date, at which the item was created""" - createdAt: DateTime! + """The date, at which the item was created""" + createdAt: DateTime! - """The main identifier of the item""" - id: ID! + """The main identifier of the item""" + id: ID! - """The date, at which the item was last modified""" - updatedAt: DateTime! + """The date, at which the item was last modified""" + updatedAt: DateTime! } type Common { - """The date, at which the item was created""" - createdAt: DateTime! + """The date, at which the item was created""" + createdAt: DateTime! + discussions(skip: Int, take: Int): [Discussion!]! - """List of events, that occurred in a common""" - events(orderBy: EventOrderByInput, skip: Int = 0, take: Int = 10): [Event!]! + """List of events, that occurred in a common""" + events(orderBy: EventOrderByInput, skip: Int = 0, take: Int = 10): [Event!]! - """The main identifier of the item""" - id: ID! - members(orderBy: CommonMemberOrderByInput, skip: Int, take: Int): [CommonMember]! + """The main identifier of the item""" + id: ID! + members(orderBy: CommonMemberOrderByInput, skip: Int, take: Int): [CommonMember]! - """The name of the common as provided""" - name: String! - proposals(skip: Int = 0, take: Int = 10, where: ProposalWhereInput): [Proposal!]! + """The name of the common as provided""" + name: String! + proposals(skip: Int = 0, take: Int = 10, where: ProposalWhereInput): [Proposal!]! - """The date, at which the item was last modified""" - updatedAt: DateTime! + """The date, at which the item was last modified""" + updatedAt: DateTime! - """The whitelisting state of a common""" - whitelisted: Boolean! + """The whitelisting state of a common""" + whitelisted: Boolean! } type CommonMember { common: Common commonId: ID! id: ID! + proposals(skip: Int = 0, take: Int = 10, where: ProposalWhereInput): [Proposal!]! roles: [CommonMemberRole!]! user: User userId: ID! @@ -79,9 +92,31 @@ input CreateCardInput { } input CreateCommonInput { - fundingMinimumAmount: Int! - fundingType: FundingType! - name: String! + fundingMinimumAmount: Int! + fundingType: FundingType! + name: String! +} + +input CreateDiscussionInput { + """The ID of the common, for which we are creating the discussion""" + commonId: ID! + + """Short description about the topic""" + description: String! + + """The ID of the proposal, if this is proposal discussion""" + proposalId: ID + + """The topic of the discussion to be created""" + topic: String! +} + +input CreateDiscussionMessageInput { + """The ID of the discussion, for which we are creating the message""" + discussionId: ID! + + """The message itself""" + message: String! } input CreateFundingProposalInput { @@ -121,25 +156,100 @@ A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `dat """ scalar DateTime +type Discussion implements BaseEntity { + """The date, at which the item was created""" + createdAt: DateTime! + + """Short description of the topic""" + description: String! + + """The main identifier of the item""" + id: UUID! + + """The date at which the last message on the discussion was added""" + latestMessage: DateTime! + messages(orderBy: DiscussionMessagesOrderByInput = {createdAt: asc}, skip: Int = 0, take: Int = 10): [DiscussionMessage!]! + + """What this discussion is about""" + topic: String! + type: DiscussionType! + + """The date, at which the item was last modified""" + updatedAt: DateTime! +} + +type DiscussionMessage implements BaseEntity { + """The date, at which the item was created""" + createdAt: DateTime! + + """The main identifier of the item""" + id: UUID! + message: String! + type: DiscussionMessageType! + + """The date, at which the item was last modified""" + updatedAt: DateTime! +} + +enum DiscussionMessageType { + Message +} + +input DiscussionMessagesOrderByInput { + createdAt: SortOrder + updatedAt: SortOrder +} + +type DiscussionSubscription implements BaseEntity { + """The date, at which the item was created""" + createdAt: DateTime! + discussion: Discussion! + discussionId: UUID! + + """The main identifier of the item""" + id: UUID! + type: DiscussionSubscriptionType! + + """The date, at which the item was last modified""" + updatedAt: DateTime! + userId: String! +} + +input DiscussionSubscriptionOrderByInput { + createdAt: SortOrder + updatedAt: SortOrder +} + +enum DiscussionSubscriptionType { + AllNotifications + NoNotification + OnlyMentions +} + +enum DiscussionType { + CommonDiscussion + ProposalDiscussion +} + type Event { - """The ID of the common, for whom the event was created""" - commonId: ID + """The ID of the common, for whom the event was created""" + commonId: ID - """The date, at which the item was created""" - createdAt: DateTime! + """The date, at which the item was created""" + createdAt: DateTime! - """The main identifier of the item""" - id: ID! - payload: JSON + """The main identifier of the item""" + id: ID! + payload: JSON - """The type of the event in one of the predefined event types""" - type: EventType! + """The type of the event in one of the predefined event types""" + type: EventType! - """The date, at which the item was last modified""" - updatedAt: DateTime! + """The date, at which the item was last modified""" + updatedAt: DateTime! - """The ID of the event creator""" - userId: ID + """The ID of the event creator""" + userId: ID } input EventOrderByInput { @@ -156,6 +266,10 @@ enum EventType { CommonMemberCreated CommonMemberRoleAdded CommonMemberRoleRemoved + DiscussionCreated + DiscussionMessageCreated + DiscussionSubscriptionCreated + DiscussionSubscriptionTypeChanged FundingRequestAccepted FundingRequestCreated FundingRequestRejected @@ -172,20 +286,20 @@ enum EventType { } type FundingProposal { - """The date, at which the item was created""" - createdAt: DateTime! + """The date, at which the item was created""" + createdAt: DateTime! - """The main identifier of the item""" - id: ID! + """The main identifier of the item""" + id: ID! - """The date, at which the item was last modified""" - updatedAt: DateTime! + """The date, at which the item was last modified""" + updatedAt: DateTime! } """The funding type of the common""" enum FundingType { - Monthly - OneTime + Monthly + OneTime } """ @@ -194,14 +308,14 @@ The `JSON` scalar type represents JSON values as specified by [ECMA-404](http:// scalar JSON type JoinProposal { - """The date, at which the item was created""" - createdAt: DateTime! + """The date, at which the item was created""" + createdAt: DateTime! - """The main identifier of the item""" - id: ID! + """The main identifier of the item""" + id: ID! - """The date, at which the item was last modified""" - updatedAt: DateTime! + """The date, at which the item was last modified""" + updatedAt: DateTime! } type Link { @@ -221,79 +335,95 @@ input LinkInput { } type Mutation { - createCard(input: CreateCardInput!): Card! - createCommon(input: CreateCommonInput!): Common! - createFundingProposal(input: CreateFundingProposalInput!): FundingProposal! + changeDiscussionSubscriptionType( + """The ID of the discussion subscription to change""" + id: ID! + + """The new subscription type""" + type: DiscussionSubscriptionType! + ): DiscussionSubscription + createCard(input: CreateCardInput!): Card! + createCommon(input: CreateCommonInput!): Common! + createDiscussion(input: CreateDiscussionInput!): Discussion! + createDiscussionMessage(input: CreateDiscussionMessageInput!): DiscussionMessage! + createFundingProposal(input: CreateFundingProposalInput!): FundingProposal! - """Create new proposal of type JOIN.""" - createJoinProposal(input: CreateJoinProposalInput!): JoinProposal! + """Create new proposal of type JOIN.""" + createJoinProposal(input: CreateJoinProposalInput!): JoinProposal! - """Creates new user in the system""" - createUser(input: CreateUserInput!): User! - createVote(input: CreateVoteInput!): Vote! - finalizeProposal(proposalId: ID!): Boolean! + """Creates new user in the system""" + createUser(input: CreateUserInput!): User! + createVote(input: CreateVoteInput!): Vote! + finalizeProposal(proposalId: ID!): Boolean! } type Proposal { - """The date, at which the item was created""" - createdAt: DateTime! + """The date, at which the item was created""" + createdAt: DateTime! + discussions(skip: Int, take: Int): [Discussion!]! - """The main identifier of the item""" - id: ID! - type: ProposalType! + """The main identifier of the item""" + id: ID! + type: ProposalType! - """The date, at which the item was last modified""" - updatedAt: DateTime! + """The date, at which the item was last modified""" + updatedAt: DateTime! } input ProposalFileInput { - value: String! + value: String! } input ProposalImageInput { - value: String! + value: String! } input ProposalLinkInput { - title: String! - url: String! + title: String! + url: String! } enum ProposalType { - FundingRequest - JoinRequest + FundingRequest + JoinRequest } input ProposalWhereInput { - type: ProposalType + type: ProposalType +} + +input ProposalWhereUniqueInput { + id: UUID! } type Query { - common(where: CommonWhereUniqueInput!): Common - generateUserAuthToken(authId: String!): String! + common(where: CommonWhereUniqueInput!): Common + discussion(id: ID!): Discussion + generateUserAuthToken(authId: String!): String! + proposal(where: ProposalWhereUniqueInput!): Proposal - """ - Provide ID to fetch specific user or do not pass anything to get the currently authenticated user - """ - user(userId: ID): User + """ + Provide ID to fetch specific user or do not pass anything to get the currently authenticated user + """ + user(userId: ID): User } enum SortOrder { - asc - desc + asc + desc } input StringFilter { - contains: String - endsWith: String - equals: String - gt: String - gte: String - in: [String!] - lt: String - lte: String - notIn: [String!] - startsWith: String + contains: String + endsWith: String + equals: String + gt: String + gte: String + in: [String!] + lt: String + lte: String + notIn: [String!] + startsWith: String } """ @@ -301,39 +431,45 @@ A field whose value conforms to the standard URL format as specified in RFC3986: """ scalar URL +""" +A field whose value is a generic Universally Unique Identifier: https://en.wikipedia.org/wiki/Universally_unique_identifier. +""" +scalar UUID + type User { - """The date, at which the item was created""" - createdAt: DateTime! + """The date, at which the item was created""" + createdAt: DateTime! + discussionSubscriptions(orderBy: DiscussionSubscriptionOrderByInput, skip: Int = 0, take: Int = 10): [DiscussionSubscription!]! - """The display name of the user""" - displayName: String! + """The display name of the user""" + displayName: String! - """List of events, that occurred and are related to this user""" - events(orderBy: EventOrderByInput, skip: Int = 0, take: Int = 10): [Event!]! + """List of events, that occurred and are related to this user""" + events(orderBy: EventOrderByInput, skip: Int = 0, take: Int = 10): [Event!]! - """The first name of the user""" - firstName: String! + """The first name of the user""" + firstName: String! - """The system Id of the user""" - id: ID! + """The system Id of the user""" + id: ID! - """The last name of the user""" - lastName: String! - proposals(skip: Int = 0, take: Int = 10, where: ProposalWhereInput): [Proposal!]! + """The last name of the user""" + lastName: String! + proposals(skip: Int = 0, take: Int = 10, where: ProposalWhereInput): [Proposal!]! - """The date, at which the item was last modified""" - updatedAt: DateTime! + """The date, at which the item was last modified""" + updatedAt: DateTime! } type Vote { - """The date, at which the item was created""" - createdAt: DateTime! + """The date, at which the item was created""" + createdAt: DateTime! - """The main identifier of the item""" - id: ID! + """The main identifier of the item""" + id: ID! - """The date, at which the item was last modified""" - updatedAt: DateTime! + """The date, at which the item was last modified""" + updatedAt: DateTime! } enum VoteOutcome { diff --git a/packages/graphql/src/schema/Shared/Interfaces/BaseEntity.interface.ts b/packages/graphql/src/schema/Shared/Interfaces/BaseEntity.interface.ts new file mode 100644 index 000000000..a0cbe53d9 --- /dev/null +++ b/packages/graphql/src/schema/Shared/Interfaces/BaseEntity.interface.ts @@ -0,0 +1,20 @@ +import { interfaceType } from 'nexus'; + +export const BaseEntityInterface = interfaceType({ + resolveType: () => null, + name: 'BaseEntity', + definition(t) { + t.nonNull.uuid('id', { + description: 'The main identifier of the item' + }); + + t.nonNull.date('createdAt', { + description: 'The date, at which the item was created' + }); + + t.nonNull.date('updatedAt', { + description: 'The date, at which the item was last modified' + }); + } + +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Shared/Scalars/Uuid.scalar.ts b/packages/graphql/src/schema/Shared/Scalars/Uuid.scalar.ts new file mode 100644 index 000000000..ca92cf93d --- /dev/null +++ b/packages/graphql/src/schema/Shared/Scalars/Uuid.scalar.ts @@ -0,0 +1,4 @@ +import { asNexusMethod } from 'nexus'; +import { GraphQLUUID } from 'graphql-scalars'; + +export const UuidScalar = asNexusMethod(GraphQLUUID, 'uuid'); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/CommonMember/Extensions/CommonMemberProposals.extensions.ts b/packages/graphql/src/schema/Types/CommonMember/Extensions/CommonMemberProposals.extensions.ts new file mode 100644 index 000000000..1fc047333 --- /dev/null +++ b/packages/graphql/src/schema/Types/CommonMember/Extensions/CommonMemberProposals.extensions.ts @@ -0,0 +1,38 @@ +import { extendType, intArg, arg } from 'nexus'; +import { prisma } from '@common/core'; + +export const CommonMemberProposalsExtensions = extendType({ + type: 'CommonMember', + definition(t) { + t.nonNull.list.nonNull.field('proposals', { + type: 'Proposal', + complexity: 20, + args: { + take: intArg({ + default: 10 + }), + + skip: intArg({ + default: 0 + }), + + where: arg({ + type: 'ProposalWhereInput' + }) + }, + resolve: (root, args) => { + return prisma.commonMember + .findUnique({ + where: { + id: root.id + } + }) + .proposals({ + take: args.take || undefined, + skip: args.skip || undefined, + where: (args.where as any) || undefined + }); + } + }); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/CommonMember/index.ts b/packages/graphql/src/schema/Types/CommonMember/index.ts index 638954061..95aa04a31 100644 --- a/packages/graphql/src/schema/Types/CommonMember/index.ts +++ b/packages/graphql/src/schema/Types/CommonMember/index.ts @@ -1,6 +1,9 @@ import { CommonMemberType } from './Types/CommonMember.type'; + import { CommonMemberUserExtension } from './Extensions/CommonMemberUser.extension'; import { CommonMemberCommonExtensions } from './Extensions/CommonMemberCommon.extensions'; +import { CommonMemberProposalsExtensions } from './Extensions/CommonMemberProposals.extensions'; + import { CommonMemberOrderByInput } from './Inputs/CommonMemberOrderBy.input'; import { CommonMemberRoleEnum } from './Enums/CommonMemberRole.enum'; @@ -9,6 +12,7 @@ export const CommonMemberTypes = [ CommonMemberUserExtension, CommonMemberCommonExtensions, + CommonMemberProposalsExtensions, CommonMemberOrderByInput, diff --git a/packages/graphql/src/schema/Types/Commons/Extensions/CommonDiscussions.extension.ts b/packages/graphql/src/schema/Types/Commons/Extensions/CommonDiscussions.extension.ts new file mode 100644 index 000000000..6838bc937 --- /dev/null +++ b/packages/graphql/src/schema/Types/Commons/Extensions/CommonDiscussions.extension.ts @@ -0,0 +1,27 @@ +import { extendType, intArg } from 'nexus'; +import { prisma } from '@common/core'; + +export const CommonDiscussionsExtension = extendType({ + type: 'Common', + definition(t) { + t.nonNull.list.nonNull.field('discussions', { + type: 'Discussion', + args: { + take: intArg(), + skip: intArg() + }, + resolve: (root, args) => { + return prisma.common + .findUnique({ + where: { + id: root.id + } + }) + .discussions({ + take: args.take || 10, + skip: args.skip || 0 + }); + } + }); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Commons/index.ts b/packages/graphql/src/schema/Types/Commons/index.ts index 994fc0a3b..334ea9d83 100644 --- a/packages/graphql/src/schema/Types/Commons/index.ts +++ b/packages/graphql/src/schema/Types/Commons/index.ts @@ -6,6 +6,7 @@ import { GetCommonsQuery } from './Queries/GetCommons.query'; import { CommonEventsExtension } from './Extensions/CommonEvents.extension'; import { CommonProposalsExtension } from './Extensions/CommonProposals.extension'; +import { CommonDiscussionsExtension } from './Extensions/CommonDiscussions.extension'; import { CommonCommonMemberExtension } from './Extensions/CommonCommonMember.extension'; import { CommonType } from './Types/Common.type'; @@ -26,5 +27,6 @@ export const CommonTypes = [ CommonEventsExtension, CommonProposalsExtension, + CommonDiscussionsExtension, CommonCommonMemberExtension ]; \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/Enums/DiscussionMessageType.enum.ts b/packages/graphql/src/schema/Types/Discussion/Enums/DiscussionMessageType.enum.ts new file mode 100644 index 000000000..2e38e61b0 --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/Enums/DiscussionMessageType.enum.ts @@ -0,0 +1,7 @@ +import { enumType } from 'nexus'; +import { DiscussionMessageType } from '@prisma/client'; + +export const DiscussionMessageTypeEnum = enumType({ + name: 'DiscussionMessageType', + members: DiscussionMessageType +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/Enums/DiscussionSubscriptionType.enum.ts b/packages/graphql/src/schema/Types/Discussion/Enums/DiscussionSubscriptionType.enum.ts new file mode 100644 index 000000000..23dd3b5dc --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/Enums/DiscussionSubscriptionType.enum.ts @@ -0,0 +1,7 @@ +import { enumType } from 'nexus'; +import { DiscussionSubscriptionType } from '@prisma/client'; + +export const DiscussionSubscriptionTypeEnum = enumType({ + name: 'DiscussionSubscriptionType', + members: DiscussionSubscriptionType +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/Enums/DiscussionType.enum.ts b/packages/graphql/src/schema/Types/Discussion/Enums/DiscussionType.enum.ts new file mode 100644 index 000000000..e73d49bc2 --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/Enums/DiscussionType.enum.ts @@ -0,0 +1,7 @@ +import { DiscussionType } from '@prisma/client'; +import { enumType } from 'nexus'; + +export const DiscussionTypeEnum = enumType({ + name: 'DiscussionType', + members: DiscussionType +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/Extensions/DiscussionMessages.extension.ts b/packages/graphql/src/schema/Types/Discussion/Extensions/DiscussionMessages.extension.ts new file mode 100644 index 000000000..86b28cd26 --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/Extensions/DiscussionMessages.extension.ts @@ -0,0 +1,39 @@ +import { extendType, intArg, arg } from 'nexus'; +import { prisma } from '@common/core'; + +export const DiscussionMessagesExtension = extendType({ + type: 'Discussion', + definition(t) { + t.nonNull.list.nonNull.field('messages', { + type: 'DiscussionMessage', + complexity: 10, + args: { + take: intArg({ + default: 10 + }), + + skip: intArg({ + default: 0 + }), + + orderBy: arg({ + type: 'DiscussionMessagesOrderByInput', + default: { + createdAt: 'asc' + } + }) + }, + resolve: async (root, args) => { + return prisma.discussionMessage + .findMany({ + where: { + discussionId: root.id + }, + take: args.take || 10, + skip: args.skip || undefined, + orderBy: (args.orderBy as any) + }); + } + }); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/Extensions/DiscussionSubscriptionDiscussion.extension.ts b/packages/graphql/src/schema/Types/Discussion/Extensions/DiscussionSubscriptionDiscussion.extension.ts new file mode 100644 index 000000000..93b430f46 --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/Extensions/DiscussionSubscriptionDiscussion.extension.ts @@ -0,0 +1,21 @@ +import { extendType } from 'nexus'; +import { prisma } from '@common/core'; + +export const DiscussionSubscriptionDiscussionExtension = extendType({ + type: 'DiscussionSubscription', + definition(t) { + t.nonNull.field('discussion', { + complexity: 10, + type: 'Discussion', + resolve: (root) => { + return prisma.discussionSubscription + .findUnique({ + where: { + id: root.id + } + }) + .discussion(); + } + }); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/Inputs/DiscussionMessagesOrderBy.input.ts b/packages/graphql/src/schema/Types/Discussion/Inputs/DiscussionMessagesOrderBy.input.ts new file mode 100644 index 000000000..95495e8f3 --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/Inputs/DiscussionMessagesOrderBy.input.ts @@ -0,0 +1,14 @@ +import { inputObjectType } from 'nexus'; + +export const DiscussionMessagesOrderByInput = inputObjectType({ + name: 'DiscussionMessagesOrderByInput', + definition(t) { + t.field('createdAt', { + type: 'SortOrder' + }); + + t.field('updatedAt', { + type: 'SortOrder' + }); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/Inputs/DiscussionSubscriptionOrderBy.input.ts b/packages/graphql/src/schema/Types/Discussion/Inputs/DiscussionSubscriptionOrderBy.input.ts new file mode 100644 index 000000000..91e5ac180 --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/Inputs/DiscussionSubscriptionOrderBy.input.ts @@ -0,0 +1,14 @@ +import { inputObjectType } from 'nexus'; + +export const DiscussionSubscriptionOrderByInput = inputObjectType({ + name: 'DiscussionSubscriptionOrderByInput', + definition(t) { + t.field('createdAt', { + type: 'SortOrder' + }); + + t.field('updatedAt', { + type: 'SortOrder' + }); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/Mutations/ChangeDiscussionSubscriptionType.mutation.ts b/packages/graphql/src/schema/Types/Discussion/Mutations/ChangeDiscussionSubscriptionType.mutation.ts new file mode 100644 index 000000000..7b2964791 --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/Mutations/ChangeDiscussionSubscriptionType.mutation.ts @@ -0,0 +1,29 @@ +import { arg, extendType, idArg, nonNull } from 'nexus'; +import { discussionService } from '@common/core'; + +export const ChangeDiscussionSubscriptionTypeMutation = extendType({ + type: 'Mutation', + definition(t) { + t.field('changeDiscussionSubscriptionType', { + type: 'DiscussionSubscription', + args: { + id: nonNull( + idArg({ + description: 'The ID of the discussion subscription to change' + }) + ), + type: nonNull( + arg({ + type: 'DiscussionSubscriptionType', + description: 'The new subscription type' + }) + ) + }, + resolve: async (root, args) => { + // @todo Authorization!!!! + + return discussionService.subscription.changeType(args); + } + }); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/Mutations/CreateDiscussion.mutation.ts b/packages/graphql/src/schema/Types/Discussion/Mutations/CreateDiscussion.mutation.ts new file mode 100644 index 000000000..03b0ce2b2 --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/Mutations/CreateDiscussion.mutation.ts @@ -0,0 +1,47 @@ +import { extendType, inputObjectType, nonNull, arg } from 'nexus'; +import { discussionService } from '@common/core'; + +export const CreateDiscussionInput = inputObjectType({ + name: 'CreateDiscussionInput', + definition(t) { + t.nonNull.string('topic', { + description: 'The topic of the discussion to be created' + }); + + t.nonNull.string('description', { + description: 'Short description about the topic' + }); + + t.nonNull.id('commonId', { + description: 'The ID of the common, for which we are creating the discussion' + }); + + t.id('proposalId', { + description: 'The ID of the proposal, if this is proposal discussion' + }); + } +}); + +export const CreateDiscussionMutation = extendType({ + type: 'Mutation', + definition(t) { + t.nonNull.field('createDiscussion', { + type: 'Discussion', + args: { + input: nonNull( + arg({ + type: 'CreateDiscussionInput' + }) + ) + }, + resolve: async (root, args, ctx) => { + const userId = await ctx.getUserId(); + + return discussionService.create({ + ...args.input, + userId + }); + } + }); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/Mutations/CreateDiscussionMessage.mutation.ts b/packages/graphql/src/schema/Types/Discussion/Mutations/CreateDiscussionMessage.mutation.ts new file mode 100644 index 000000000..e87320529 --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/Mutations/CreateDiscussionMessage.mutation.ts @@ -0,0 +1,39 @@ +import { inputObjectType, extendType, nonNull, arg } from 'nexus'; +import { discussionService } from '@common/core'; + +export const CreateDiscussionMessageInput = inputObjectType({ + name: 'CreateDiscussionMessageInput', + definition(t) { + t.nonNull.id('discussionId', { + description: 'The ID of the discussion, for which we are creating the message' + }); + + t.nonNull.string('message', { + description: 'The message itself' + }); + } +}); + +export const CreateDiscussionMessageMutation = extendType({ + type: 'Mutation', + definition(t) { + t.nonNull.field('createDiscussionMessage', { + type: 'DiscussionMessage', + args: { + input: nonNull( + arg({ + type: 'CreateDiscussionMessageInput' + }) + ) + }, + resolve: async (root, args, ctx) => { + const userId = await ctx.getUserId(); + + return discussionService.messages.create({ + ...args.input, + userId + }); + } + }); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/Queries/GetDiscussion.query.ts b/packages/graphql/src/schema/Types/Discussion/Queries/GetDiscussion.query.ts new file mode 100644 index 000000000..58de72f14 --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/Queries/GetDiscussion.query.ts @@ -0,0 +1,21 @@ +import { extendType, idArg, nonNull } from 'nexus'; +import { prisma } from '@common/core'; + +export const GetDiscussionQuery = extendType({ + type: 'Query', + definition(t) { + t.field('discussion', { + type: 'Discussion', + args: { + id: nonNull(idArg()) + }, + resolve: (root, args) => { + return prisma.discussion.findUnique({ + where: { + id: args.id + } + }); + } + }); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/Types/Discussion.type.ts b/packages/graphql/src/schema/Types/Discussion/Types/Discussion.type.ts new file mode 100644 index 000000000..a3684e42f --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/Types/Discussion.type.ts @@ -0,0 +1,24 @@ +import { objectType } from 'nexus'; + +export const DiscussionType = objectType({ + name: 'Discussion', + definition(t) { + t.implements('BaseEntity'); + + t.nonNull.string('topic', { + description: 'What this discussion is about' + }); + + t.nonNull.string('description', { + description: 'Short description of the topic' + }); + + t.nonNull.date('latestMessage', { + description: 'The date at which the last message on the discussion was added' + }); + + t.nonNull.field('type', { + type: 'DiscussionType' + }); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/Types/DiscussionMessage.type.ts b/packages/graphql/src/schema/Types/Discussion/Types/DiscussionMessage.type.ts new file mode 100644 index 000000000..50d22f638 --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/Types/DiscussionMessage.type.ts @@ -0,0 +1,15 @@ +import { objectType } from 'nexus'; + +export const DiscussionMessageType = objectType({ + name: 'DiscussionMessage', + definition(t) { + t.implements('BaseEntity'); + + t.nonNull.string('message'); + + t.nonNull.field('type', { + type: 'DiscussionMessageType' + }); + + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/Types/DiscussionSubscription.type.ts b/packages/graphql/src/schema/Types/Discussion/Types/DiscussionSubscription.type.ts new file mode 100644 index 000000000..eb5f25987 --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/Types/DiscussionSubscription.type.ts @@ -0,0 +1,15 @@ +import { objectType } from 'nexus'; + +export const DiscussionSubscriptionType = objectType({ + name: 'DiscussionSubscription', + definition(t) { + t.implements('BaseEntity'); + + t.nonNull.field('type', { + type: 'DiscussionSubscriptionType' + }); + + t.nonNull.string('userId'); + t.nonNull.uuid('discussionId'); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Discussion/index.ts b/packages/graphql/src/schema/Types/Discussion/index.ts new file mode 100644 index 000000000..bbd7335a0 --- /dev/null +++ b/packages/graphql/src/schema/Types/Discussion/index.ts @@ -0,0 +1,50 @@ +import { DiscussionType } from './Types/Discussion.type'; +import { DiscussionMessageType } from './Types/DiscussionMessage.type'; +import { DiscussionSubscriptionType } from './Types/DiscussionSubscription.type'; + +import { DiscussionTypeEnum } from './Enums/DiscussionType.enum'; +import { DiscussionMessageTypeEnum } from './Enums/DiscussionMessageType.enum'; +import { DiscussionSubscriptionTypeEnum } from './Enums/DiscussionSubscriptionType.enum'; + +import { GetDiscussionQuery } from './Queries/GetDiscussion.query'; + +import { DiscussionMessagesOrderByInput } from './Inputs/DiscussionMessagesOrderBy.input'; +import { DiscussionSubscriptionOrderByInput } from './Inputs/DiscussionSubscriptionOrderBy.input'; + +import { DiscussionMessagesExtension } from './Extensions/DiscussionMessages.extension'; +import { DiscussionSubscriptionDiscussionExtension } from './Extensions/DiscussionSubscriptionDiscussion.extension'; + + +import { CreateDiscussionInput, CreateDiscussionMutation } from './Mutations/CreateDiscussion.mutation'; +import { + CreateDiscussionMessageInput, + CreateDiscussionMessageMutation +} from './Mutations/CreateDiscussionMessage.mutation'; + +import { ChangeDiscussionSubscriptionTypeMutation } from './Mutations/ChangeDiscussionSubscriptionType.mutation'; + +export const DiscussionTypes = [ + DiscussionType, + DiscussionMessageType, + DiscussionSubscriptionType, + + DiscussionTypeEnum, + DiscussionMessageTypeEnum, + DiscussionSubscriptionTypeEnum, + + GetDiscussionQuery, + + DiscussionMessagesOrderByInput, + DiscussionSubscriptionOrderByInput, + + DiscussionMessagesExtension, + DiscussionSubscriptionDiscussionExtension, + + CreateDiscussionInput, + CreateDiscussionMutation, + + CreateDiscussionMessageInput, + CreateDiscussionMessageMutation, + + ChangeDiscussionSubscriptionTypeMutation +]; \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Proposals/Extensions/ProposalDiscussions.extension.ts b/packages/graphql/src/schema/Types/Proposals/Extensions/ProposalDiscussions.extension.ts new file mode 100644 index 000000000..8a0dc1b56 --- /dev/null +++ b/packages/graphql/src/schema/Types/Proposals/Extensions/ProposalDiscussions.extension.ts @@ -0,0 +1,27 @@ +import { extendType, intArg } from 'nexus'; +import { prisma } from '@common/core'; + +export const ProposalDiscussionsExtension = extendType({ + type: 'Proposal', + definition(t) { + t.nonNull.list.nonNull.field('discussions', { + type: 'Discussion', + args: { + take: intArg(), + skip: intArg() + }, + resolve: (root, args) => { + return prisma.proposal + .findUnique({ + where: { + id: root.id + } + }) + .discussions({ + take: args.take || 10, + skip: args.skip || 0 + }); + } + }); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Proposals/Inputs/ProposalWhereUnique.input.ts b/packages/graphql/src/schema/Types/Proposals/Inputs/ProposalWhereUnique.input.ts new file mode 100644 index 000000000..9bcbcea3f --- /dev/null +++ b/packages/graphql/src/schema/Types/Proposals/Inputs/ProposalWhereUnique.input.ts @@ -0,0 +1,8 @@ +import { inputObjectType } from 'nexus'; + +export const ProposalWhereUniqueInput = inputObjectType({ + name: 'ProposalWhereUniqueInput', + definition(t) { + t.nonNull.uuid('id'); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Proposals/Queries/GetProposal.query.ts b/packages/graphql/src/schema/Types/Proposals/Queries/GetProposal.query.ts new file mode 100644 index 000000000..e9b5a7217 --- /dev/null +++ b/packages/graphql/src/schema/Types/Proposals/Queries/GetProposal.query.ts @@ -0,0 +1,24 @@ +import { extendType, nonNull, arg } from 'nexus'; +import { prisma } from '@common/core'; + +export const GetProposalQuery = extendType({ + type: 'Query', + definition(t) { + t.field('proposal', { + type: 'Proposal', + args: { + where: nonNull( + arg({ + type: 'ProposalWhereUniqueInput' + }) + ) + }, + resolve: (root, args) => { + return prisma.proposal + .findUnique({ + where: args.where + }); + } + }); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Proposals/index.ts b/packages/graphql/src/schema/Types/Proposals/index.ts index fc987d0ee..4180be31d 100644 --- a/packages/graphql/src/schema/Types/Proposals/index.ts +++ b/packages/graphql/src/schema/Types/Proposals/index.ts @@ -14,6 +14,12 @@ import { FinalizeProposalMutation } from './Mutations/FinalizeProposalMutation'; import { ProposalTypeEnum } from './Enums/ProposalType.enum'; import { ProposalType } from './Types/Proposal.type'; +import { GetProposalQuery } from './Queries/GetProposal.query'; + +import { ProposalWhereUniqueInput } from './Inputs/ProposalWhereUnique.input'; + +import { ProposalDiscussionsExtension } from './Extensions/ProposalDiscussions.extension'; + export const ProposalTypes = [ ProposalType, @@ -32,5 +38,11 @@ export const ProposalTypes = [ ProposalFileInput, ProposalImageInput, - ProposalTypeEnum + ProposalTypeEnum, + + GetProposalQuery, + + ProposalWhereUniqueInput, + + ProposalDiscussionsExtension ]; \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Users/Extensions/UserDiscussionSubscriptions.extension.ts b/packages/graphql/src/schema/Types/Users/Extensions/UserDiscussionSubscriptions.extension.ts new file mode 100644 index 000000000..ac25c3ca4 --- /dev/null +++ b/packages/graphql/src/schema/Types/Users/Extensions/UserDiscussionSubscriptions.extension.ts @@ -0,0 +1,39 @@ +import { extendType, intArg, arg } from 'nexus'; +import { prisma } from '@common/core'; + +export const UserDiscussionSubscriptionsExtension = extendType({ + type: 'User', + definition(t) { + t.nonNull.list.nonNull.field('discussionSubscriptions', { + type: 'DiscussionSubscription', + args: { + take: intArg({ + default: 10 + }), + + skip: intArg({ + default: 0 + }), + + orderBy: arg({ + type: 'DiscussionSubscriptionOrderByInput' + }) + }, + resolve: (root, args) => { + return prisma.user + .findUnique({ + where: { + id: root.id + } + }) + .discussionSubscriptions({ + take: args.take || 10, + skip: args.skip || 0, + orderBy: (args.orderBy as any) || { + createdAt: 'asc' + } + }); + } + }); + } +}); \ No newline at end of file diff --git a/packages/graphql/src/schema/Types/Users/index.ts b/packages/graphql/src/schema/Types/Users/index.ts index 25442a628..6819a4562 100644 --- a/packages/graphql/src/schema/Types/Users/index.ts +++ b/packages/graphql/src/schema/Types/Users/index.ts @@ -7,6 +7,7 @@ import { CreateUserInput, CreateUserMutation } from './Mutations/CreateUser.muta import { UserEventsExtension } from './Extensions/UserEvents.extension'; import { UserProposalsExtension } from './Extensions/UserProposals.extension'; +import { UserDiscussionSubscriptionsExtension } from './Extensions/UserDiscussionSubscriptions.extension'; export const UserTypes = [ UserType, @@ -18,6 +19,7 @@ export const UserTypes = [ UserEventsExtension, UserProposalsExtension, + UserDiscussionSubscriptionsExtension, GenerateUserAuthTokenQuery ]; \ No newline at end of file diff --git a/packages/graphql/src/schema/index.ts b/packages/graphql/src/schema/index.ts index b792d0f6f..eeaf5828a 100644 --- a/packages/graphql/src/schema/index.ts +++ b/packages/graphql/src/schema/index.ts @@ -7,18 +7,20 @@ import { VoteTypes } from './Types/Votes'; import { EventTypes } from './Types/Events'; import { CommonTypes } from './Types/Commons'; import { ProposalTypes } from './Types/Proposals'; - +import { DiscussionTypes } from './Types/Discussion'; import { CommonMemberTypes } from './Types/CommonMember'; import { UrlScalar } from './Shared/Scalars/Url.scalar'; import { DateScalar } from './Shared/Scalars/Date.scalar'; import { JsonScalar } from './Shared/Scalars/Json.scalar'; +import { UuidScalar } from './Shared/Scalars/Uuid.scalar'; import { LinkType, LinkInputType } from './Shared/Types/Link.type'; +import { BaseEntityInterface } from './Shared/Interfaces/BaseEntity.interface'; + import { BillingDetailsInput } from './Shared/Inputs/BillingDetails.input'; import { StringFilterInput } from './Shared/Inputs/StringFilter.input'; - import { SortOrder } from './Shared/Enums/SortBy.enum'; const types = [ @@ -28,12 +30,14 @@ const types = [ EventTypes, CommonTypes, ProposalTypes, + DiscussionTypes, CommonMemberTypes, // Scalars UrlScalar, DateScalar, JsonScalar, + UuidScalar, // Shared Enums SortOrder, @@ -41,6 +45,9 @@ const types = [ // Shared Types LinkType, + // Shared Interfaces + BaseEntityInterface, + // Shared Input Types LinkInputType, StringFilterInput, diff --git a/packages/queues/src/jobs/EventsQueue.ts b/packages/queues/src/jobs/EventsQueue.ts index d28d350c3..2ccce3d39 100644 --- a/packages/queues/src/jobs/EventsQueue.ts +++ b/packages/queues/src/jobs/EventsQueue.ts @@ -1,16 +1,14 @@ import Queue, { JobOptions } from 'bull'; -import { setQueues, BullAdapter } from 'bull-board'; import { Event, EventType } from '@prisma/client'; import { Queues } from '../constants/Queues'; -import { CommonError } from '@common/core/dist/domain/errors'; -import { logger, eventService } from '@common/core'; +import { logger, CommonError } from '@common/core'; // Create the job spec export interface IEventsQueueJob { create?: { - type: EventType; + type: EventType | string; userId?: string; commonId?: string; diff --git a/yarn.lock b/yarn.lock index 45e14d182..9cf7980f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1701,11 +1701,28 @@ "@firebase/util" "0.3.4" tslib "^1.11.1" +"@firebase/analytics@0.6.8": + version "0.6.8" + resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.6.8.tgz#ec69a8673df2e0381bdebc892d28448e2d97ee8a" + integrity sha512-cPbQIQo3uqpImtiGIB42F9s9fw8cPseCj1ZMR3VshL6u/6kzC9ptOpgg8PMCLOgZvBwC993LbT1UOTuufTd49Q== + dependencies: + "@firebase/analytics-types" "0.4.0" + "@firebase/component" "0.4.0" + "@firebase/installations" "0.4.24" + "@firebase/logger" "0.2.6" + "@firebase/util" "0.4.1" + tslib "^2.1.0" + "@firebase/app-types@0.6.1": version "0.6.1" resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.6.1.tgz#dcbd23030a71c0c74fc95d4a3f75ba81653850e9" integrity sha512-L/ZnJRAq7F++utfuoTKX4CLBG5YR7tFO3PLzG1/oXXKEezJ0kRL3CMRoueBEmTCzVb/6SIs2Qlaw++uDgi5Xyg== +"@firebase/app-types@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.6.2.tgz#8578cb1061a83ced4570188be9e225d54e0f27fb" + integrity sha512-2VXvq/K+n8XMdM4L2xy5bYp2ZXMawJXluUIDzUBvMthVR+lhxK4pfFiqr1mmDbv9ydXvEAuFsD+6DpcZuJcSSw== + "@firebase/app@0.6.13": version "0.6.13" resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.6.13.tgz#f2e9fa9e75815e54161dc34659a60f1fffd9a450" @@ -1732,6 +1749,19 @@ tslib "^1.11.1" xmlhttprequest "1.8.0" +"@firebase/app@0.6.19": + version "0.6.19" + resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.6.19.tgz#40fe266889436ab0fcf035ee5a415db7339c1936" + integrity sha512-qDimGNoukCuWvGYcsosGV2tOKbJ98RuRHLoK2j4t73TupY6rH+4QeR3tf5E3q1gZ5mtaFZloXc6aZWWOgtfwoQ== + dependencies: + "@firebase/app-types" "0.6.2" + "@firebase/component" "0.4.0" + "@firebase/logger" "0.2.6" + "@firebase/util" "0.4.1" + dom-storage "2.1.0" + tslib "^2.1.0" + xmlhttprequest "1.8.0" + "@firebase/auth-interop-types@0.1.5": version "0.1.5" resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.1.5.tgz#9fc9bd7c879f16b8d1bb08373a0f48c3a8b74557" @@ -1742,6 +1772,11 @@ resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.10.1.tgz#7815e71c9c6f072034415524b29ca8f1d1770660" integrity sha512-/+gBHb1O9x/YlG7inXfxff/6X3BPZt4zgBv4kql6HEmdzNQCodIRlEYnI+/da+lN+dha7PjaFH7C7ewMmfV7rw== +"@firebase/auth-types@0.10.2": + version "0.10.2" + resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.10.2.tgz#3fad953380c447b7545122430a4c7a9bc8355001" + integrity sha512-0GMWVWh5TBCYIQfVerxzDsuvhoFpK0++O9LtP3FWkwYo7EAxp6w0cftAg/8ntU1E5Wg56Ry0b6ti/YGP6g0jlg== + "@firebase/auth@0.16.2": version "0.16.2" resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-0.16.2.tgz#e8fdd65c7987276bc06676e9ed990346ebe2dc51" @@ -1756,6 +1791,13 @@ dependencies: "@firebase/auth-types" "0.10.1" +"@firebase/auth@0.16.4": + version "0.16.4" + resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-0.16.4.tgz#6249d80f1e974b0db122930ae9fac885eccead5c" + integrity sha512-zgHPK6/uL6+nAyG9zqammHTF1MQpAN7z/jVRLYkDZS4l81H08b2SzApLbRfW/fmy665xqb5MK7sVH0V1wsiCNw== + dependencies: + "@firebase/auth-types" "0.10.2" + "@firebase/component@0.1.21": version "0.1.21" resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.1.21.tgz#56062eb0d449dc1e7bbef3c084a9b5fa48c7c14d" @@ -1764,6 +1806,14 @@ "@firebase/util" "0.3.4" tslib "^1.11.1" +"@firebase/component@0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.4.0.tgz#90baa455d75160c8a5134b3e9d642df11f0ac818" + integrity sha512-L7kLKpW1v5qxPfIhx/VqHuVi+vr5IcnDS4zCJFb+/eYe23i6czSOWR1urAoJ4r42Dk0XB5kDt6Idojdd9BGMEA== + dependencies: + "@firebase/util" "0.4.1" + tslib "^2.1.0" + "@firebase/database-types@0.6.1", "@firebase/database-types@^0.6.1": version "0.6.1" resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-0.6.1.tgz#cf1cfc03e617ed4c2561703781f85ba4c707ff65" @@ -1778,6 +1828,13 @@ dependencies: "@firebase/app-types" "0.6.1" +"@firebase/database-types@0.7.1": + version "0.7.1" + resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-0.7.1.tgz#3505e3e8d57e94a3ce6038649a95afe0af040757" + integrity sha512-465ceJXSMqFFMnL2lxYx+YhYajcyk+VpGiXf9T6KNME0lKne5hYuqYr7XmS8/sTeyV0huhmTb8K1nxlA7hiPOg== + dependencies: + "@firebase/app-types" "0.6.2" + "@firebase/database@0.9.0": version "0.9.0" resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.9.0.tgz#eaf07dbaf3433be6cc27543c1823dc3c88c47572" @@ -1817,6 +1874,19 @@ faye-websocket "0.11.3" tslib "^1.11.1" +"@firebase/database@0.9.8": + version "0.9.8" + resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.9.8.tgz#244eb897033ecacfc4a1fa5f031cda9b5e4009e5" + integrity sha512-bqZUDR6jIQSQcY7oZVGmI/Bg7SfmUUW/toaZBCfaddWAnniBthaa8o0Hyv1ypPxjEZCu1CfPQwtpMhlSTjG0tA== + dependencies: + "@firebase/auth-interop-types" "0.1.5" + "@firebase/component" "0.4.0" + "@firebase/database-types" "0.7.1" + "@firebase/logger" "0.2.6" + "@firebase/util" "0.4.1" + faye-websocket "0.11.3" + tslib "^2.1.0" + "@firebase/database@^0.8.1": version "0.8.3" resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.8.3.tgz#4e5efa8fc8df00d6febfd9c8d6d6e409596659f7" @@ -1835,6 +1905,11 @@ resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-2.1.0.tgz#ad406c6fd7f0eae7ea52979f712daa0166aef665" integrity sha512-jietErBWihMvJkqqEquQy5GgoEwzHnMXXC/TsVoe9FPysXm1/AeJS12taS7ZYvenAtyvL/AEJyKrRKRh4adcJQ== +"@firebase/firestore-types@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-2.2.0.tgz#9a3f3f2906232c3b4a726d988a6ef077f35f9093" + integrity sha512-5kZZtQ32FIRJP1029dw+ZVNRCclKOErHv1+Xn0pw/5Fq3dxroA/ZyFHqDu+uV52AyWHhNLjCqX43ibm4YqOzRw== + "@firebase/firestore@2.1.3": version "2.1.3" resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-2.1.3.tgz#74b99c9365a26ea101045c0600641064621cb341" @@ -1880,6 +1955,21 @@ node-fetch "2.6.1" tslib "^1.11.1" +"@firebase/firestore@2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-2.2.3.tgz#e76d9191c48ef4c51ae73c2fcce7d547be2a8c17" + integrity sha512-efJxJahP9936QlIHeATvatCO4c3UEk6nz7pc812xxkgTVezkg8K66IDUe0fncV70zbDrIyxUIl8yRcxhXytiGw== + dependencies: + "@firebase/component" "0.4.0" + "@firebase/firestore-types" "2.2.0" + "@firebase/logger" "0.2.6" + "@firebase/util" "0.4.1" + "@firebase/webchannel-wrapper" "0.4.1" + "@grpc/grpc-js" "^1.0.0" + "@grpc/proto-loader" "^0.5.0" + node-fetch "2.6.1" + tslib "^2.1.0" + "@firebase/functions-types@0.4.0": version "0.4.0" resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.4.0.tgz#0b789f4fe9a9c0b987606c4da10139345b40f6b9" @@ -1896,6 +1986,17 @@ node-fetch "2.6.1" tslib "^1.11.1" +"@firebase/functions@0.6.6": + version "0.6.6" + resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.6.6.tgz#06b786e68b269a615fc83598d99cda7b11ec740e" + integrity sha512-cvZiqcL3X7+6ObkwcRUV54iFHaVxVgio2t610p2qwjzMxyYfiHWDA+GwKPioObDWqyXmNtkU8cw2WLoGf46cnA== + dependencies: + "@firebase/component" "0.4.0" + "@firebase/functions-types" "0.4.0" + "@firebase/messaging-types" "0.5.0" + node-fetch "2.6.1" + tslib "^2.1.0" + "@firebase/installations-types@0.3.4": version "0.3.4" resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.3.4.tgz#589a941d713f4f64bf9f4feb7f463505bab1afa2" @@ -1912,6 +2013,17 @@ idb "3.0.2" tslib "^1.11.1" +"@firebase/installations@0.4.24": + version "0.4.24" + resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.4.24.tgz#acaf3d48c156f3a3a5ddb53e8e8c63a89fce2f55" + integrity sha512-cMWI3IfnmdJ4SzPav56yaHwEhpPPl5b03AVtv7AeKnmDZ61eBqPzEnYSL8Iso73/FeKpr8BYcZelAx0EyxcJ3Q== + dependencies: + "@firebase/component" "0.4.0" + "@firebase/installations-types" "0.3.4" + "@firebase/util" "0.4.1" + idb "3.0.2" + tslib "^2.1.0" + "@firebase/logger@0.2.6": version "0.2.6" resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.2.6.tgz#3aa2ca4fe10327cabf7808bd3994e88db26d7989" @@ -1934,11 +2046,35 @@ idb "3.0.2" tslib "^1.11.1" +"@firebase/messaging@0.7.8": + version "0.7.8" + resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.7.8.tgz#90119a2f1cd5055fd61206732024e0281de80616" + integrity sha512-rXYvVQPZd+rCMV7+/FgpvsHad0HuEhoyH5OQgYxeBgSsgFn6mOyvAtYcoCFjPTvTV5eyGH1I4hQtNOyY8zVzzg== + dependencies: + "@firebase/component" "0.4.0" + "@firebase/installations" "0.4.24" + "@firebase/messaging-types" "0.5.0" + "@firebase/util" "0.4.1" + idb "3.0.2" + tslib "^2.1.0" + "@firebase/performance-types@0.0.13": version "0.0.13" resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.0.13.tgz#58ce5453f57e34b18186f74ef11550dfc558ede6" integrity sha512-6fZfIGjQpwo9S5OzMpPyqgYAUZcFzZxHFqOyNtorDIgNXq33nlldTL/vtaUZA8iT9TT5cJlCrF/jthKU7X21EA== +"@firebase/performance@0.4.10": + version "0.4.10" + resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.4.10.tgz#c78ed1c15c26884eae23edf1498e930bb729b51f" + integrity sha512-gyAOd9Z/GVlLE5V8U5pVQDZpjr4Msdx5yJr7oQE/xkh6dNZGuYp5qJh1pAmJs2ZI8eMTs+j2bXJEMYk6w7ehRg== + dependencies: + "@firebase/component" "0.4.0" + "@firebase/installations" "0.4.24" + "@firebase/logger" "0.2.6" + "@firebase/performance-types" "0.0.13" + "@firebase/util" "0.4.1" + tslib "^2.1.0" + "@firebase/performance@0.4.5": version "0.4.5" resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.4.5.tgz#3ab89208ed6fb80165e5594058e46dc85113cd78" @@ -1977,6 +2113,18 @@ "@firebase/util" "0.3.4" tslib "^1.11.1" +"@firebase/remote-config@0.1.35": + version "0.1.35" + resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.1.35.tgz#792b6d9e2d8e5db0a883ee53579629c2412ae1f5" + integrity sha512-szhu48LTyb46S33hUR3sC4kiykEoc+B5M7HWWHhjp7Ne+524G8pH/9+/r9ZA8eVj48c5cihXyQKQ/6yCQotnUA== + dependencies: + "@firebase/component" "0.4.0" + "@firebase/installations" "0.4.24" + "@firebase/logger" "0.2.6" + "@firebase/remote-config-types" "0.1.9" + "@firebase/util" "0.4.1" + tslib "^2.1.0" + "@firebase/rules-unit-testing@^1.0.3": version "1.1.9" resolved "https://registry.yarnpkg.com/@firebase/rules-unit-testing/-/rules-unit-testing-1.1.9.tgz#aa867c3faf8b2fc2310710dabd6df759b32e80aa" @@ -2002,6 +2150,16 @@ "@firebase/util" "0.3.4" tslib "^1.11.1" +"@firebase/storage@0.4.7": + version "0.4.7" + resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.4.7.tgz#541a2d96af6da9c345b190858345c1106650fce0" + integrity sha512-5DFb+VncNBomPzpzYqJzzJjfiZhOWg0FHTBkw90K9OdE2wUfKqzhhbIAjyaXcu+2YLB2hjft8BKbjQfV5BDFnw== + dependencies: + "@firebase/component" "0.4.0" + "@firebase/storage-types" "0.3.13" + "@firebase/util" "0.4.1" + tslib "^2.1.0" + "@firebase/util@0.3.4": version "0.3.4" resolved "https://registry.yarnpkg.com/@firebase/util/-/util-0.3.4.tgz#e389d0e0e2aac88a5235b06ba9431db999d4892b" @@ -2009,6 +2167,13 @@ dependencies: tslib "^1.11.1" +"@firebase/util@0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@firebase/util/-/util-0.4.1.tgz#fe76cf0238901dc5455b341cf02e298e7bf68df4" + integrity sha512-XhYCOwq4AH+YeQBEnDQvigz50WiiBU4LnJh2+//VMt4J2Ybsk0eTgUHNngUzXsmp80EJrwal3ItODg55q1ajWg== + dependencies: + tslib "^2.1.0" + "@firebase/webchannel-wrapper@0.4.1": version "0.4.1" resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.4.1.tgz#600f2275ff54739ad5ac0102f1467b8963cd5f71" @@ -11044,6 +11209,26 @@ firebase@^8.2.7: "@firebase/storage" "0.4.2" "@firebase/util" "0.3.4" +firebase@^8.3.2: + version "8.3.3" + resolved "https://registry.yarnpkg.com/firebase/-/firebase-8.3.3.tgz#21d8fb8eec2c43b0d8f98ab6bda5535b7454fa54" + integrity sha512-eRkW7bD25aevlGwtCEsP53xBo5/Fi4wkxvfvmDW6R2/oSHjy+hVLkQILP4kQFFXgFL0LBjxIPOchXoQ5MUbTCA== + dependencies: + "@firebase/analytics" "0.6.8" + "@firebase/app" "0.6.19" + "@firebase/app-types" "0.6.2" + "@firebase/auth" "0.16.4" + "@firebase/database" "0.9.8" + "@firebase/firestore" "2.2.3" + "@firebase/functions" "0.6.6" + "@firebase/installations" "0.4.24" + "@firebase/messaging" "0.7.8" + "@firebase/performance" "0.4.10" + "@firebase/polyfill" "0.3.36" + "@firebase/remote-config" "0.1.35" + "@firebase/storage" "0.4.7" + "@firebase/util" "0.4.1" + flat-arguments@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/flat-arguments/-/flat-arguments-1.0.2.tgz#9baa780adf0501f282d726c9c6a038dba44ea76f" @@ -22896,6 +23081,11 @@ tslib@^2, tslib@^2.0.0, tslib@^2.0.3, tslib@~2.1.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== +tslib@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" + integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== + tslib@~2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c"