fix(server): seat not allocated when new user invited to licensed workspace (#12322)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## 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.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
forehalo
2025-05-19 09:30:37 +00:00
parent 91e7b28dd5
commit fa5110e76f
4 changed files with 10 additions and 84 deletions

View File

@@ -144,8 +144,7 @@ export class QuotaService {
: await this.getWorkspaceStorageUsage(workspaceId); : await this.getWorkspaceStorageUsage(workspaceId);
const memberCount = const memberCount =
await this.models.workspaceUser.chargedCount(workspaceId); await this.models.workspaceUser.chargedCount(workspaceId);
const overcapacityMemberCount = const overcapacityMemberCount = memberCount - quota.memberLimit;
await this.models.workspaceUser.insufficientSeatMemberCount(workspaceId);
return { return {
...quota, ...quota,

View File

@@ -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( async getUserActiveRoles(
userId: string, userId: string,
filter: { role?: WorkspaceRole } = {} filter: { role?: WorkspaceRole } = {}

View File

@@ -288,6 +288,15 @@ export class LicenseService {
return; 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); const count = await this.models.workspaceUser.chargedCount(workspaceId);
await this.fetchAffinePro(`/api/team/licenses/${license.key}/seats`, { await this.fetchAffinePro(`/api/team/licenses/${license.key}/seats`, {
method: 'POST', method: 'POST',

View File

@@ -1,18 +1,15 @@
import { test } from '@affine-test/kit/playwright'; import { test } from '@affine-test/kit/playwright';
import { import {
addUserToWorkspace,
createRandomUser, createRandomUser,
enableCloudWorkspace, enableCloudWorkspace,
loginUser, loginUser,
} from '@affine-test/kit/utils/cloud'; } from '@affine-test/kit/utils/cloud';
import { clickPageModeButton } from '@affine-test/kit/utils/editor'; import { clickPageModeButton } from '@affine-test/kit/utils/editor';
import { import {
clickNewPageButton,
getBlockSuiteEditorTitle, getBlockSuiteEditorTitle,
waitForEditorLoad, waitForEditorLoad,
waitForEmptyEditor, waitForEmptyEditor,
} from '@affine-test/kit/utils/page-logic'; } from '@affine-test/kit/utils/page-logic';
import { openSettingModal } from '@affine-test/kit/utils/setting';
import { createLocalWorkspace } from '@affine-test/kit/utils/workspace'; import { createLocalWorkspace } from '@affine-test/kit/utils/workspace';
import { expect } from '@playwright/test'; import { expect } from '@playwright/test';
@@ -28,76 +25,6 @@ test.beforeEach(async ({ page }) => {
await loginUser(page, user); 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 }) => { test('should transform local favorites data', async ({ page }) => {
await page.reload(); await page.reload();
await waitForEditorLoad(page); await waitForEditorLoad(page);