From 4ec89ebd69514c55272735cb32f725b51496468f Mon Sep 17 00:00:00 2001 From: forehalo Date: Wed, 31 Jul 2024 07:59:22 +0000 Subject: [PATCH] chore(server): standardize server db names and columns (#7674) --- .../migration.sql | 146 ++++++++++ packages/backend/server/schema.prisma | 264 ++++++------------ .../server/src/core/features/feature.ts | 2 +- .../server/src/core/features/service.ts | 32 +-- .../backend/server/src/core/quota/quota.ts | 2 +- .../backend/server/src/core/quota/service.ts | 15 +- .../1698652531198-user-features-init.ts | 3 +- .../1699005339766-page-permission.ts | 94 ------- .../1702620653283-old-user-feature.ts | 6 +- .../1703828796699-workspace-blobs.ts | 38 --- .../data/migrations/1710319359062-oauth.ts | 39 --- .../data/migrations/utils/user-features.ts | 74 +---- .../src/data/migrations/utils/user-quotas.ts | 6 +- .../server/src/plugins/payment/service.ts | 12 +- tests/kit/utils/cloud.ts | 2 +- 15 files changed, 276 insertions(+), 459 deletions(-) create mode 100644 packages/backend/server/migrations/20240731043837_standardize_table_columns/migration.sql delete mode 100644 packages/backend/server/src/data/migrations/1699005339766-page-permission.ts delete mode 100644 packages/backend/server/src/data/migrations/1703828796699-workspace-blobs.ts delete mode 100644 packages/backend/server/src/data/migrations/1710319359062-oauth.ts diff --git a/packages/backend/server/migrations/20240731043837_standardize_table_columns/migration.sql b/packages/backend/server/migrations/20240731043837_standardize_table_columns/migration.sql new file mode 100644 index 0000000000..10dec4496b --- /dev/null +++ b/packages/backend/server/migrations/20240731043837_standardize_table_columns/migration.sql @@ -0,0 +1,146 @@ +-- AlterTable +ALTER TABLE "_data_migrations" ALTER COLUMN "id" SET DATA TYPE VARCHAR, +ALTER COLUMN "started_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "finished_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "ai_prompts_messages" ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "ai_prompts_metadata" ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "ai_sessions_messages" ALTER COLUMN "id" SET DATA TYPE VARCHAR, +ALTER COLUMN "session_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "updated_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "ai_sessions_metadata" ALTER COLUMN "id" SET DATA TYPE VARCHAR, +ALTER COLUMN "user_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "workspace_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "doc_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "deleted_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "parent_session_id" SET DATA TYPE VARCHAR; + +-- AlterTable +ALTER TABLE "app_runtime_settings" ALTER COLUMN "updated_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "deleted_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "last_updated_by" SET DATA TYPE VARCHAR; + +-- AlterTable +ALTER TABLE "features" ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "multiple_users_sessions" ALTER COLUMN "id" SET DATA TYPE VARCHAR, +ALTER COLUMN "expires_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "snapshot_histories" +ALTER COLUMN "workspace_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "guid" SET DATA TYPE VARCHAR, +ALTER COLUMN "timestamp" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "expired_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "snapshots" ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "updated_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "updates" ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "user_connected_accounts" ALTER COLUMN "id" SET DATA TYPE VARCHAR, +ALTER COLUMN "user_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "expires_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "updated_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "user_features" ALTER COLUMN "user_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "expired_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "user_invoices" ALTER COLUMN "user_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "updated_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "user_sessions" ALTER COLUMN "id" SET DATA TYPE VARCHAR, +ALTER COLUMN "session_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "user_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "expires_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "user_stripe_customers" ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "user_subscriptions" ALTER COLUMN "user_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "start" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "end" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "next_bill_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "canceled_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "trial_start" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "trial_end" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "updated_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "users" ALTER COLUMN "name" SET DATA TYPE VARCHAR, +ALTER COLUMN "email" SET DATA TYPE VARCHAR, +ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "verification_tokens" ALTER COLUMN "token" SET DATA TYPE VARCHAR, +ALTER COLUMN "expiresAt" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "workspace_features" ALTER COLUMN "workspace_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3), +ALTER COLUMN "expired_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "workspace_page_user_permissions" +ALTER COLUMN "id" SET DATA TYPE VARCHAR, +ALTER COLUMN "workspace_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "page_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "user_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "workspace_pages" ALTER COLUMN "workspace_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "page_id" SET DATA TYPE VARCHAR; + +-- AlterTable +ALTER TABLE "workspace_user_permissions" ALTER COLUMN "id" SET DATA TYPE VARCHAR, +ALTER COLUMN "workspace_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "user_id" SET DATA TYPE VARCHAR, +ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "workspaces" ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3); + +-- DropTable +DROP TABLE "accounts"; + +-- DropTable +DROP TABLE "blobs"; + +-- DropTable +DROP TABLE "new_features_waiting_list"; + +-- DropTable +DROP TABLE "optimized_blobs"; + +-- DropTable +DROP TABLE "sessions"; + +-- DropTable +DROP TABLE "user_workspace_permissions"; + +-- DropTable +DROP TABLE "verificationtokens"; diff --git a/packages/backend/server/schema.prisma b/packages/backend/server/schema.prisma index e5162ee508..b766e48153 100644 --- a/packages/backend/server/schema.prisma +++ b/packages/backend/server/schema.prisma @@ -11,18 +11,18 @@ datasource db { model User { id String @id @default(uuid()) @db.VarChar - name String - email String @unique - emailVerifiedAt DateTime? @map("email_verified") + name String @db.VarChar + email String @unique @db.VarChar + emailVerifiedAt DateTime? @map("email_verified") @db.Timestamp(3) avatarUrl String? @map("avatar_url") @db.VarChar - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) /// Not available if user signed up through OAuth providers password String? @db.VarChar /// Indicate whether the user finished the signup progress. /// for example, the value will be false if user never registered and invited into a workspace by others. registered Boolean @default(true) - features UserFeatures[] + features UserFeature[] customer UserStripeCustomer? subscriptions UserSubscription[] invoices UserInvoice[] @@ -38,16 +38,16 @@ model User { } model ConnectedAccount { - id String @id @default(uuid()) @db.VarChar(36) - userId String @map("user_id") @db.VarChar(36) + id String @id @default(uuid()) @db.VarChar + userId String @map("user_id") @db.VarChar provider String @db.VarChar providerAccountId String @map("provider_account_id") @db.VarChar scope String? @db.Text accessToken String? @map("access_token") @db.Text refreshToken String? @map("refresh_token") @db.Text - expiresAt DateTime? @map("expires_at") @db.Timestamptz(6) - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) + expiresAt DateTime? @map("expires_at") @db.Timestamp(3) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamp(3) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@ -57,9 +57,9 @@ model ConnectedAccount { } model Session { - id String @id @default(uuid()) @db.VarChar(36) - expiresAt DateTime? @map("expires_at") @db.Timestamptz(6) - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + id String @id @default(uuid()) @db.VarChar + expiresAt DateTime? @map("expires_at") @db.Timestamp(3) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) userSessions UserSession[] @@ -67,11 +67,11 @@ model Session { } model UserSession { - id String @id @default(uuid()) @db.VarChar(36) - sessionId String @map("session_id") @db.VarChar(36) - userId String @map("user_id") @db.VarChar(36) - expiresAt DateTime? @map("expires_at") @db.Timestamptz(6) - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + id String @id @default(uuid()) @db.VarChar + sessionId String @map("session_id") @db.VarChar + userId String @map("user_id") @db.VarChar + expiresAt DateTime? @map("expires_at") @db.Timestamp(3) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) session Session @relation(fields: [sessionId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@ -81,10 +81,10 @@ model UserSession { } model VerificationToken { - token String @db.VarChar(36) + token String @db.VarChar type Int @db.SmallInt credential String? @db.Text - expiresAt DateTime @db.Timestamptz(6) + expiresAt DateTime @db.Timestamp(3) @@unique([type, token]) @@map("verification_tokens") @@ -93,12 +93,12 @@ model VerificationToken { model Workspace { id String @id @default(uuid()) @db.VarChar public Boolean - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) pages WorkspacePage[] permissions WorkspaceUserPermission[] pagePermissions WorkspacePageUserPermission[] - features WorkspaceFeatures[] + features WorkspaceFeature[] @@map("workspaces") } @@ -109,8 +109,8 @@ model Workspace { // Only the ones that have ever changed will have records here, // and for others we will make sure it's has a default value return in our bussiness logic. model WorkspacePage { - workspaceId String @map("workspace_id") @db.VarChar(36) - pageId String @map("page_id") @db.VarChar(36) + workspaceId String @map("workspace_id") @db.VarChar + pageId String @map("page_id") @db.VarChar public Boolean @default(false) // Page/Edgeless mode Int @default(0) @db.SmallInt @@ -121,31 +121,15 @@ model WorkspacePage { @@map("workspace_pages") } -// @deprecated, use WorkspaceUserPermission -model DeprecatedUserWorkspacePermission { +model WorkspaceUserPermission { id String @id @default(uuid()) @db.VarChar workspaceId String @map("workspace_id") @db.VarChar - subPageId String? @map("sub_page_id") @db.VarChar - userId String? @map("entity_id") @db.VarChar - /// Read/Write/Admin/Owner - type Int @db.SmallInt - /// Whether the permission invitation is accepted by the user - accepted Boolean @default(false) - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - - @@unique([workspaceId, subPageId, userId]) - @@map("user_workspace_permissions") -} - -model WorkspaceUserPermission { - id String @id @default(uuid()) @db.VarChar(36) - workspaceId String @map("workspace_id") @db.VarChar(36) - userId String @map("user_id") @db.VarChar(36) + userId String @map("user_id") @db.VarChar // Read/Write type Int @db.SmallInt /// Whether the permission invitation is accepted by the user accepted Boolean @default(false) - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) user User @relation(fields: [userId], references: [id], onDelete: Cascade) workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade) @@ -155,15 +139,15 @@ model WorkspaceUserPermission { } model WorkspacePageUserPermission { - id String @id @default(uuid()) @db.VarChar(36) - workspaceId String @map("workspace_id") @db.VarChar(36) - pageId String @map("page_id") @db.VarChar(36) - userId String @map("user_id") @db.VarChar(36) + id String @id @default(uuid()) @db.VarChar + workspaceId String @map("workspace_id") @db.VarChar + pageId String @map("page_id") @db.VarChar + userId String @map("user_id") @db.VarChar // Read/Write type Int @db.SmallInt /// Whether the permission invitation is accepted by the user accepted Boolean @default(false) - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) user User @relation(fields: [userId], references: [id], onDelete: Cascade) workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade) @@ -176,9 +160,9 @@ model WorkspacePageUserPermission { // for example: // - early access is a feature that allow some users to access the insider version // - pro plan is a quota that allow some users access to more resources after they pay -model UserFeatures { +model UserFeature { id Int @id @default(autoincrement()) - userId String @map("user_id") @db.VarChar(36) + userId String @map("user_id") @db.VarChar featureId Int @map("feature_id") @db.Integer // we will record the reason why the feature is enabled/disabled @@ -186,16 +170,16 @@ model UserFeatures { // - pro_plan_v1: "user buy the pro plan" reason String @db.VarChar // record the quota enabled time - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) // record the quota expired time, pay plan is a subscription, so it will expired - expiredAt DateTime? @map("expired_at") @db.Timestamptz(6) + expiredAt DateTime? @map("expired_at") @db.Timestamp(3) // whether the feature is activated // for example: // - if we switch the user to another plan, we will set the old plan to deactivated, but dont delete it activated Boolean @default(false) - feature Features @relation(fields: [featureId], references: [id], onDelete: Cascade) - user User @relation(fields: [userId], references: [id], onDelete: Cascade) + feature Feature @relation(fields: [featureId], references: [id], onDelete: Cascade) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@map("user_features") @@ -204,9 +188,9 @@ model UserFeatures { // feature gates is a way to enable/disable features for a workspace // for example: // - copilet is a feature that allow some users in a workspace to access the copilet feature -model WorkspaceFeatures { +model WorkspaceFeature { id Int @id @default(autoincrement()) - workspaceId String @map("workspace_id") @db.VarChar(36) + workspaceId String @map("workspace_id") @db.VarChar featureId Int @map("feature_id") @db.Integer // we will record the reason why the feature is enabled/disabled @@ -214,21 +198,21 @@ model WorkspaceFeatures { // - copilet_v1: "owner buy the copilet feature package" reason String @db.VarChar // record the feature enabled time - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) // record the quota expired time, pay plan is a subscription, so it will expired - expiredAt DateTime? @map("expired_at") @db.Timestamptz(6) + expiredAt DateTime? @map("expired_at") @db.Timestamp(3) // whether the feature is activated // for example: // - if owner unsubscribe a feature package, we will set the feature to deactivated, but dont delete it activated Boolean @default(false) - feature Features @relation(fields: [featureId], references: [id], onDelete: Cascade) + feature Feature @relation(fields: [featureId], references: [id], onDelete: Cascade) workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade) @@map("workspace_features") } -model Features { +model Feature { id Int @id @default(autoincrement()) feature String @db.VarChar version Int @default(0) @db.Integer @@ -236,82 +220,15 @@ model Features { type Int @db.Integer // configs, define by feature conntroller configs Json @db.Json - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) - UserFeatureGates UserFeatures[] - WorkspaceFeatures WorkspaceFeatures[] + UserFeatureGates UserFeature[] + WorkspaceFeatures WorkspaceFeature[] @@unique([feature, version]) @@map("features") } -model DeprecatedNextAuthAccount { - id String @id @default(cuid()) - userId String @map("user_id") - type String - provider String - providerAccountId String @map("provider_account_id") - refresh_token String? @db.Text - access_token String? @db.Text - expires_at Int? - token_type String? - scope String? - id_token String? @db.Text - session_state String? - - @@unique([provider, providerAccountId]) - @@map("accounts") -} - -model DeprecatedNextAuthSession { - id String @id @default(cuid()) - sessionToken String @unique @map("session_token") - userId String @map("user_id") - expires DateTime - - @@map("sessions") -} - -model DeprecatedNextAuthVerificationToken { - identifier String - token String @unique - expires DateTime - - @@unique([identifier, token]) - @@map("verificationtokens") -} - -// deprecated, use [ObjectStorage] -model Blob { - id Int @id @default(autoincrement()) @db.Integer - hash String @db.VarChar - workspaceId String @map("workspace_id") @db.VarChar - blob Bytes @db.ByteA - length BigInt - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - // not for keeping, but for snapshot history - deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6) - - @@unique([workspaceId, hash]) - @@map("blobs") -} - -// deprecated, use [ObjectStorage] -model OptimizedBlob { - id Int @id @default(autoincrement()) @db.Integer - hash String @db.VarChar - workspaceId String @map("workspace_id") @db.VarChar - params String @db.VarChar - blob Bytes @db.ByteA - length BigInt - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - // not for keeping, but for snapshot history - deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6) - - @@unique([workspaceId, hash, params]) - @@map("optimized_blobs") -} - // the latest snapshot of each doc that we've seen // Snapshot + Updates are the latest state of the doc model Snapshot { @@ -320,10 +237,10 @@ model Snapshot { blob Bytes @db.ByteA seq Int @default(0) @db.Integer state Bytes? @db.ByteA - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) // the `updated_at` field will not record the time of record changed, // but the created time of last seen update that has been merged into snapshot. - updatedAt DateTime @map("updated_at") @db.Timestamptz(6) + updatedAt DateTime @map("updated_at") @db.Timestamp(3) @@id([id, workspaceId]) @@map("snapshots") @@ -334,37 +251,28 @@ model Update { id String @map("guid") @db.VarChar seq Int @db.Integer blob Bytes @db.ByteA - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) @@id([workspaceId, id, seq]) @@map("updates") } model SnapshotHistory { - workspaceId String @map("workspace_id") @db.VarChar(36) - id String @map("guid") @db.VarChar(36) - timestamp DateTime @db.Timestamptz(6) + workspaceId String @map("workspace_id") @db.VarChar + id String @map("guid") @db.VarChar + timestamp DateTime @db.Timestamp(3) blob Bytes @db.ByteA state Bytes? @db.ByteA - expiredAt DateTime @map("expired_at") @db.Timestamptz(6) + expiredAt DateTime @map("expired_at") @db.Timestamp(3) @@id([workspaceId, id, timestamp]) @@map("snapshot_histories") } -model NewFeaturesWaitingList { - id String @id @default(uuid()) @db.VarChar - email String @unique - type Int @db.SmallInt - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - - @@map("new_features_waiting_list") -} - model UserStripeCustomer { userId String @id @map("user_id") @db.VarChar stripeCustomerId String @unique @map("stripe_customer_id") @db.VarChar - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@ -373,7 +281,7 @@ model UserStripeCustomer { model UserSubscription { id Int @id @default(autoincrement()) @db.Integer - userId String @map("user_id") @db.VarChar(36) + userId String @map("user_id") @db.VarChar plan String @db.VarChar(20) // yearly/monthly recurring String @db.VarChar(20) @@ -382,21 +290,21 @@ model UserSubscription { // subscription.status, active/past_due/canceled/unpaid... status String @db.VarChar(20) // subscription.current_period_start - start DateTime @map("start") @db.Timestamptz(6) + start DateTime @map("start") @db.Timestamp(3) // subscription.current_period_end, null for lifetime payment - end DateTime? @map("end") @db.Timestamptz(6) + end DateTime? @map("end") @db.Timestamp(3) // subscription.billing_cycle_anchor - nextBillAt DateTime? @map("next_bill_at") @db.Timestamptz(6) + nextBillAt DateTime? @map("next_bill_at") @db.Timestamp(3) // subscription.canceled_at - canceledAt DateTime? @map("canceled_at") @db.Timestamptz(6) + canceledAt DateTime? @map("canceled_at") @db.Timestamp(3) // subscription.trial_start - trialStart DateTime? @map("trial_start") @db.Timestamptz(6) + trialStart DateTime? @map("trial_start") @db.Timestamp(3) // subscription.trial_end - trialEnd DateTime? @map("trial_end") @db.Timestamptz(6) + trialEnd DateTime? @map("trial_end") @db.Timestamp(3) stripeScheduleId String? @map("stripe_schedule_id") @db.VarChar - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamp(3) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([userId, plan]) @@ -405,7 +313,7 @@ model UserSubscription { model UserInvoice { id Int @id @default(autoincrement()) @db.Integer - userId String @map("user_id") @db.VarChar(36) + userId String @map("user_id") @db.VarChar stripeInvoiceId String @unique @map("stripe_invoice_id") currency String @db.VarChar(3) // CNY 12.50 stored as 1250 @@ -413,8 +321,8 @@ model UserInvoice { status String @db.VarChar(20) plan String @db.VarChar(20) recurring String @db.VarChar(20) - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamp(3) // billing reason reason String @db.VarChar lastPaymentError String? @map("last_payment_error") @db.Text @@ -442,7 +350,7 @@ model AiPromptMessage { content String @db.Text attachments Json? @db.Json params Json? @db.Json - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) prompt AiPrompt @relation(fields: [promptId], references: [id], onDelete: Cascade) @@ -458,7 +366,7 @@ model AiPrompt { action String? @db.VarChar model String @db.VarChar config Json? @db.Json - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) messages AiPromptMessage[] sessions AiSession[] @@ -467,14 +375,14 @@ model AiPrompt { } model AiSessionMessage { - id String @id @default(uuid()) @db.VarChar(36) - sessionId String @map("session_id") @db.VarChar(36) + id String @id @default(uuid()) @db.VarChar + sessionId String @map("session_id") @db.VarChar role AiPromptRole content String @db.Text attachments Json? @db.Json params Json? @db.Json - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamp(3) session AiSession @relation(fields: [sessionId], references: [id], onDelete: Cascade) @@ -482,17 +390,17 @@ model AiSessionMessage { } model AiSession { - id String @id @default(uuid()) @db.VarChar(36) - userId String @map("user_id") @db.VarChar(36) - workspaceId String @map("workspace_id") @db.VarChar(36) - docId String @map("doc_id") @db.VarChar(36) + id String @id @default(uuid()) @db.VarChar + userId String @map("user_id") @db.VarChar + workspaceId String @map("workspace_id") @db.VarChar + docId String @map("doc_id") @db.VarChar promptName String @map("prompt_name") @db.VarChar(32) // the session id of the parent session if this session is a forked session - parentSessionId String? @map("parent_session_id") @db.VarChar(36) + parentSessionId String? @map("parent_session_id") @db.VarChar messageCost Int @default(0) tokenCost Int @default(0) - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6) + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3) + deletedAt DateTime? @map("deleted_at") @db.Timestamp(3) user User @relation(fields: [userId], references: [id], onDelete: Cascade) prompt AiPrompt @relation(fields: [promptName], references: [name], onDelete: Cascade) @@ -502,10 +410,10 @@ model AiSession { } model DataMigration { - id String @id @default(uuid()) @db.VarChar(36) + id String @id @default(uuid()) @db.VarChar name String @db.VarChar - startedAt DateTime @default(now()) @map("started_at") @db.Timestamptz(6) - finishedAt DateTime? @map("finished_at") @db.Timestamptz(6) + startedAt DateTime @default(now()) @map("started_at") @db.Timestamp(3) + finishedAt DateTime? @map("finished_at") @db.Timestamp(3) @@map("_data_migrations") } @@ -525,9 +433,9 @@ model RuntimeConfig { key String @db.VarChar value Json @db.Json description String @db.Text - updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) - deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6) - lastUpdatedBy String? @map("last_updated_by") @db.VarChar(36) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamp(3) + deletedAt DateTime? @map("deleted_at") @db.Timestamp(3) + lastUpdatedBy String? @map("last_updated_by") @db.VarChar lastUpdatedByUser User? @relation(fields: [lastUpdatedBy], references: [id]) diff --git a/packages/backend/server/src/core/features/feature.ts b/packages/backend/server/src/core/features/feature.ts index 083d016870..c52fb96bfc 100644 --- a/packages/backend/server/src/core/features/feature.ts +++ b/packages/backend/server/src/core/features/feature.ts @@ -32,7 +32,7 @@ export async function getFeature(prisma: PrismaTransaction, featureId: number) { return cachedFeature; } - const feature = await prisma.features.findFirst({ + const feature = await prisma.feature.findFirst({ where: { id: featureId, }, diff --git a/packages/backend/server/src/core/features/service.ts b/packages/backend/server/src/core/features/service.ts index 21e9e04d38..3dd60a6cce 100644 --- a/packages/backend/server/src/core/features/service.ts +++ b/packages/backend/server/src/core/features/service.ts @@ -10,7 +10,7 @@ export class FeatureService { constructor(private readonly prisma: PrismaClient) {} async getFeature(feature: F) { - const data = await this.prisma.features.findFirst({ + const data = await this.prisma.feature.findFirst({ where: { feature, type: FeatureKind.Feature, @@ -36,7 +36,7 @@ export class FeatureService { expiredAt?: Date | string ) { return this.prisma.$transaction(async tx => { - const latestFlag = await tx.userFeatures.findFirst({ + const latestFlag = await tx.userFeature.findFirst({ where: { userId, feature: { @@ -53,7 +53,7 @@ export class FeatureService { if (latestFlag) { return latestFlag.id; } else { - const featureId = await tx.features + const featureId = await tx.feature .findFirst({ where: { feature, type: FeatureKind.Feature }, orderBy: { version: 'desc' }, @@ -65,7 +65,7 @@ export class FeatureService { throw new Error(`Feature ${feature} not found`); } - return tx.userFeatures + return tx.userFeature .create({ data: { reason, @@ -81,7 +81,7 @@ export class FeatureService { } async removeUserFeature(userId: string, feature: FeatureType) { - return this.prisma.userFeatures + return this.prisma.userFeature .updateMany({ where: { userId, @@ -104,7 +104,7 @@ export class FeatureService { * @returns list of features */ async getUserFeatures(userId: string) { - const features = await this.prisma.userFeatures.findMany({ + const features = await this.prisma.userFeature.findMany({ where: { userId, feature: { type: FeatureKind.Feature }, @@ -129,7 +129,7 @@ export class FeatureService { } async getActivatedUserFeatures(userId: string) { - const features = await this.prisma.userFeatures.findMany({ + const features = await this.prisma.userFeature.findMany({ where: { userId, feature: { type: FeatureKind.Feature }, @@ -156,7 +156,7 @@ export class FeatureService { } async listFeatureUsers(feature: FeatureType) { - return this.prisma.userFeatures + return this.prisma.userFeature .findMany({ where: { activated: true, @@ -182,7 +182,7 @@ export class FeatureService { } async hasUserFeature(userId: string, feature: FeatureType) { - return this.prisma.userFeatures + return this.prisma.userFeature .count({ where: { userId, @@ -206,7 +206,7 @@ export class FeatureService { expiredAt?: Date | string ) { return this.prisma.$transaction(async tx => { - const latestFlag = await tx.workspaceFeatures.findFirst({ + const latestFlag = await tx.workspaceFeature.findFirst({ where: { workspaceId, feature: { @@ -223,7 +223,7 @@ export class FeatureService { return latestFlag.id; } else { // use latest version of feature - const featureId = await tx.features + const featureId = await tx.feature .findFirst({ where: { feature, type: FeatureKind.Feature }, select: { id: true }, @@ -235,7 +235,7 @@ export class FeatureService { throw new Error(`Feature ${feature} not found`); } - return tx.workspaceFeatures + return tx.workspaceFeature .create({ data: { reason, @@ -251,7 +251,7 @@ export class FeatureService { } async removeWorkspaceFeature(workspaceId: string, feature: FeatureType) { - return this.prisma.workspaceFeatures + return this.prisma.workspaceFeature .updateMany({ where: { workspaceId, @@ -274,7 +274,7 @@ export class FeatureService { * @returns list of features */ async getWorkspaceFeatures(workspaceId: string) { - const features = await this.prisma.workspaceFeatures.findMany({ + const features = await this.prisma.workspaceFeature.findMany({ where: { workspace: { id: workspaceId }, feature: { @@ -301,7 +301,7 @@ export class FeatureService { } async listFeatureWorkspaces(feature: FeatureType): Promise { - return this.prisma.workspaceFeatures + return this.prisma.workspaceFeature .findMany({ where: { activated: true, @@ -324,7 +324,7 @@ export class FeatureService { } async hasWorkspaceFeature(workspaceId: string, feature: FeatureType) { - return this.prisma.workspaceFeatures + return this.prisma.workspaceFeature .count({ where: { workspaceId, diff --git a/packages/backend/server/src/core/quota/quota.ts b/packages/backend/server/src/core/quota/quota.ts index 61422a7c42..752324a976 100644 --- a/packages/backend/server/src/core/quota/quota.ts +++ b/packages/backend/server/src/core/quota/quota.ts @@ -13,7 +13,7 @@ export class QuotaConfig { return cachedQuota; } - const quota = await tx.features.findFirst({ + const quota = await tx.feature.findFirst({ where: { id: featureId, }, diff --git a/packages/backend/server/src/core/quota/service.ts b/packages/backend/server/src/core/quota/service.ts index 4e2a34c840..7808dcbfa6 100644 --- a/packages/backend/server/src/core/quota/service.ts +++ b/packages/backend/server/src/core/quota/service.ts @@ -17,7 +17,7 @@ export class QuotaService { // get activated user quota async getUserQuota(userId: string) { - const quota = await this.prisma.userFeatures.findFirst({ + const quota = await this.prisma.userFeature.findFirst({ where: { userId, feature: { @@ -44,7 +44,7 @@ export class QuotaService { // get user all quota records async getUserQuotas(userId: string) { - const quotas = await this.prisma.userFeatures.findMany({ + const quotas = await this.prisma.userFeature.findMany({ where: { userId, feature: { @@ -58,6 +58,9 @@ export class QuotaService { expiredAt: true, featureId: true, }, + orderBy: { + id: 'asc', + }, }); const configs = await Promise.all( quotas.map(async quota => { @@ -92,7 +95,7 @@ export class QuotaService { return; } - const featureId = await tx.features + const featureId = await tx.feature .findFirst({ where: { feature: quota, type: FeatureKind.Quota }, select: { id: true }, @@ -105,7 +108,7 @@ export class QuotaService { } // we will deactivate all exists quota for this user - await tx.userFeatures.updateMany({ + await tx.userFeature.updateMany({ where: { id: undefined, userId, @@ -118,7 +121,7 @@ export class QuotaService { }, }); - await tx.userFeatures.create({ + await tx.userFeature.create({ data: { userId, featureId, @@ -133,7 +136,7 @@ export class QuotaService { async hasQuota(userId: string, quota: QuotaType, tx?: PrismaTransaction) { const executor = tx ?? this.prisma; - return executor.userFeatures + return executor.userFeature .count({ where: { userId, diff --git a/packages/backend/server/src/data/migrations/1698652531198-user-features-init.ts b/packages/backend/server/src/data/migrations/1698652531198-user-features-init.ts index 1e3b1de98e..d15a00864e 100644 --- a/packages/backend/server/src/data/migrations/1698652531198-user-features-init.ts +++ b/packages/backend/server/src/data/migrations/1698652531198-user-features-init.ts @@ -2,7 +2,7 @@ import { PrismaClient } from '@prisma/client'; import { Features } from '../../core/features'; import { Quotas } from '../../core/quota/schema'; -import { migrateNewFeatureTable, upsertFeature } from './utils/user-features'; +import { upsertFeature } from './utils/user-features'; export class UserFeaturesInit1698652531198 { // do the migration @@ -11,7 +11,6 @@ export class UserFeaturesInit1698652531198 { for (const feature of Features) { await upsertFeature(db, feature); } - await migrateNewFeatureTable(db); for (const quota of Quotas) { await upsertFeature(db, quota); diff --git a/packages/backend/server/src/data/migrations/1699005339766-page-permission.ts b/packages/backend/server/src/data/migrations/1699005339766-page-permission.ts deleted file mode 100644 index ca3238b335..0000000000 --- a/packages/backend/server/src/data/migrations/1699005339766-page-permission.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { PrismaClient } from '@prisma/client'; -export class PagePermission1699005339766 { - // do the migration - static async up(db: PrismaClient) { - let turn = 0; - let lastTurnCount = 50; - const done = new Set(); - - while (lastTurnCount === 50) { - const workspaces = await db.workspace.findMany({ - skip: turn * 50, - take: 50, - orderBy: { - createdAt: 'asc', - }, - }); - lastTurnCount = workspaces.length; - - for (const workspace of workspaces) { - if (done.has(workspace.id)) { - continue; - } - - const oldPermissions = - await db.deprecatedUserWorkspacePermission.findMany({ - where: { - workspaceId: workspace.id, - }, - }); - - for (const oldPermission of oldPermissions) { - // mark subpage public - if (oldPermission.subPageId) { - const existed = await db.workspacePage.findUnique({ - where: { - workspaceId_pageId: { - workspaceId: oldPermission.workspaceId, - pageId: oldPermission.subPageId, - }, - }, - }); - if (!existed) { - await db.workspacePage.create({ - select: null, - data: { - workspaceId: oldPermission.workspaceId, - pageId: oldPermission.subPageId, - public: true, - }, - }); - } - } else if (oldPermission.userId) { - // workspace user permission - const existed = await db.workspaceUserPermission.findUnique({ - where: { - id: oldPermission.id, - }, - }); - - if (!existed) { - await db.workspaceUserPermission - .create({ - select: null, - data: { - // this id is used at invite email, should keep - id: oldPermission.id, - workspaceId: oldPermission.workspaceId, - userId: oldPermission.userId, - type: oldPermission.type, - accepted: oldPermission.accepted, - }, - }) - .catch(() => { - // duplicated - }); - } - } else { - // ignore wrong data - } - } - - done.add(workspace.id); - } - - turn++; - } - } - - // revert the migration - static async down(db: PrismaClient) { - await db.workspaceUserPermission.deleteMany({}); - await db.workspacePageUserPermission.deleteMany({}); - } -} diff --git a/packages/backend/server/src/data/migrations/1702620653283-old-user-feature.ts b/packages/backend/server/src/data/migrations/1702620653283-old-user-feature.ts index 049c8bf994..8fe978336d 100644 --- a/packages/backend/server/src/data/migrations/1702620653283-old-user-feature.ts +++ b/packages/backend/server/src/data/migrations/1702620653283-old-user-feature.ts @@ -5,7 +5,7 @@ export class OldUserFeature1702620653283 { // do the migration static async up(db: PrismaClient) { await db.$transaction(async tx => { - const latestFreePlan = await tx.features.findFirstOrThrow({ + const latestFreePlan = await tx.feature.findFirstOrThrow({ where: { feature: QuotaType.FreePlanV1 }, orderBy: { version: 'desc' }, select: { id: true }, @@ -17,7 +17,7 @@ export class OldUserFeature1702620653283 { select: { id: true }, }); - await tx.userFeatures.createMany({ + await tx.userFeature.createMany({ data: userIds.map(({ id: userId }) => ({ userId, featureId: latestFreePlan.id, @@ -31,6 +31,6 @@ export class OldUserFeature1702620653283 { // revert the migration // WARN: this will drop all user features static async down(db: PrismaClient) { - await db.userFeatures.deleteMany({}); + await db.userFeature.deleteMany({}); } } diff --git a/packages/backend/server/src/data/migrations/1703828796699-workspace-blobs.ts b/packages/backend/server/src/data/migrations/1703828796699-workspace-blobs.ts deleted file mode 100644 index 40cd5fdd08..0000000000 --- a/packages/backend/server/src/data/migrations/1703828796699-workspace-blobs.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { ModuleRef } from '@nestjs/core'; -import { PrismaClient } from '@prisma/client'; - -import { WorkspaceBlobStorage } from '../../core/storage'; - -export class WorkspaceBlobs1703828796699 { - // do the migration - static async up(db: PrismaClient, injector: ModuleRef) { - const blobStorage = injector.get(WorkspaceBlobStorage, { strict: false }); - let hasMore = true; - let turn = 0; - const eachTurnCount = 50; - - while (hasMore) { - const blobs = await db.blob.findMany({ - skip: turn * eachTurnCount, - take: eachTurnCount, - orderBy: { - createdAt: 'asc', - }, - }); - - hasMore = blobs.length === eachTurnCount; - turn += 1; - - await Promise.all( - blobs.map(async ({ workspaceId, hash, blob }) => - blobStorage.put(workspaceId, hash, blob) - ) - ); - } - } - - // revert the migration - static async down(_db: PrismaClient) { - // old data kept, no need to downgrade the migration - } -} diff --git a/packages/backend/server/src/data/migrations/1710319359062-oauth.ts b/packages/backend/server/src/data/migrations/1710319359062-oauth.ts deleted file mode 100644 index 457cdc1f99..0000000000 --- a/packages/backend/server/src/data/migrations/1710319359062-oauth.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { PrismaClient } from '@prisma/client'; - -import { loop } from './utils/loop'; - -export class Oauth1710319359062 { - // do the migration - static async up(db: PrismaClient) { - await loop(async (skip, take) => { - const oldRecords = await db.deprecatedNextAuthAccount.findMany({ - skip, - take, - orderBy: { - providerAccountId: 'asc', - }, - }); - - await db.connectedAccount.createMany({ - data: oldRecords.map(record => ({ - userId: record.userId, - provider: record.provider, - scope: record.scope, - providerAccountId: record.providerAccountId, - accessToken: record.access_token, - refreshToken: record.refresh_token, - expiresAt: record.expires_at - ? new Date(record.expires_at * 1000) - : null, - })), - }); - - return oldRecords.length; - }, 10); - } - - // revert the migration - static async down(db: PrismaClient) { - await db.connectedAccount.deleteMany({}); - } -} diff --git a/packages/backend/server/src/data/migrations/utils/user-features.ts b/packages/backend/server/src/data/migrations/utils/user-features.ts index fdc7c9130d..0f30cb6118 100644 --- a/packages/backend/server/src/data/migrations/utils/user-features.ts +++ b/packages/backend/server/src/data/migrations/utils/user-features.ts @@ -1,11 +1,6 @@ import { Prisma, PrismaClient } from '@prisma/client'; -import { - CommonFeature, - FeatureKind, - Features, - FeatureType, -} from '../../../core/features'; +import { CommonFeature, Features, FeatureType } from '../../../core/features'; // upgrade features from lower version to higher version export async function upsertFeature( @@ -13,7 +8,7 @@ export async function upsertFeature( feature: CommonFeature ): Promise { const hasEqualOrGreaterVersion = - (await db.features.count({ + (await db.feature.count({ where: { feature: feature.feature, version: { @@ -23,7 +18,7 @@ export async function upsertFeature( })) > 0; // will not update exists version if (!hasEqualOrGreaterVersion) { - await db.features.create({ + await db.feature.create({ data: { feature: feature.feature, type: feature.type, @@ -43,66 +38,3 @@ export async function upsertLatestFeatureVersion( const latestFeature = feature[0]; await upsertFeature(db, latestFeature); } - -export async function migrateNewFeatureTable(prisma: PrismaClient) { - const waitingList = await prisma.newFeaturesWaitingList.findMany(); - const latestEarlyAccessFeatureId = await prisma.features - .findFirst({ - where: { feature: FeatureType.EarlyAccess, type: FeatureKind.Feature }, - select: { id: true }, - orderBy: { version: 'desc' }, - }) - .then(r => r?.id); - if (!latestEarlyAccessFeatureId) { - throw new Error('Feature EarlyAccess not found'); - } - for (const oldUser of waitingList) { - const user = await prisma.user.findFirst({ - where: { - email: oldUser.email, - }, - }); - if (user) { - const hasEarlyAccess = await prisma.userFeatures.count({ - where: { - userId: user.id, - feature: { - feature: FeatureType.EarlyAccess, - }, - activated: true, - }, - }); - if (hasEarlyAccess === 0) { - await prisma.$transaction(async tx => { - const latestFlag = await tx.userFeatures.findFirst({ - where: { - userId: user.id, - feature: { - feature: FeatureType.EarlyAccess, - type: FeatureKind.Feature, - }, - activated: true, - }, - orderBy: { - createdAt: 'desc', - }, - }); - if (latestFlag) { - return latestFlag.id; - } else { - return tx.userFeatures - .create({ - data: { - reason: 'Early access user', - activated: true, - userId: user.id, - featureId: latestEarlyAccessFeatureId, - }, - }) - .then(r => r.id); - } - }); - } - } - } -} diff --git a/packages/backend/server/src/data/migrations/utils/user-quotas.ts b/packages/backend/server/src/data/migrations/utils/user-quotas.ts index 3c7d9d0201..771ab46f0e 100644 --- a/packages/backend/server/src/data/migrations/utils/user-quotas.ts +++ b/packages/backend/server/src/data/migrations/utils/user-quotas.ts @@ -15,7 +15,7 @@ export async function upgradeQuotaVersion( // migrate all users that using old quota to new quota await db.$transaction( async tx => { - const latestQuotaVersion = await tx.features.findFirstOrThrow({ + const latestQuotaVersion = await tx.feature.findFirstOrThrow({ where: { feature: quota.feature }, orderBy: { version: 'desc' }, select: { id: true }, @@ -39,7 +39,7 @@ export async function upgradeQuotaVersion( }); // deactivate all old quota for the user - await tx.userFeatures.updateMany({ + await tx.userFeature.updateMany({ where: { id: undefined, userId: { @@ -55,7 +55,7 @@ export async function upgradeQuotaVersion( }, }); - await tx.userFeatures.createMany({ + await tx.userFeature.createMany({ data: userIds.map(({ id: userId }) => ({ userId, featureId: latestQuotaVersion.id, diff --git a/packages/backend/server/src/plugins/payment/service.ts b/packages/backend/server/src/plugins/payment/service.ts index ba4bcfb9f6..3c1d014a9f 100644 --- a/packages/backend/server/src/plugins/payment/service.ts +++ b/packages/backend/server/src/plugins/payment/service.ts @@ -84,17 +84,17 @@ export class SubscriptionService { private readonly db: PrismaClient, private readonly scheduleManager: ScheduleManager, private readonly event: EventEmitter, - private readonly features: FeatureManagementService + private readonly feature: FeatureManagementService ) {} async listPrices(user?: CurrentUser) { let canHaveEarlyAccessDiscount = false; let canHaveAIEarlyAccessDiscount = false; if (user) { - canHaveEarlyAccessDiscount = await this.features.isEarlyAccessUser( + canHaveEarlyAccessDiscount = await this.feature.isEarlyAccessUser( user.id ); - canHaveAIEarlyAccessDiscount = await this.features.isEarlyAccessUser( + canHaveAIEarlyAccessDiscount = await this.feature.isEarlyAccessUser( user.id, EarlyAccessType.AI ); @@ -181,7 +181,7 @@ export class SubscriptionService { if ( this.config.deploy && this.config.affine.canary && - !this.features.isStaff(user.email) + !this.feature.isStaff(user.email) ) { throw new ActionForbidden(); } @@ -847,7 +847,7 @@ export class SubscriptionService { plan: SubscriptionPlan, recurring: SubscriptionRecurring ): Promise<{ price: string; coupon?: string }> { - const isEaUser = await this.features.isEarlyAccessUser(customer.userId); + const isEaUser = await this.feature.isEarlyAccessUser(customer.userId); const oldSubscriptions = await this.stripe.subscriptions.list({ customer: customer.stripeCustomerId, status: 'all', @@ -876,7 +876,7 @@ export class SubscriptionService { : undefined, }; } else { - const isAIEaUser = await this.features.isEarlyAccessUser( + const isAIEaUser = await this.feature.isEarlyAccessUser( customer.userId, EarlyAccessType.AI ); diff --git a/tests/kit/utils/cloud.ts b/tests/kit/utils/cloud.ts index 24fa82bae5..6ba29b042a 100644 --- a/tests/kit/utils/cloud.ts +++ b/tests/kit/utils/cloud.ts @@ -111,7 +111,7 @@ export async function createRandomUser(): Promise<{ password: '123456', }; const result = await runPrisma(async client => { - const featureId = await client.features + const featureId = await client.feature .findFirst({ where: { feature: 'free_plan_v1' }, select: { id: true },