import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { CreateAccessDto, UpdateAccessDto } from '@ghostfolio/common/dtos'; import { SubscriptionType } from '@ghostfolio/common/enums'; import { Access, AccessSettings } from '@ghostfolio/common/interfaces'; import { permissions } from '@ghostfolio/common/permissions'; import type { RequestWithUser } from '@ghostfolio/common/types'; import { Body, Controller, Delete, Get, HttpException, Inject, Param, Post, Put, UseGuards } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; import { Access as AccessModel, Prisma } from '@prisma/client'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { AccessService } from './access.service'; @Controller('access') export class AccessController { public constructor( private readonly accessService: AccessService, private readonly configurationService: ConfigurationService, @Inject(REQUEST) private readonly request: RequestWithUser ) {} @Get() @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async getAllAccesses(): Promise { const accessesWithGranteeUser = await this.accessService.accesses({ include: { granteeUser: true }, orderBy: [{ granteeUserId: 'desc' }, { createdAt: 'asc' }], where: { userId: this.request.user.id } }); return accessesWithGranteeUser.map( ({ alias, granteeUser, id, permissions: accessPermissions, settings }) => { if (granteeUser) { return { alias, grantee: granteeUser?.id, id, permissions: accessPermissions, settings: settings as AccessSettings, type: 'PRIVATE' }; } return { alias, grantee: 'Public', id, permissions: accessPermissions, settings: settings as AccessSettings, type: 'PUBLIC' }; } ); } @HasPermission(permissions.createAccess) @Post() @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async createAccess( @Body() data: CreateAccessDto ): Promise { if ( this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && this.request.user.subscription.type === SubscriptionType.Basic ) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), StatusCodes.FORBIDDEN ); } try { const settings: AccessSettings = data.filter ? { filter: data.filter } : {}; return this.accessService.createAccess({ alias: data.alias || undefined, granteeUser: data.granteeUserId ? { connect: { id: data.granteeUserId } } : undefined, permissions: data.permissions, settings: settings as Prisma.InputJsonValue, user: { connect: { id: this.request.user.id } } }); } catch { throw new HttpException( getReasonPhrase(StatusCodes.BAD_REQUEST), StatusCodes.BAD_REQUEST ); } } @HasPermission(permissions.updateAccess) @Put(':id') @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async updateAccess( @Body() data: UpdateAccessDto, @Param('id') id: string ): Promise { if ( this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && this.request.user.subscription.type === SubscriptionType.Basic ) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), StatusCodes.FORBIDDEN ); } const originalAccess = await this.accessService.access({ id, userId: this.request.user.id }); if (!originalAccess) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), StatusCodes.FORBIDDEN ); } try { const settings: AccessSettings = data.filter ? { filter: data.filter } : {}; return this.accessService.updateAccess({ data: { alias: data.alias, granteeUser: data.granteeUserId ? { connect: { id: data.granteeUserId } } : { disconnect: true }, permissions: data.permissions, settings: settings as Prisma.InputJsonValue }, where: { id } }); } catch { throw new HttpException( getReasonPhrase(StatusCodes.BAD_REQUEST), StatusCodes.BAD_REQUEST ); } } @Delete(':id') @HasPermission(permissions.deleteAccess) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async deleteAccess(@Param('id') id: string): Promise { const originalAccess = await this.accessService.access({ id, userId: this.request.user.id }); if (!originalAccess) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), StatusCodes.FORBIDDEN ); } return this.accessService.deleteAccess({ id }); } }