mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-25 06:18:45 +08:00
chore(server): standardize server db names and columns (#7674)
This commit is contained in:
@@ -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,
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ export class FeatureService {
|
||||
constructor(private readonly prisma: PrismaClient) {}
|
||||
|
||||
async getFeature<F extends FeatureType>(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<WorkspaceType[]> {
|
||||
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,
|
||||
|
||||
@@ -13,7 +13,7 @@ export class QuotaConfig {
|
||||
return cachedQuota;
|
||||
}
|
||||
|
||||
const quota = await tx.features.findFirst({
|
||||
const quota = await tx.feature.findFirst({
|
||||
where: {
|
||||
id: featureId,
|
||||
},
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<string>();
|
||||
|
||||
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({});
|
||||
}
|
||||
}
|
||||
@@ -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({});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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({});
|
||||
}
|
||||
}
|
||||
@@ -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<void> {
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user