feat(web): granular api access controls (#18179)

* feat: api access control

* feat(web): granular api access controls

* fix test

* fix e2e test

* fix: lint

* pr feedback

* merge main + new design

* finalize styling

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
Daimolean
2025-05-29 02:16:43 +08:00
committed by GitHub
parent f0d881b4f8
commit b054e9dc2c
12 changed files with 311 additions and 37 deletions

View File

@@ -69,7 +69,9 @@ describe(ApiKeyService.name, () => {
mocks.apiKey.getById.mockResolvedValue(void 0);
await expect(sut.update(auth, id, { name: 'New Name' })).rejects.toBeInstanceOf(BadRequestException);
await expect(sut.update(auth, id, { name: 'New Name', permissions: [Permission.ALL] })).rejects.toBeInstanceOf(
BadRequestException,
);
expect(mocks.apiKey.update).not.toHaveBeenCalledWith(id);
});
@@ -82,9 +84,28 @@ describe(ApiKeyService.name, () => {
mocks.apiKey.getById.mockResolvedValue(apiKey);
mocks.apiKey.update.mockResolvedValue(apiKey);
await sut.update(auth, apiKey.id, { name: newName });
await sut.update(auth, apiKey.id, { name: newName, permissions: [Permission.ALL] });
expect(mocks.apiKey.update).toHaveBeenCalledWith(auth.user.id, apiKey.id, { name: newName });
expect(mocks.apiKey.update).toHaveBeenCalledWith(auth.user.id, apiKey.id, {
name: newName,
permissions: [Permission.ALL],
});
});
it('should update permissions', async () => {
const auth = factory.auth();
const apiKey = factory.apiKey({ userId: auth.user.id });
const newPermissions = [Permission.ACTIVITY_CREATE, Permission.ACTIVITY_READ, Permission.ACTIVITY_UPDATE];
mocks.apiKey.getById.mockResolvedValue(apiKey);
mocks.apiKey.update.mockResolvedValue(apiKey);
await sut.update(auth, apiKey.id, { name: apiKey.name, permissions: newPermissions });
expect(mocks.apiKey.update).toHaveBeenCalledWith(auth.user.id, apiKey.id, {
name: apiKey.name,
permissions: newPermissions,
});
});
});

View File

@@ -32,7 +32,7 @@ export class ApiKeyService extends BaseService {
throw new BadRequestException('API Key not found');
}
const key = await this.apiKeyRepository.update(auth.user.id, id, { name: dto.name });
const key = await this.apiKeyRepository.update(auth.user.id, id, { name: dto.name, permissions: dto.permissions });
return this.map(key);
}