From 568c4cc8f34bc0efa2ee1d197352c0ac03249f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Mart=C3=ADn?= Date: Sun, 28 Sep 2025 23:47:28 +0200 Subject: [PATCH] Refactor access management: update access handling and permissions, enhance UI interactions for editing access --- apps/api/src/app/access/access.controller.ts | 45 ++++----- apps/api/src/app/access/access.service.ts | 15 ++- apps/api/src/app/access/update-access.dto.ts | 3 + .../access-table/access-table.component.html | 15 +-- .../access-table/access-table.component.ts | 6 +- ...reate-or-update-access-dialog.component.ts | 99 +++++++++---------- .../create-or-update-access-dialog.html | 8 +- .../interfaces/interfaces.ts | 1 - .../user-account-access.component.ts | 68 ++++++------- .../user-account-access.html | 2 +- apps/client/src/app/services/data.service.ts | 12 +-- libs/common/src/lib/permissions.ts | 3 + 12 files changed, 135 insertions(+), 142 deletions(-) diff --git a/apps/api/src/app/access/access.controller.ts b/apps/api/src/app/access/access.controller.ts index 372c7f34a..836bd49c0 100644 --- a/apps/api/src/app/access/access.controller.ts +++ b/apps/api/src/app/access/access.controller.ts @@ -34,21 +34,6 @@ export class AccessController { @Inject(REQUEST) private readonly request: RequestWithUser ) {} - @Get(':id') - @UseGuards(AuthGuard('jwt'), HasPermissionGuard) - public async getAccess(@Param('id') id: string): Promise { - const access = await this.accessService.access({ id }); - - if (!access || access.userId !== this.request.user.id) { - throw new HttpException( - getReasonPhrase(StatusCodes.FORBIDDEN), - StatusCodes.FORBIDDEN - ); - } - - return access; - } - @Get() @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async getAllAccesses(): Promise { @@ -56,7 +41,10 @@ export class AccessController { include: { granteeUser: true }, - orderBy: { granteeUserId: 'asc' }, + orderBy: [ + { granteeUserId: 'desc' }, // NULL values first (public access), then user IDs + { createdAt: 'asc' } // Within each group, order by creation time + ], where: { userId: this.request.user.id } }); @@ -120,9 +108,12 @@ export class AccessController { @HasPermission(permissions.deleteAccess) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async deleteAccess(@Param('id') id: string): Promise { - const access = await this.accessService.access({ id }); + const originalAccess = await this.accessService.access({ + id, + userId: this.request.user.id + }); - if (!access || access.userId !== this.request.user.id) { + if (!originalAccess) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), StatusCodes.FORBIDDEN @@ -134,6 +125,7 @@ export class AccessController { }); } + @HasPermission(permissions.updateAccess) @Put(':id') @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async updateAccess( @@ -150,9 +142,12 @@ export class AccessController { ); } - const access = await this.accessService.access({ id }); + const originalAccess = await this.accessService.access({ + id, + userId: this.request.user.id + }); - if (!access || access.userId !== this.request.user.id) { + if (!originalAccess) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), StatusCodes.FORBIDDEN @@ -160,16 +155,16 @@ export class AccessController { } try { - return this.accessService.updateAccess( - { id }, - { + return this.accessService.updateAccess({ + data: { alias: data.alias, granteeUser: data.granteeUserId ? { connect: { id: data.granteeUserId } } : { disconnect: true }, permissions: data.permissions - } - ); + }, + where: { id } + }); } catch { throw new HttpException( getReasonPhrase(StatusCodes.BAD_REQUEST), diff --git a/apps/api/src/app/access/access.service.ts b/apps/api/src/app/access/access.service.ts index 995e27ae9..4c4534811 100644 --- a/apps/api/src/app/access/access.service.ts +++ b/apps/api/src/app/access/access.service.ts @@ -25,7 +25,9 @@ export class AccessService { take?: number; cursor?: Prisma.AccessWhereUniqueInput; where?: Prisma.AccessWhereInput; - orderBy?: Prisma.AccessOrderByWithRelationInput; + orderBy?: + | Prisma.AccessOrderByWithRelationInput + | Prisma.AccessOrderByWithRelationInput[]; }): Promise { const { include, skip, take, cursor, where, orderBy } = params; @@ -53,10 +55,13 @@ export class AccessService { }); } - public async updateAccess( - where: Prisma.AccessWhereUniqueInput, - data: Prisma.AccessUpdateInput - ): Promise { + public async updateAccess({ + data, + where + }: { + data: Prisma.AccessUpdateInput; + where: Prisma.AccessWhereUniqueInput; + }): Promise { return this.prismaService.access.update({ where, data diff --git a/apps/api/src/app/access/update-access.dto.ts b/apps/api/src/app/access/update-access.dto.ts index 5e8799747..26b6df687 100644 --- a/apps/api/src/app/access/update-access.dto.ts +++ b/apps/api/src/app/access/update-access.dto.ts @@ -2,6 +2,9 @@ import { AccessPermission } from '@prisma/client'; import { IsEnum, IsOptional, IsString, IsUUID } from 'class-validator'; export class UpdateAccessDto { + @IsString() + id: string; + @IsOptional() @IsString() alias?: string; diff --git a/apps/client/src/app/components/access-table/access-table.component.html b/apps/client/src/app/components/access-table/access-table.component.html index 71e01f180..ded172acd 100644 --- a/apps/client/src/app/components/access-table/access-table.component.html +++ b/apps/client/src/app/components/access-table/access-table.component.html @@ -65,12 +65,14 @@ - + @if (user?.settings?.isExperimentalFeatures) { + + } @if (element.type === 'PUBLIC') { } -