From fa5110e76f8dcbb45d70f1a0cba7a264ecf2246e Mon Sep 17 00:00:00 2001 From: forehalo Date: Mon, 19 May 2025 09:30:37 +0000 Subject: [PATCH] fix(server): seat not allocated when new user invited to licensed workspace (#12322) ## Summary by CodeRabbit - **Bug Fixes** - Improved the accuracy of workspace member overcapacity calculation. - Corrected seat allocation handling for one-time license variants, ensuring proper event emission and bypassing unnecessary updates. - **Refactor** - Streamlined internal logic by removing an obsolete method related to seat count checks. - **Tests** - Removed a workspace member list pagination test to streamline end-to-end testing. --- .../backend/server/src/core/quota/service.ts | 3 +- .../server/src/models/workspace-user.ts | 9 --- .../server/src/plugins/license/service.ts | 9 +++ tests/affine-cloud/e2e/workspace.spec.ts | 73 ------------------- 4 files changed, 10 insertions(+), 84 deletions(-) diff --git a/packages/backend/server/src/core/quota/service.ts b/packages/backend/server/src/core/quota/service.ts index 54969d448..cbbaf4fc9 100644 --- a/packages/backend/server/src/core/quota/service.ts +++ b/packages/backend/server/src/core/quota/service.ts @@ -144,8 +144,7 @@ export class QuotaService { : await this.getWorkspaceStorageUsage(workspaceId); const memberCount = await this.models.workspaceUser.chargedCount(workspaceId); - const overcapacityMemberCount = - await this.models.workspaceUser.insufficientSeatMemberCount(workspaceId); + const overcapacityMemberCount = memberCount - quota.memberLimit; return { ...quota, diff --git a/packages/backend/server/src/models/workspace-user.ts b/packages/backend/server/src/models/workspace-user.ts index 1a6a6499f..f8ae53f8f 100644 --- a/packages/backend/server/src/models/workspace-user.ts +++ b/packages/backend/server/src/models/workspace-user.ts @@ -289,15 +289,6 @@ export class WorkspaceUserModel extends BaseModel { }); } - async insufficientSeatMemberCount(workspaceId: string) { - return this.db.workspaceUserRole.count({ - where: { - workspaceId, - status: WorkspaceMemberStatus.NeedMoreSeat, - }, - }); - } - async getUserActiveRoles( userId: string, filter: { role?: WorkspaceRole } = {} diff --git a/packages/backend/server/src/plugins/license/service.ts b/packages/backend/server/src/plugins/license/service.ts index cc6fc74ad..d02b29959 100644 --- a/packages/backend/server/src/plugins/license/service.ts +++ b/packages/backend/server/src/plugins/license/service.ts @@ -288,6 +288,15 @@ export class LicenseService { return; } + if (license.variant === SubscriptionVariant.Onetime) { + this.event.emit('workspace.members.allocateSeats', { + workspaceId, + quantity: license.quantity, + }); + + return; + } + const count = await this.models.workspaceUser.chargedCount(workspaceId); await this.fetchAffinePro(`/api/team/licenses/${license.key}/seats`, { method: 'POST', diff --git a/tests/affine-cloud/e2e/workspace.spec.ts b/tests/affine-cloud/e2e/workspace.spec.ts index 27e3313a3..93edc0a10 100644 --- a/tests/affine-cloud/e2e/workspace.spec.ts +++ b/tests/affine-cloud/e2e/workspace.spec.ts @@ -1,18 +1,15 @@ import { test } from '@affine-test/kit/playwright'; import { - addUserToWorkspace, createRandomUser, enableCloudWorkspace, loginUser, } from '@affine-test/kit/utils/cloud'; import { clickPageModeButton } from '@affine-test/kit/utils/editor'; import { - clickNewPageButton, getBlockSuiteEditorTitle, waitForEditorLoad, waitForEmptyEditor, } from '@affine-test/kit/utils/page-logic'; -import { openSettingModal } from '@affine-test/kit/utils/setting'; import { createLocalWorkspace } from '@affine-test/kit/utils/workspace'; import { expect } from '@playwright/test'; @@ -28,76 +25,6 @@ test.beforeEach(async ({ page }) => { await loginUser(page, user); }); -test('should have pagination in member list', async ({ page }) => { - await page.reload(); - await waitForEditorLoad(page); - await createLocalWorkspace( - { - name: 'test', - }, - page - ); - await enableCloudWorkspace(page); - await clickNewPageButton(page); - const currentUrl = page.url(); - // format: http://localhost:8080/workspace/${workspaceId}/xxx - const workspaceId = currentUrl.split('/')[4]; - - // create 10 user and add to workspace - const createUserAndAddToWorkspace = async () => { - const userB = await createRandomUser(); - await addUserToWorkspace(workspaceId, userB.id, 1 /* READ */); - }; - await Promise.all( - Array.from({ length: 10 }) - .fill(1) - .map(() => createUserAndAddToWorkspace()) - ); - - await openSettingModal(page); - await page - .getByTestId('settings-sidebar') - .getByTestId('workspace-setting:members') - .click(); - - await page.waitForTimeout(1000); - - const firstPageMemberItemCount = await page - .locator('[data-testid="member-item"]') - .count(); - - expect(firstPageMemberItemCount).toBe(8); - - const navigationItems = await page - .getByRole('navigation') - .getByRole('button') - .all(); - - // make sure the first member is the owner - await expect(page.getByTestId('member-item').first()).toContainText( - 'Workspace Owner' - ); - - // There have four pagination items: < 1 2 > - expect(navigationItems.length).toBe(4); - // Click second page - await navigationItems[2].click(); - await page.waitForTimeout(500); - // There should have other three members in second page - const secondPageMemberItemCount = await page - .locator('[data-testid="member-item"]') - .count(); - expect(secondPageMemberItemCount).toBe(3); - // Click left arrow to back to first page - await navigationItems[0].click(); - await page.waitForTimeout(500); - await expect(page.locator('[data-testid="member-item"]')).toHaveCount(8); - // Click right arrow to second page - await navigationItems[3].click(); - await page.waitForTimeout(500); - await expect(page.locator('[data-testid="member-item"]')).toHaveCount(3); -}); - test('should transform local favorites data', async ({ page }) => { await page.reload(); await waitForEditorLoad(page);