mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
refactor(server): import prisma from @prisma/client (#5863)
This commit is contained in:
@@ -8,13 +8,11 @@ import {
|
|||||||
UseGuards,
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { Reflector } from '@nestjs/core';
|
import { Reflector } from '@nestjs/core';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
import type { NextAuthOptions } from 'next-auth';
|
import type { NextAuthOptions } from 'next-auth';
|
||||||
import { AuthHandler } from 'next-auth/core';
|
import { AuthHandler } from 'next-auth/core';
|
||||||
|
|
||||||
import {
|
import { getRequestResponseFromContext } from '../../fundamentals';
|
||||||
getRequestResponseFromContext,
|
|
||||||
PrismaService,
|
|
||||||
} from '../../fundamentals';
|
|
||||||
import { NextAuthOptionsProvide } from './next-auth-options';
|
import { NextAuthOptionsProvide } from './next-auth-options';
|
||||||
import { AuthService } from './service';
|
import { AuthService } from './service';
|
||||||
|
|
||||||
@@ -57,7 +55,7 @@ class AuthGuard implements CanActivate {
|
|||||||
@Inject(NextAuthOptionsProvide)
|
@Inject(NextAuthOptionsProvide)
|
||||||
private readonly nextAuthOptions: NextAuthOptions,
|
private readonly nextAuthOptions: NextAuthOptions,
|
||||||
private readonly auth: AuthService,
|
private readonly auth: AuthService,
|
||||||
private readonly prisma: PrismaService,
|
private readonly prisma: PrismaClient,
|
||||||
private readonly reflector: Reflector
|
private readonly reflector: Reflector
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { PrismaAdapter } from '@auth/prisma-adapter';
|
import { PrismaAdapter } from '@auth/prisma-adapter';
|
||||||
import { FactoryProvider, Logger } from '@nestjs/common';
|
import { FactoryProvider, Logger } from '@nestjs/common';
|
||||||
import { verify } from '@node-rs/argon2';
|
import { verify } from '@node-rs/argon2';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
import { assign, omit } from 'lodash-es';
|
import { assign, omit } from 'lodash-es';
|
||||||
import { NextAuthOptions } from 'next-auth';
|
import { NextAuthOptions } from 'next-auth';
|
||||||
import Credentials from 'next-auth/providers/credentials';
|
import Credentials from 'next-auth/providers/credentials';
|
||||||
@@ -8,12 +9,7 @@ import Email from 'next-auth/providers/email';
|
|||||||
import Github from 'next-auth/providers/github';
|
import Github from 'next-auth/providers/github';
|
||||||
import Google from 'next-auth/providers/google';
|
import Google from 'next-auth/providers/google';
|
||||||
|
|
||||||
import {
|
import { Config, MailService, SessionService } from '../../fundamentals';
|
||||||
Config,
|
|
||||||
MailService,
|
|
||||||
PrismaService,
|
|
||||||
SessionService,
|
|
||||||
} from '../../fundamentals';
|
|
||||||
import { FeatureType } from '../features';
|
import { FeatureType } from '../features';
|
||||||
import { Quota_FreePlanV1_1 } from '../quota';
|
import { Quota_FreePlanV1_1 } from '../quota';
|
||||||
import {
|
import {
|
||||||
@@ -31,7 +27,7 @@ export const NextAuthOptionsProvider: FactoryProvider<NextAuthOptions> = {
|
|||||||
provide: NextAuthOptionsProvide,
|
provide: NextAuthOptionsProvide,
|
||||||
useFactory(
|
useFactory(
|
||||||
config: Config,
|
config: Config,
|
||||||
prisma: PrismaService,
|
prisma: PrismaClient,
|
||||||
mailer: MailService,
|
mailer: MailService,
|
||||||
session: SessionService
|
session: SessionService
|
||||||
) {
|
) {
|
||||||
@@ -284,5 +280,5 @@ export const NextAuthOptionsProvider: FactoryProvider<NextAuthOptions> = {
|
|||||||
};
|
};
|
||||||
return nextAuthOptions;
|
return nextAuthOptions;
|
||||||
},
|
},
|
||||||
inject: [Config, PrismaService, MailService, SessionService],
|
inject: [Config, PrismaClient, MailService, SessionService],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
UseGuards,
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { hash, verify } from '@node-rs/argon2';
|
import { hash, verify } from '@node-rs/argon2';
|
||||||
import type { User } from '@prisma/client';
|
import { PrismaClient, type User } from '@prisma/client';
|
||||||
import type { NextFunction, Request, Response } from 'express';
|
import type { NextFunction, Request, Response } from 'express';
|
||||||
import { pick } from 'lodash-es';
|
import { pick } from 'lodash-es';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
@@ -26,7 +26,6 @@ import {
|
|||||||
AuthThrottlerGuard,
|
AuthThrottlerGuard,
|
||||||
Config,
|
Config,
|
||||||
metrics,
|
metrics,
|
||||||
PrismaService,
|
|
||||||
SessionService,
|
SessionService,
|
||||||
Throttle,
|
Throttle,
|
||||||
} from '../../fundamentals';
|
} from '../../fundamentals';
|
||||||
@@ -45,7 +44,7 @@ export class NextAuthController {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly config: Config,
|
readonly config: Config,
|
||||||
readonly prisma: PrismaService,
|
readonly prisma: PrismaClient,
|
||||||
private readonly authService: AuthService,
|
private readonly authService: AuthService,
|
||||||
@Inject(NextAuthOptionsProvide)
|
@Inject(NextAuthOptionsProvide)
|
||||||
private readonly nextAuthOptions: NextAuthOptions,
|
private readonly nextAuthOptions: NextAuthOptions,
|
||||||
|
|||||||
@@ -8,13 +8,12 @@ import {
|
|||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { hash, verify } from '@node-rs/argon2';
|
import { hash, verify } from '@node-rs/argon2';
|
||||||
import { Algorithm, sign, verify as jwtVerify } from '@node-rs/jsonwebtoken';
|
import { Algorithm, sign, verify as jwtVerify } from '@node-rs/jsonwebtoken';
|
||||||
import type { User } from '@prisma/client';
|
import { PrismaClient, type User } from '@prisma/client';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Config,
|
Config,
|
||||||
MailService,
|
MailService,
|
||||||
PrismaService,
|
|
||||||
verifyChallengeResponse,
|
verifyChallengeResponse,
|
||||||
} from '../../fundamentals';
|
} from '../../fundamentals';
|
||||||
import { Quota_FreePlanV1_1 } from '../quota';
|
import { Quota_FreePlanV1_1 } from '../quota';
|
||||||
@@ -32,7 +31,7 @@ export const getUtcTimestamp = () => Math.floor(Date.now() / 1000);
|
|||||||
export class AuthService {
|
export class AuthService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly config: Config,
|
private readonly config: Config,
|
||||||
private readonly prisma: PrismaService,
|
private readonly prisma: PrismaClient,
|
||||||
private readonly mailer: MailService
|
private readonly mailer: MailService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,15 @@ import { randomUUID } from 'node:crypto';
|
|||||||
|
|
||||||
import { BadRequestException } from '@nestjs/common';
|
import { BadRequestException } from '@nestjs/common';
|
||||||
import { Algorithm, sign, verify as jwtVerify } from '@node-rs/jsonwebtoken';
|
import { Algorithm, sign, verify as jwtVerify } from '@node-rs/jsonwebtoken';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
import { JWT } from 'next-auth/jwt';
|
import { JWT } from 'next-auth/jwt';
|
||||||
|
|
||||||
import { Config, PrismaService } from '../../../fundamentals';
|
import { Config } from '../../../fundamentals';
|
||||||
import { getUtcTimestamp, UserClaim } from '../service';
|
import { getUtcTimestamp, UserClaim } from '../service';
|
||||||
|
|
||||||
export const jwtEncode = async (
|
export const jwtEncode = async (
|
||||||
config: Config,
|
config: Config,
|
||||||
prisma: PrismaService,
|
prisma: PrismaClient,
|
||||||
token: JWT | undefined,
|
token: JWT | undefined,
|
||||||
maxAge: number | undefined
|
maxAge: number | undefined
|
||||||
) => {
|
) => {
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ import { isDeepStrictEqual } from 'node:util';
|
|||||||
|
|
||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
import { Cron, CronExpression } from '@nestjs/schedule';
|
import { Cron, CronExpression } from '@nestjs/schedule';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Config,
|
Config,
|
||||||
type EventPayload,
|
type EventPayload,
|
||||||
metrics,
|
metrics,
|
||||||
OnEvent,
|
OnEvent,
|
||||||
PrismaService,
|
|
||||||
} from '../../fundamentals';
|
} from '../../fundamentals';
|
||||||
import { QuotaService } from '../quota';
|
import { QuotaService } from '../quota';
|
||||||
import { Permission } from '../workspaces/types';
|
import { Permission } from '../workspaces/types';
|
||||||
@@ -19,7 +19,7 @@ export class DocHistoryManager {
|
|||||||
private readonly logger = new Logger(DocHistoryManager.name);
|
private readonly logger = new Logger(DocHistoryManager.name);
|
||||||
constructor(
|
constructor(
|
||||||
private readonly config: Config,
|
private readonly config: Config,
|
||||||
private readonly db: PrismaService,
|
private readonly db: PrismaClient,
|
||||||
private readonly quota: QuotaService
|
private readonly quota: QuotaService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
OnModuleInit,
|
OnModuleInit,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { Cron, CronExpression } from '@nestjs/schedule';
|
import { Cron, CronExpression } from '@nestjs/schedule';
|
||||||
import { Snapshot, Update } from '@prisma/client';
|
import { PrismaClient, Snapshot, Update } from '@prisma/client';
|
||||||
import { chunk } from 'lodash-es';
|
import { chunk } from 'lodash-es';
|
||||||
import { defer, retry } from 'rxjs';
|
import { defer, retry } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
@@ -25,7 +25,6 @@ import {
|
|||||||
mergeUpdatesInApplyWay as jwstMergeUpdates,
|
mergeUpdatesInApplyWay as jwstMergeUpdates,
|
||||||
metrics,
|
metrics,
|
||||||
OnEvent,
|
OnEvent,
|
||||||
PrismaService,
|
|
||||||
} from '../../fundamentals';
|
} from '../../fundamentals';
|
||||||
|
|
||||||
function compare(yBinary: Buffer, jwstBinary: Buffer, strict = false): boolean {
|
function compare(yBinary: Buffer, jwstBinary: Buffer, strict = false): boolean {
|
||||||
@@ -72,7 +71,7 @@ export class DocManager implements OnModuleInit, OnModuleDestroy {
|
|||||||
private busy = false;
|
private busy = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly db: PrismaService,
|
private readonly db: PrismaClient,
|
||||||
private readonly config: Config,
|
private readonly config: Config,
|
||||||
private readonly cache: Cache,
|
private readonly cache: Cache,
|
||||||
private readonly event: EventEmitter
|
private readonly event: EventEmitter
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
import { Config, PrismaService } from '../../fundamentals';
|
import { Config } from '../../fundamentals';
|
||||||
import { FeatureService } from './service';
|
import { FeatureService } from './service';
|
||||||
import { FeatureType } from './types';
|
import { FeatureType } from './types';
|
||||||
|
|
||||||
@@ -12,7 +13,7 @@ export class FeatureManagementService {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly feature: FeatureService,
|
private readonly feature: FeatureService,
|
||||||
private readonly prisma: PrismaService,
|
private readonly prisma: PrismaClient,
|
||||||
private readonly config: Config
|
private readonly config: Config
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
import { PrismaService } from '../../fundamentals';
|
|
||||||
import { UserType } from '../users/types';
|
import { UserType } from '../users/types';
|
||||||
import { WorkspaceType } from '../workspaces/types';
|
import { WorkspaceType } from '../workspaces/types';
|
||||||
import { FeatureConfigType, getFeature } from './feature';
|
import { FeatureConfigType, getFeature } from './feature';
|
||||||
@@ -8,7 +8,7 @@ import { FeatureKind, FeatureType } from './types';
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FeatureService {
|
export class FeatureService {
|
||||||
constructor(private readonly prisma: PrismaService) {}
|
constructor(private readonly prisma: PrismaClient) {}
|
||||||
|
|
||||||
async getFeaturesVersion() {
|
async getFeaturesVersion() {
|
||||||
const features = await this.prisma.features.findMany({
|
const features = await this.prisma.features.findMany({
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { PrismaService } from '../../fundamentals';
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
import { formatDate, formatSize, Quota, QuotaSchema } from './types';
|
import { formatDate, formatSize, Quota, QuotaSchema } from './types';
|
||||||
|
|
||||||
const QuotaCache = new Map<number, QuotaConfig>();
|
const QuotaCache = new Map<number, QuotaConfig>();
|
||||||
@@ -6,7 +7,7 @@ const QuotaCache = new Map<number, QuotaConfig>();
|
|||||||
export class QuotaConfig {
|
export class QuotaConfig {
|
||||||
readonly config: Quota;
|
readonly config: Quota;
|
||||||
|
|
||||||
static async get(prisma: PrismaService, featureId: number) {
|
static async get(prisma: PrismaClient, featureId: number) {
|
||||||
const cachedQuota = QuotaCache.get(featureId);
|
const cachedQuota = QuotaCache.get(featureId);
|
||||||
|
|
||||||
if (cachedQuota) {
|
if (cachedQuota) {
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
import { type EventPayload, OnEvent, PrismaService } from '../../fundamentals';
|
import { type EventPayload, OnEvent } from '../../fundamentals';
|
||||||
import { FeatureKind } from '../features';
|
import { FeatureKind } from '../features';
|
||||||
import { QuotaConfig } from './quota';
|
import { QuotaConfig } from './quota';
|
||||||
import { QuotaType } from './types';
|
import { QuotaType } from './types';
|
||||||
|
|
||||||
type Transaction = Parameters<Parameters<PrismaService['$transaction']>[0]>[0];
|
type Transaction = Parameters<Parameters<PrismaClient['$transaction']>[0]>[0];
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QuotaService {
|
export class QuotaService {
|
||||||
constructor(private readonly prisma: PrismaService) {}
|
constructor(private readonly prisma: PrismaClient) {}
|
||||||
|
|
||||||
// get activated user quota
|
// get activated user quota
|
||||||
async getUserQuota(userId: string) {
|
async getUserQuota(userId: string) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
ResolveField,
|
ResolveField,
|
||||||
Resolver,
|
Resolver,
|
||||||
} from '@nestjs/graphql';
|
} from '@nestjs/graphql';
|
||||||
import type { User } from '@prisma/client';
|
import { PrismaClient, type User } from '@prisma/client';
|
||||||
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
|
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -15,7 +15,6 @@ import {
|
|||||||
EventEmitter,
|
EventEmitter,
|
||||||
type FileUpload,
|
type FileUpload,
|
||||||
PaymentRequiredException,
|
PaymentRequiredException,
|
||||||
PrismaService,
|
|
||||||
Throttle,
|
Throttle,
|
||||||
} from '../../fundamentals';
|
} from '../../fundamentals';
|
||||||
import { Auth, CurrentUser, Public, Publicable } from '../auth/guard';
|
import { Auth, CurrentUser, Public, Publicable } from '../auth/guard';
|
||||||
@@ -40,7 +39,7 @@ import { UsersService } from './users';
|
|||||||
@Resolver(() => UserType)
|
@Resolver(() => UserType)
|
||||||
export class UserResolver {
|
export class UserResolver {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly prisma: PrismaService,
|
private readonly prisma: PrismaClient,
|
||||||
private readonly storage: AvatarStorage,
|
private readonly storage: AvatarStorage,
|
||||||
private readonly users: UsersService,
|
private readonly users: UsersService,
|
||||||
private readonly feature: FeatureManagementService,
|
private readonly feature: FeatureManagementService,
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
import { PrismaService } from '../../fundamentals';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UsersService {
|
export class UsersService {
|
||||||
constructor(private readonly prisma: PrismaService) {}
|
constructor(private readonly prisma: PrismaClient) {}
|
||||||
|
|
||||||
async findUserByEmail(email: string) {
|
async findUserByEmail(email: string) {
|
||||||
return this.prisma.user.findFirst({
|
return this.prisma.user.findFirst({
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ import {
|
|||||||
Param,
|
Param,
|
||||||
Res,
|
Res,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
import type { Response } from 'express';
|
import type { Response } from 'express';
|
||||||
|
|
||||||
import { CallTimer, PrismaService } from '../../fundamentals';
|
import { CallTimer } from '../../fundamentals';
|
||||||
import { Auth, CurrentUser, Publicable } from '../auth';
|
import { Auth, CurrentUser, Publicable } from '../auth';
|
||||||
import { DocHistoryManager, DocManager } from '../doc';
|
import { DocHistoryManager, DocManager } from '../doc';
|
||||||
import { WorkspaceBlobStorage } from '../storage';
|
import { WorkspaceBlobStorage } from '../storage';
|
||||||
@@ -26,7 +27,7 @@ export class WorkspacesController {
|
|||||||
private readonly permission: PermissionService,
|
private readonly permission: PermissionService,
|
||||||
private readonly docManager: DocManager,
|
private readonly docManager: DocManager,
|
||||||
private readonly historyManager: DocHistoryManager,
|
private readonly historyManager: DocHistoryManager,
|
||||||
private readonly prisma: PrismaService
|
private readonly prisma: PrismaClient
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
// get workspace blob
|
// get workspace blob
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { ForbiddenException, Injectable } from '@nestjs/common';
|
import { ForbiddenException, Injectable } from '@nestjs/common';
|
||||||
import { Prisma } from '@prisma/client';
|
import { type Prisma, PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
import { PrismaService } from '../../fundamentals';
|
|
||||||
import { Permission } from './types';
|
import { Permission } from './types';
|
||||||
|
|
||||||
export enum PublicPageMode {
|
export enum PublicPageMode {
|
||||||
@@ -11,7 +10,7 @@ export enum PublicPageMode {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PermissionService {
|
export class PermissionService {
|
||||||
constructor(private readonly prisma: PrismaService) {}
|
constructor(private readonly prisma: PrismaClient) {}
|
||||||
|
|
||||||
/// Start regin: workspace permission
|
/// Start regin: workspace permission
|
||||||
async get(ws: string, user: string) {
|
async get(ws: string, user: string) {
|
||||||
|
|||||||
@@ -9,9 +9,12 @@ import {
|
|||||||
ResolveField,
|
ResolveField,
|
||||||
Resolver,
|
Resolver,
|
||||||
} from '@nestjs/graphql';
|
} from '@nestjs/graphql';
|
||||||
import type { WorkspacePage as PrismaWorkspacePage } from '@prisma/client';
|
import {
|
||||||
|
PrismaClient,
|
||||||
|
type WorkspacePage as PrismaWorkspacePage,
|
||||||
|
} from '@prisma/client';
|
||||||
|
|
||||||
import { CloudThrottlerGuard, PrismaService } from '../../../fundamentals';
|
import { CloudThrottlerGuard } from '../../../fundamentals';
|
||||||
import { Auth, CurrentUser } from '../../auth';
|
import { Auth, CurrentUser } from '../../auth';
|
||||||
import { UserType } from '../../users';
|
import { UserType } from '../../users';
|
||||||
import { DocID } from '../../utils/doc';
|
import { DocID } from '../../utils/doc';
|
||||||
@@ -43,7 +46,7 @@ class WorkspacePage implements Partial<PrismaWorkspacePage> {
|
|||||||
@Resolver(() => WorkspaceType)
|
@Resolver(() => WorkspaceType)
|
||||||
export class PagePermissionResolver {
|
export class PagePermissionResolver {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly prisma: PrismaService,
|
private readonly prisma: PrismaClient,
|
||||||
private readonly permission: PermissionService
|
private readonly permission: PermissionService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
ResolveField,
|
ResolveField,
|
||||||
Resolver,
|
Resolver,
|
||||||
} from '@nestjs/graphql';
|
} from '@nestjs/graphql';
|
||||||
import type { User } from '@prisma/client';
|
import { PrismaClient, type User } from '@prisma/client';
|
||||||
import { getStreamAsBuffer } from 'get-stream';
|
import { getStreamAsBuffer } from 'get-stream';
|
||||||
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
|
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
|
||||||
import { applyUpdate, Doc } from 'yjs';
|
import { applyUpdate, Doc } from 'yjs';
|
||||||
@@ -25,7 +25,6 @@ import {
|
|||||||
EventEmitter,
|
EventEmitter,
|
||||||
type FileUpload,
|
type FileUpload,
|
||||||
MailService,
|
MailService,
|
||||||
PrismaService,
|
|
||||||
Throttle,
|
Throttle,
|
||||||
} from '../../../fundamentals';
|
} from '../../../fundamentals';
|
||||||
import { Auth, CurrentUser, Public } from '../../auth';
|
import { Auth, CurrentUser, Public } from '../../auth';
|
||||||
@@ -57,7 +56,7 @@ export class WorkspaceResolver {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly auth: AuthService,
|
private readonly auth: AuthService,
|
||||||
private readonly mailer: MailService,
|
private readonly mailer: MailService,
|
||||||
private readonly prisma: PrismaService,
|
private readonly prisma: PrismaClient,
|
||||||
private readonly permissions: PermissionService,
|
private readonly permissions: PermissionService,
|
||||||
private readonly quota: QuotaManagementService,
|
private readonly quota: QuotaManagementService,
|
||||||
private readonly users: UsersService,
|
private readonly users: UsersService,
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ export {
|
|||||||
GlobalExceptionFilter,
|
GlobalExceptionFilter,
|
||||||
OptionalModule,
|
OptionalModule,
|
||||||
} from './nestjs';
|
} from './nestjs';
|
||||||
export { PrismaService } from './prisma';
|
|
||||||
export { SessionService } from './session';
|
export { SessionService } from './session';
|
||||||
export * from './storage';
|
export * from './storage';
|
||||||
export { type StorageProvider, StorageProviderFactory } from './storage';
|
export { type StorageProvider, StorageProviderFactory } from './storage';
|
||||||
|
|||||||
@@ -3,16 +3,16 @@ import { PrismaClient } from '@prisma/client';
|
|||||||
|
|
||||||
import { PrismaService } from './service';
|
import { PrismaService } from './service';
|
||||||
|
|
||||||
// both `PrismaService` and `PrismaClient` can be injected
|
// only `PrismaClient` can be injected
|
||||||
const clientProvider: Provider = {
|
const clientProvider: Provider = {
|
||||||
provide: PrismaClient,
|
provide: PrismaClient,
|
||||||
useExisting: PrismaService,
|
useClass: PrismaService,
|
||||||
};
|
};
|
||||||
|
|
||||||
@Global()
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
providers: [PrismaService, clientProvider],
|
providers: [clientProvider],
|
||||||
exports: [PrismaService, clientProvider],
|
exports: [clientProvider],
|
||||||
})
|
})
|
||||||
export class PrismaModule {}
|
export class PrismaModule {}
|
||||||
export { PrismaService } from './service';
|
export { PrismaService } from './service';
|
||||||
|
|||||||
@@ -18,11 +18,12 @@ import {
|
|||||||
Resolver,
|
Resolver,
|
||||||
} from '@nestjs/graphql';
|
} from '@nestjs/graphql';
|
||||||
import type { User, UserInvoice, UserSubscription } from '@prisma/client';
|
import type { User, UserInvoice, UserSubscription } from '@prisma/client';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
import { groupBy } from 'lodash-es';
|
import { groupBy } from 'lodash-es';
|
||||||
|
|
||||||
import { Auth, CurrentUser, Public } from '../../core/auth';
|
import { Auth, CurrentUser, Public } from '../../core/auth';
|
||||||
import { UserType } from '../../core/users';
|
import { UserType } from '../../core/users';
|
||||||
import { Config, PrismaService } from '../../fundamentals';
|
import { Config } from '../../fundamentals';
|
||||||
import { decodeLookupKey, SubscriptionService } from './service';
|
import { decodeLookupKey, SubscriptionService } from './service';
|
||||||
import {
|
import {
|
||||||
InvoiceStatus,
|
InvoiceStatus,
|
||||||
@@ -303,7 +304,7 @@ export class SubscriptionResolver {
|
|||||||
export class UserSubscriptionResolver {
|
export class UserSubscriptionResolver {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly config: Config,
|
private readonly config: Config,
|
||||||
private readonly db: PrismaService
|
private readonly db: PrismaClient
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ResolveField(() => UserSubscriptionType, { nullable: true })
|
@ResolveField(() => UserSubscriptionType, { nullable: true })
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import type {
|
|||||||
UserStripeCustomer,
|
UserStripeCustomer,
|
||||||
UserSubscription,
|
UserSubscription,
|
||||||
} from '@prisma/client';
|
} from '@prisma/client';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
import Stripe from 'stripe';
|
import Stripe from 'stripe';
|
||||||
|
|
||||||
import { FeatureManagementService } from '../../core/features';
|
import { FeatureManagementService } from '../../core/features';
|
||||||
import { EventEmitter, PrismaService } from '../../fundamentals';
|
import { EventEmitter } from '../../fundamentals';
|
||||||
import { ScheduleManager } from './schedule';
|
import { ScheduleManager } from './schedule';
|
||||||
import {
|
import {
|
||||||
InvoiceStatus,
|
InvoiceStatus,
|
||||||
@@ -56,7 +57,7 @@ export class SubscriptionService {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly stripe: Stripe,
|
private readonly stripe: Stripe,
|
||||||
private readonly db: PrismaService,
|
private readonly db: PrismaClient,
|
||||||
private readonly scheduleManager: ScheduleManager,
|
private readonly scheduleManager: ScheduleManager,
|
||||||
private readonly event: EventEmitter,
|
private readonly event: EventEmitter,
|
||||||
private readonly features: FeatureManagementService
|
private readonly features: FeatureManagementService
|
||||||
|
|||||||
@@ -4,14 +4,13 @@ import { randomUUID } from 'node:crypto';
|
|||||||
import { Transformer } from '@napi-rs/image';
|
import { Transformer } from '@napi-rs/image';
|
||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { hashSync } from '@node-rs/argon2';
|
import { hashSync } from '@node-rs/argon2';
|
||||||
import { type User } from '@prisma/client';
|
import { PrismaClient, type User } from '@prisma/client';
|
||||||
import ava, { type TestFn } from 'ava';
|
import ava, { type TestFn } from 'ava';
|
||||||
import type { Express } from 'express';
|
import type { Express } from 'express';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
|
|
||||||
import { AppModule } from '../src/app.module';
|
import { AppModule } from '../src/app.module';
|
||||||
import { FeatureManagementService } from '../src/core/features';
|
import { FeatureManagementService } from '../src/core/features';
|
||||||
import { PrismaService } from '../src/fundamentals/prisma';
|
|
||||||
import { createTestingApp } from './utils';
|
import { createTestingApp } from './utils';
|
||||||
|
|
||||||
const gql = '/graphql';
|
const gql = '/graphql';
|
||||||
@@ -52,7 +51,7 @@ test.beforeEach(async t => {
|
|||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
tapModule(builder) {
|
tapModule(builder) {
|
||||||
builder
|
builder
|
||||||
.overrideProvider(PrismaService)
|
.overrideProvider(PrismaClient)
|
||||||
.useClass(FakePrisma)
|
.useClass(FakePrisma)
|
||||||
.overrideProvider(FeatureManagementService)
|
.overrideProvider(FeatureManagementService)
|
||||||
.useValue({ canEarlyAccess: () => true });
|
.useValue({ canEarlyAccess: () => true });
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
getLatestMailMessage,
|
getLatestMailMessage,
|
||||||
} from '@affine-test/kit/utils/cloud';
|
} from '@affine-test/kit/utils/cloud';
|
||||||
import { TestingModule } from '@nestjs/testing';
|
import { TestingModule } from '@nestjs/testing';
|
||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
import ava, { type TestFn } from 'ava';
|
import ava, { type TestFn } from 'ava';
|
||||||
|
|
||||||
import { AuthService } from '../src/core/auth/service';
|
import { AuthService } from '../src/core/auth/service';
|
||||||
@@ -20,13 +19,6 @@ const test = ava as TestFn<{
|
|||||||
skip: boolean;
|
skip: boolean;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
// cleanup database before each test
|
|
||||||
test.beforeEach(async () => {
|
|
||||||
const client = new PrismaClient();
|
|
||||||
await client.$connect();
|
|
||||||
await client.user.deleteMany({});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(async t => {
|
test.beforeEach(async t => {
|
||||||
t.context.module = await createTestingModule({
|
t.context.module = await createTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
|||||||
@@ -1,126 +1,11 @@
|
|||||||
import { randomUUID } from 'node:crypto';
|
|
||||||
|
|
||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { hashSync } from '@node-rs/argon2';
|
|
||||||
import { type User } from '@prisma/client';
|
|
||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
import ava, { type TestFn } from 'ava';
|
import ava, { type TestFn } from 'ava';
|
||||||
|
import Sinon from 'sinon';
|
||||||
|
|
||||||
import { AppModule } from '../src/app.module';
|
import { AppModule } from '../src/app.module';
|
||||||
import { FeatureKind, FeatureManagementService } from '../src/core/features';
|
import { FeatureManagementService } from '../src/core/features';
|
||||||
import { Quotas } from '../src/core/quota';
|
|
||||||
import { MailService } from '../src/fundamentals/mailer';
|
import { MailService } from '../src/fundamentals/mailer';
|
||||||
import {
|
import { createTestingApp, createWorkspace, inviteUser, signUp } from './utils';
|
||||||
createTestingApp,
|
|
||||||
createWorkspace,
|
|
||||||
getInviteInfo,
|
|
||||||
inviteUser,
|
|
||||||
signUp,
|
|
||||||
} from './utils';
|
|
||||||
|
|
||||||
const FakePrisma = {
|
|
||||||
fakeUser: {
|
|
||||||
id: randomUUID(),
|
|
||||||
name: 'Alex Yang',
|
|
||||||
avatarUrl: '',
|
|
||||||
email: 'alex.yang@example.org',
|
|
||||||
password: hashSync('123456'),
|
|
||||||
emailVerified: new Date(),
|
|
||||||
createdAt: new Date(),
|
|
||||||
} satisfies User,
|
|
||||||
|
|
||||||
get user() {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
||||||
const prisma = this;
|
|
||||||
return {
|
|
||||||
async findFirst() {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
async create({ data }: any) {
|
|
||||||
return {
|
|
||||||
...prisma.fakeUser,
|
|
||||||
...data,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
async findUnique() {
|
|
||||||
return prisma.fakeUser;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
get workspace() {
|
|
||||||
return {
|
|
||||||
id: randomUUID(),
|
|
||||||
async create({ data }: any) {
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
public: data.public ?? false,
|
|
||||||
createdAt: new Date(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
snapshot: {
|
|
||||||
id: randomUUID(),
|
|
||||||
async create() {},
|
|
||||||
async findFirstOrThrow() {
|
|
||||||
return { id: this.id, blob: Buffer.from([0, 0]) };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
get workspaceUserPermission() {
|
|
||||||
return {
|
|
||||||
id: randomUUID(),
|
|
||||||
prisma: this,
|
|
||||||
async count() {
|
|
||||||
return 1;
|
|
||||||
},
|
|
||||||
async create() {
|
|
||||||
return { id: this.id };
|
|
||||||
},
|
|
||||||
async findUniqueOrThrow() {
|
|
||||||
return { id: this.id, workspaceId: this.prisma.workspace.id };
|
|
||||||
},
|
|
||||||
async findFirst() {
|
|
||||||
return { id: this.id };
|
|
||||||
},
|
|
||||||
async findFirstOrThrow() {
|
|
||||||
return { id: this.id, user: this.prisma.fakeUser };
|
|
||||||
},
|
|
||||||
async workspaceUserPermission() {
|
|
||||||
return {
|
|
||||||
id: randomUUID(),
|
|
||||||
createdAt: new Date(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
get features() {
|
|
||||||
return {
|
|
||||||
async findFirst() {
|
|
||||||
return {
|
|
||||||
id: 1,
|
|
||||||
type: FeatureKind.Quota,
|
|
||||||
feature: Quotas[0].feature,
|
|
||||||
configs: Quotas[0].configs,
|
|
||||||
version: Quotas[0].version,
|
|
||||||
createdAt: new Date(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
get userFeatures() {
|
|
||||||
return {
|
|
||||||
async findFirst() {
|
|
||||||
return {
|
|
||||||
createdAt: new Date(),
|
|
||||||
featureId: 1,
|
|
||||||
reason: '',
|
|
||||||
expiredAt: null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const test = ava as TestFn<{
|
const test = ava as TestFn<{
|
||||||
app: INestApplication;
|
app: INestApplication;
|
||||||
mail: MailService;
|
mail: MailService;
|
||||||
@@ -130,15 +15,11 @@ test.beforeEach(async t => {
|
|||||||
const { module, app } = await createTestingApp({
|
const { module, app } = await createTestingApp({
|
||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
tapModule: module => {
|
tapModule: module => {
|
||||||
module
|
module.overrideProvider(FeatureManagementService).useValue({
|
||||||
.overrideProvider(PrismaClient)
|
hasWorkspaceFeature() {
|
||||||
.useValue(FakePrisma)
|
return false;
|
||||||
.overrideProvider(FeatureManagementService)
|
},
|
||||||
.useValue({
|
});
|
||||||
hasWorkspaceFeature() {
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -153,38 +34,34 @@ test.afterEach.always(async t => {
|
|||||||
|
|
||||||
test('should send invite email', async t => {
|
test('should send invite email', async t => {
|
||||||
const { mail, app } = t.context;
|
const { mail, app } = t.context;
|
||||||
|
|
||||||
if (mail.hasConfigured()) {
|
if (mail.hasConfigured()) {
|
||||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||||
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
||||||
|
|
||||||
const workspace = await createWorkspace(app, u1.token.token);
|
const workspace = await createWorkspace(app, u1.token.token);
|
||||||
const inviteId = await inviteUser(
|
|
||||||
|
const stub = Sinon.stub(mail, 'sendMail');
|
||||||
|
|
||||||
|
await inviteUser(
|
||||||
app,
|
app,
|
||||||
u1.token.token,
|
u1.token.token,
|
||||||
workspace.id,
|
workspace.id,
|
||||||
u2.email,
|
u2.email,
|
||||||
'Admin'
|
'Admin',
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
const inviteInfo = await getInviteInfo(app, u1.token.token, inviteId);
|
t.true(stub.calledOnce);
|
||||||
|
|
||||||
const resp = await mail.sendInviteEmail(
|
const args = stub.args[0][0];
|
||||||
'production@toeverything.info',
|
|
||||||
inviteId,
|
t.is(args.to, u2.email);
|
||||||
{
|
t.true(
|
||||||
workspace: {
|
args.subject!.startsWith(
|
||||||
id: inviteInfo.workspace.id,
|
`${u1.name} invited you to join` /* we don't know the name of mocked workspace */
|
||||||
name: inviteInfo.workspace.name,
|
)
|
||||||
avatar: '',
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
avatar: inviteInfo.user?.avatarUrl || '',
|
|
||||||
name: inviteInfo.user?.name || '',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
t.is(resp.accepted.length, 1, 'failed to send invite email');
|
|
||||||
}
|
}
|
||||||
t.pass();
|
t.pass();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user