From 10daf5fa617c1e5fa817c5129ec134694c5809e6 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 14 Feb 2025 20:50:05 +0100 Subject: [PATCH] Extend create tag endpoint --- apps/api/src/app/tag/create-tag.dto.ts | 6 ++- apps/api/src/app/tag/tag.controller.ts | 39 +++++++++++++++++-- apps/api/src/app/tag/update-tag.dto.ts | 6 ++- apps/api/src/app/user/user.service.ts | 1 + .../holding-detail-dialog.component.ts | 10 ++--- .../holding-detail-dialog.html | 2 +- libs/common/src/lib/permissions.ts | 3 ++ 7 files changed, 55 insertions(+), 12 deletions(-) diff --git a/apps/api/src/app/tag/create-tag.dto.ts b/apps/api/src/app/tag/create-tag.dto.ts index 650a0ce12..09c29d25a 100644 --- a/apps/api/src/app/tag/create-tag.dto.ts +++ b/apps/api/src/app/tag/create-tag.dto.ts @@ -1,6 +1,10 @@ -import { IsString } from 'class-validator'; +import { IsOptional, IsString } from 'class-validator'; export class CreateTagDto { @IsString() name: string; + + @IsOptional() + @IsString() + userId?: string; } diff --git a/apps/api/src/app/tag/tag.controller.ts b/apps/api/src/app/tag/tag.controller.ts index 6198a0bf5..862f0a708 100644 --- a/apps/api/src/app/tag/tag.controller.ts +++ b/apps/api/src/app/tag/tag.controller.ts @@ -1,6 +1,7 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; -import { permissions } from '@ghostfolio/common/permissions'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { RequestWithUser } from '@ghostfolio/common/types'; import { Body, @@ -8,11 +9,13 @@ import { Delete, Get, HttpException, + Inject, Param, Post, Put, UseGuards } from '@nestjs/common'; +import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; import { Tag } from '@prisma/client'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; @@ -23,7 +26,10 @@ import { UpdateTagDto } from './update-tag.dto'; @Controller('tag') export class TagController { - public constructor(private readonly tagService: TagService) {} + public constructor( + @Inject(REQUEST) private readonly request: RequestWithUser, + private readonly tagService: TagService + ) {} @Get() @HasPermission(permissions.readTags) @@ -33,9 +39,34 @@ export class TagController { } @Post() - @HasPermission(permissions.createTag) - @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + @UseGuards(AuthGuard('jwt')) public async createTag(@Body() data: CreateTagDto): Promise { + const canCreateOwnTag = hasPermission( + this.request.user.permissions, + permissions.createOwnTag + ); + + const canCreateTag = hasPermission( + this.request.user.permissions, + permissions.createTag + ); + + if (!canCreateOwnTag && !canCreateTag) { + throw new HttpException( + getReasonPhrase(StatusCodes.FORBIDDEN), + StatusCodes.FORBIDDEN + ); + } + + if (canCreateOwnTag && !canCreateTag) { + if (data.userId !== this.request.user.id) { + throw new HttpException( + getReasonPhrase(StatusCodes.BAD_REQUEST), + StatusCodes.BAD_REQUEST + ); + } + } + return this.tagService.createTag(data); } diff --git a/apps/api/src/app/tag/update-tag.dto.ts b/apps/api/src/app/tag/update-tag.dto.ts index b26ffde11..5ae42dcc6 100644 --- a/apps/api/src/app/tag/update-tag.dto.ts +++ b/apps/api/src/app/tag/update-tag.dto.ts @@ -1,4 +1,4 @@ -import { IsString } from 'class-validator'; +import { IsOptional, IsString } from 'class-validator'; export class UpdateTagDto { @IsString() @@ -6,4 +6,8 @@ export class UpdateTagDto { @IsString() name: string; + + @IsOptional() + @IsString() + userId?: string; } diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 30d10c8d6..dcf9d9404 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -347,6 +347,7 @@ export class UserService { permissions.accessHoldingsChart, permissions.createAccess, permissions.createMarketDataOfOwnAssetProfile, + permissions.createOwnTag, permissions.readAiPrompt, permissions.readMarketDataOfOwnAssetProfile, permissions.updateMarketDataOfOwnAssetProfile diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts index fe572241a..54fab34d6 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts @@ -99,7 +99,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { public dividendYieldPercentWithCurrencyEffect: number; public feeInBaseCurrency: number; public firstBuyDate: string; - public hasPermissionToCreateTag: boolean; + public hasPermissionToCreateOwnTag: boolean; public hasPermissionToReadMarketDataOfOwnAssetProfile: boolean; public historicalDataItems: LineChartItem[]; public investment: number; @@ -161,9 +161,9 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { return id === undefined; }); - if (newTag && this.hasPermissionToCreateTag) { + if (newTag && this.hasPermissionToCreateOwnTag) { this.adminService - .postTag(newTag) + .postTag({ ...newTag, userId: this.user.id }) .pipe( switchMap((createdTag) => { return this.dataService.putHoldingTags({ @@ -448,9 +448,9 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { if (state?.user) { this.user = state.user; - this.hasPermissionToCreateTag = hasPermission( + this.hasPermissionToCreateOwnTag = hasPermission( this.user.permissions, - permissions.createTag + permissions.createOwnTag ); this.tagsAvailable = diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html index c7d5c2627..df1c0c62a 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -388,7 +388,7 @@