diff --git a/apps/api/src/app/import/import.module.ts b/apps/api/src/app/import/import.module.ts index 16f4bcdd6..943f95c70 100644 --- a/apps/api/src/app/import/import.module.ts +++ b/apps/api/src/app/import/import.module.ts @@ -7,7 +7,7 @@ import { ConfigurationModule } from '@ghostfolio/api/services/configuration/conf import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering/data-gathering.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; -import { PlatformModule } from '@ghostfolio/api/services/platform/platform.module'; +import { PlatformModule } from '@ghostfolio/api/app/platform/platform.module'; import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; import { Module } from '@nestjs/common'; diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index c3b8f63b3..99d83677f 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -6,7 +6,7 @@ import { OrderService } from '@ghostfolio/api/app/order/order.service'; import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; -import { PlatformService } from '@ghostfolio/api/services/platform/platform.service'; +import { PlatformService } from '@ghostfolio/api/app/platform/platform.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { parseDate } from '@ghostfolio/common/helper'; import { UniqueAsset } from '@ghostfolio/common/interfaces'; @@ -130,7 +130,7 @@ export class ImportService { } } }), - this.platformService.get() + this.platformService.getPlatforms() ]); for (const account of accountsDto) { diff --git a/apps/api/src/app/platform/create-platform.dto.ts b/apps/api/src/app/platform/create-platform.dto.ts new file mode 100644 index 000000000..0c3cfb781 --- /dev/null +++ b/apps/api/src/app/platform/create-platform.dto.ts @@ -0,0 +1,13 @@ +import { IsOptional, IsString } from 'class-validator'; + +export class CreatePlatformDto { + @IsOptional() + @IsString() + id?: string; + + @IsString() + name: string; + + @IsString() + url: string; +} diff --git a/apps/api/src/app/platform/platform.controller.ts b/apps/api/src/app/platform/platform.controller.ts new file mode 100644 index 000000000..ef80ce608 --- /dev/null +++ b/apps/api/src/app/platform/platform.controller.ts @@ -0,0 +1,113 @@ +import { + Body, + Controller, + Delete, + Get, + HttpException, + Inject, + Param, + Post, + Put, + UseGuards +} from '@nestjs/common'; +import { PlatformService } from './platform.service'; +import { AuthGuard } from '@nestjs/passport'; +import { Platform } from '@prisma/client'; +import { CreatePlatformDto } from './create-platform.dto'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { RequestWithUser } from '@ghostfolio/common/types'; +import { REQUEST } from '@nestjs/core'; +import { getReasonPhrase, StatusCodes } from 'http-status-codes'; +import { UpdatePlatformDto } from './update-platform.dto'; + +@Controller('platform') +export class PlatformController { + public constructor( + private platformService: PlatformService, + @Inject(REQUEST) private readonly request: RequestWithUser + ) {} + + @Get() + @UseGuards(AuthGuard('jwt')) + public async getPlatforms(): Promise { + return this.platformService.getPlatforms(); + } + + @Post() + @UseGuards(AuthGuard('jwt')) + public async createPlatform( + @Body() data: CreatePlatformDto + ): Promise { + if ( + !hasPermission(this.request.user.permissions, permissions.createPlatform) + ) { + throw new HttpException( + getReasonPhrase(StatusCodes.FORBIDDEN), + StatusCodes.FORBIDDEN + ); + } + return this.platformService.createPlatform(data); + } + + @Put(':id') + @UseGuards(AuthGuard('jwt')) + public async updatePlatform( + @Param(':id') id: string, + @Body() data: UpdatePlatformDto + ) { + if ( + !hasPermission(this.request.user.permissions, permissions.updatePlatform) + ) { + throw new HttpException( + getReasonPhrase(StatusCodes.FORBIDDEN), + StatusCodes.FORBIDDEN + ); + } + + const originalPlatform = await this.platformService.getPlatform({ + id + }); + + if (!originalPlatform) { + throw new HttpException( + getReasonPhrase(StatusCodes.FORBIDDEN), + StatusCodes.FORBIDDEN + ); + } + + return this.platformService.updatePlatform({ + data: { + ...data + }, + where: { + id + } + }); + } + + @Delete(':id') + @UseGuards(AuthGuard('jwt')) + public async deletePlatform(@Param(':id') id: string) { + if ( + !hasPermission(this.request.user.permissions, permissions.deletePlatform) + ) { + throw new HttpException( + getReasonPhrase(StatusCodes.FORBIDDEN), + StatusCodes.FORBIDDEN + ); + } + + const originalPlatform = await this.platformService.getPlatform({ + id + }); + + if (!originalPlatform) { + throw new HttpException( + getReasonPhrase(StatusCodes.FORBIDDEN), + StatusCodes.FORBIDDEN + ); + } + + return this.platformService.deletePlatform({ id }); + } +} diff --git a/apps/api/src/services/platform/platform.module.ts b/apps/api/src/app/platform/platform.module.ts similarity index 75% rename from apps/api/src/services/platform/platform.module.ts rename to apps/api/src/app/platform/platform.module.ts index 8167a37e0..04ccdf4d6 100644 --- a/apps/api/src/services/platform/platform.module.ts +++ b/apps/api/src/app/platform/platform.module.ts @@ -1,9 +1,11 @@ import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; import { Module } from '@nestjs/common'; +import { PlatformController } from './platform.controller'; import { PlatformService } from './platform.service'; @Module({ + controllers: [PlatformController], exports: [PlatformService], imports: [PrismaModule], providers: [PlatformService] diff --git a/apps/api/src/app/platform/platform.service.ts b/apps/api/src/app/platform/platform.service.ts new file mode 100644 index 000000000..b5912415e --- /dev/null +++ b/apps/api/src/app/platform/platform.service.ts @@ -0,0 +1,43 @@ +import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; +import { Injectable } from '@nestjs/common'; +import { Platform, Prisma } from '@prisma/client'; + +@Injectable() +export class PlatformService { + public constructor(private readonly prismaService: PrismaService) {} + + public async getPlatforms(): Promise { + return this.prismaService.platform.findMany(); + } + + public async getPlatform( + platformWhereUniqueInput: Prisma.PlatformWhereUniqueInput + ): Promise { + return this.prismaService.platform.findUnique({ + where: platformWhereUniqueInput + }); + } + + public async createPlatform(data: Prisma.PlatformCreateInput) { + return this.prismaService.platform.create({ + data + }); + } + + public async updatePlatform(params: { + where: Prisma.PlatformWhereUniqueInput; + data: Prisma.PlatformUpdateInput; + }): Promise { + const { data, where } = params; + return this.prismaService.platform.update({ + data, + where + }); + } + + public async deletePlatform( + where: Prisma.PlatformWhereUniqueInput + ): Promise { + return this.prismaService.platform.delete({ where }); + } +} diff --git a/apps/api/src/app/platform/update-platform.dto.ts b/apps/api/src/app/platform/update-platform.dto.ts new file mode 100644 index 000000000..3af9f5c94 --- /dev/null +++ b/apps/api/src/app/platform/update-platform.dto.ts @@ -0,0 +1,13 @@ +import { IsOptional, IsString } from 'class-validator'; + +export class UpdatePlatformDto { + @IsOptional() + @IsString() + id?: string; + + @IsString() + name: string; + + @IsString() + url: string; +} diff --git a/apps/api/src/services/platform/platform.service.ts b/apps/api/src/services/platform/platform.service.ts deleted file mode 100644 index 51bd4d73d..000000000 --- a/apps/api/src/services/platform/platform.service.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; -import { Injectable } from '@nestjs/common'; - -@Injectable() -export class PlatformService { - public constructor(private readonly prismaService: PrismaService) {} - - public async get() { - return this.prismaService.platform.findMany(); - } -} diff --git a/libs/common/src/lib/permissions.ts b/libs/common/src/lib/permissions.ts index 46c78acd0..3cee2072b 100644 --- a/libs/common/src/lib/permissions.ts +++ b/libs/common/src/lib/permissions.ts @@ -27,7 +27,10 @@ export const permissions = { updateAuthDevice: 'updateAuthDevice', updateOrder: 'updateOrder', updateUserSettings: 'updateUserSettings', - updateViewMode: 'updateViewMode' + updateViewMode: 'updateViewMode', + createPlatform: 'createPlatform', + deletePlatform: 'deletePlatform', + updatePlatform: 'updatePlatform' }; export function getPermissions(aRole: Role): string[] { @@ -47,7 +50,10 @@ export function getPermissions(aRole: Role): string[] { permissions.updateAuthDevice, permissions.updateOrder, permissions.updateUserSettings, - permissions.updateViewMode + permissions.updateViewMode, + permissions.createPlatform, + permissions.deletePlatform, + permissions.updatePlatform ]; case 'DEMO':