From 5fcdc99f237f49580c74372bd145ce460cf156f3 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 27 Mar 2025 07:26:28 +0000 Subject: [PATCH] feat(server): add team user with team workspace in dev environment (#11228) close CLOUD-186 --- docs/developing-server.md | 8 ++ packages/backend/server/src/core/auth/dev.ts | 88 +++++++++++++++++++ .../backend/server/src/core/auth/service.ts | 46 +--------- 3 files changed, 99 insertions(+), 43 deletions(-) create mode 100644 packages/backend/server/src/core/auth/dev.ts diff --git a/docs/developing-server.md b/docs/developing-server.md index 2bfb8a971f..478179e88d 100644 --- a/docs/developing-server.md +++ b/docs/developing-server.md @@ -70,6 +70,14 @@ Workspace members up to 10 - name: Pro User - password: pro +### team user + +Include a default `Team Workspace` and the members up to 10 + +- email: team@affine.pro +- name: Team User +- password: team + ## Start frontend ```sh diff --git a/packages/backend/server/src/core/auth/dev.ts b/packages/backend/server/src/core/auth/dev.ts new file mode 100644 index 0000000000..beeff08172 --- /dev/null +++ b/packages/backend/server/src/core/auth/dev.ts @@ -0,0 +1,88 @@ +import { Models, UserFeatureName, WorkspaceFeatureName } from '../../models'; + +export async function createDevUsers(models: Models) { + const devUsers: { + email: string; + name: string; + password: string; + features: UserFeatureName[]; + workspaceFeatures?: WorkspaceFeatureName[]; + }[] = [ + { + email: 'dev@affine.pro', + name: 'Dev User', + password: 'dev', + features: ['free_plan_v1', 'unlimited_copilot', 'administrator'], + }, + { + email: 'pro@affine.pro', + name: 'Pro User', + password: 'pro', + features: ['pro_plan_v1', 'unlimited_copilot', 'administrator'], + }, + { + email: 'team@affine.pro', + name: 'Team User', + password: 'team', + features: ['pro_plan_v1', 'unlimited_copilot', 'administrator'], + workspaceFeatures: ['team_plan_v1'], + }, + ]; + const devWorkspaceBlob = Buffer.from( + 'AwbChK7tptz3DQAnAQRtZXRhBXBhZ2VzACgBBG1ldGEEbmFtZQF3EkRldiBXb3Jrc3BhY2UgRGVtbwEAwoSu7abc9w0AAQAEIQEGc3BhY2VzCm43RDJHT25KLUoBAAEK1NDZ6tqM+QsAAAKBjeqMoITIzgEAAQAEIQEGc3BhY2VzCmllSHphSlUtOC0BAAhHwoSu7abc9w0CASgA1NDZ6tqM+QsQAmlkAXcKZURSWTg2Rzg3YygA1NDZ6tqM+QsQBXRpdGxlAXcAKADU0Nnq2oz5CxAKY3JlYXRlRGF0ZQF7QnldYlT5cAAnANTQ2erajPkLEAR0YWdzAASN6oyghMjOAQCBwoSu7abc9w0CAQAEKQEGc3BhY2VzCmVEUlk4Nkc4N2MKZURSWTg2Rzg3Y3YAAAEDwoSu7abc9w0BAgfU0Nnq2oz5CwEAEI3qjKCEyM4BAgAFBgE=', + 'base64' + ); + + for (const { + email, + name, + password, + features, + workspaceFeatures, + } of devUsers) { + try { + let devUser = await models.user.getUserByEmail(email); + if (!devUser) { + devUser = await models.user.create({ + email, + name, + password, + }); + } + for (const feature of features) { + await models.userFeature.add(devUser.id, feature, name); + } + if (workspaceFeatures) { + for (const feature of workspaceFeatures) { + const workspaceIds = ( + await models.workspaceUser.getUserActiveRoles(devUser.id) + ).map(row => row.workspaceId); + const workspaces = await models.workspace.findMany(workspaceIds); + let hasFeatureWorkspace = false; + for (const workspace of workspaces) { + if (await models.workspaceFeature.has(workspace.id, feature)) { + hasFeatureWorkspace = true; + break; + } + } + if (!hasFeatureWorkspace) { + // create a new workspace with the feature + const workspace = await models.workspace.create(devUser.id); + await models.doc.upsert({ + spaceId: workspace.id, + docId: workspace.id, + blob: devWorkspaceBlob, + timestamp: Date.now(), + editorId: devUser.id, + }); + await models.workspaceFeature.add(workspace.id, feature, name, { + memberLimit: 10, + }); + } + } + } + } catch { + // ignore + } + } +} diff --git a/packages/backend/server/src/core/auth/service.ts b/packages/backend/server/src/core/auth/service.ts index 141efe30fc..e489e90333 100644 --- a/packages/backend/server/src/core/auth/service.ts +++ b/packages/backend/server/src/core/auth/service.ts @@ -3,14 +3,10 @@ import type { CookieOptions, Request, Response } from 'express'; import { assign, pick } from 'lodash-es'; import { Config, SignUpForbidden } from '../../base'; -import { - Models, - type User, - type UserFeatureName, - type UserSession, -} from '../../models'; +import { Models, type User, type UserSession } from '../../models'; import { FeatureService } from '../features'; import { Mailer } from '../mail/mailer'; +import { createDevUsers } from './dev'; import type { CurrentUser } from './session'; export function sessionUser( @@ -54,43 +50,7 @@ export class AuthService implements OnApplicationBootstrap { async onApplicationBootstrap() { if (this.config.node.dev) { - const devUsers: { - email: string; - name: string; - password: string; - features: UserFeatureName[]; - }[] = [ - { - email: 'dev@affine.pro', - name: 'Dev User', - password: 'dev', - features: ['free_plan_v1', 'unlimited_copilot', 'administrator'], - }, - { - email: 'pro@affine.pro', - name: 'Pro User', - password: 'pro', - features: ['pro_plan_v1', 'unlimited_copilot', 'administrator'], - }, - ]; - - for (const { email, name, password, features } of devUsers) { - try { - let devUser = await this.models.user.getUserByEmail(email); - if (!devUser) { - devUser = await this.models.user.create({ - email, - name, - password, - }); - } - for (const feature of features) { - await this.models.userFeature.add(devUser.id, feature, name); - } - } catch { - // ignore - } - } + await createDevUsers(this.models); } }