import { Body, Controller, Get, HttpException, Post, Query, Req, Res, } from '@nestjs/common'; import { GetUserFromRequest } from '@gitroom/nestjs-libraries/user/user.from.request'; import { Organization, User } from '@prisma/client'; import { SubscriptionService } from '@gitroom/nestjs-libraries/database/prisma/subscriptions/subscription.service'; import { GetOrgFromRequest } from '@gitroom/nestjs-libraries/user/org.from.request'; import { StripeService } from '@gitroom/nestjs-libraries/services/stripe.service'; import { Response, Request } from 'express'; import { AuthService } from '@gitroom/backend/services/auth/auth.service'; import { OrganizationService } from '@gitroom/nestjs-libraries/database/prisma/organizations/organization.service'; import { CheckPolicies } from '@gitroom/backend/services/auth/permissions/permissions.ability'; import { AuthorizationActions, Sections, } from '@gitroom/backend/services/auth/permissions/permissions.service'; import { removeSubdomain } from '@gitroom/helpers/subdomain/subdomain.management'; import { pricing } from '@gitroom/nestjs-libraries/database/prisma/subscriptions/pricing'; import { ApiTags } from '@nestjs/swagger'; import { UsersService } from '@gitroom/nestjs-libraries/database/prisma/users/users.service'; import { UserDetailDto } from '@gitroom/nestjs-libraries/dtos/users/user.details.dto'; import { HttpForbiddenException } from '@gitroom/nestjs-libraries/services/exception.filter'; @ApiTags('User') @Controller('/user') export class UsersController { constructor( private _subscriptionService: SubscriptionService, private _stripeService: StripeService, private _authService: AuthService, private _orgService: OrganizationService, private _userService: UsersService ) {} @Get('/self') async getSelf( @GetUserFromRequest() user: User, @GetOrgFromRequest() organization: Organization, @Req() req: Request, ) { if (!organization) { throw new HttpForbiddenException(); } return { ...user, orgId: organization.id, // @ts-ignore totalChannels: organization?.subscription?.totalChannels || pricing.FREE.channel, // @ts-ignore tier: organization?.subscription?.subscriptionTier || 'FREE', // @ts-ignore role: organization?.users[0]?.role, // @ts-ignore isLifetime: !!organization?.subscription?.isLifetime, admin: !!user.isSuperAdmin, impersonate: !!req.cookies.impersonate, }; } @Get('/personal') async getPersonal(@GetUserFromRequest() user: User) { return this._userService.getPersonal(user.id); } @Get('/impersonate') async getImpersonate( @GetUserFromRequest() user: User, @Query('name') name: string ) { if (!user.isSuperAdmin) { throw new HttpException('Unauthorized', 400); } return this._userService.getImpersonateUser(name); } @Post('/impersonate') async setImpersonate( @GetUserFromRequest() user: User, @Body('id') id: string, @Res({ passthrough: true }) response: Response ) { if (!user.isSuperAdmin) { throw new HttpException('Unauthorized', 400); } response.cookie('impersonate', id, { domain: '.' + new URL(removeSubdomain(process.env.FRONTEND_URL!)).hostname, secure: true, httpOnly: true, sameSite: 'none', expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365), }); } @Post('/personal') async changePersonal( @GetUserFromRequest() user: User, @Body() body: UserDetailDto ) { return this._userService.changePersonal(user.id, body); } @Get('/subscription') @CheckPolicies([AuthorizationActions.Create, Sections.ADMIN]) async getSubscription(@GetOrgFromRequest() organization: Organization) { const subscription = await this._subscriptionService.getSubscriptionByOrganizationId( organization.id ); return subscription ? { subscription } : { subscription: undefined }; } @Get('/subscription/tiers') @CheckPolicies([AuthorizationActions.Create, Sections.ADMIN]) async tiers() { return this._stripeService.getPackages(); } @Post('/join-org') async joinOrg( @GetUserFromRequest() user: User, @Body('org') org: string, @Res({ passthrough: true }) response: Response ) { const getOrgFromCookie = this._authService.getOrgFromCookie(org); if (!getOrgFromCookie) { return response.status(200).json({ id: null }); } const addedOrg = await this._orgService.addUserToOrg( user.id, getOrgFromCookie.id, getOrgFromCookie.orgId, getOrgFromCookie.role ); response.status(200).json({ id: typeof addedOrg !== 'boolean' ? addedOrg.organizationId : null, }); } @Get('/organizations') async getOrgs(@GetUserFromRequest() user: User) { return (await this._orgService.getOrgsByUserId(user.id)).filter( (f) => !f.users[0].disabled ); } @Post('/change-org') changeOrg( @Body('id') id: string, @Res({ passthrough: true }) response: Response ) { response.cookie('showorg', id, { domain: '.' + new URL(removeSubdomain(process.env.FRONTEND_URL!)).hostname, secure: true, httpOnly: true, sameSite: 'none', expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365), }); response.status(200).send(); } @Post('/logout') logout(@Res({ passthrough: true }) response: Response) { response.cookie('auth', '', { domain: '.' + new URL(removeSubdomain(process.env.FRONTEND_URL!)).hostname, secure: true, httpOnly: true, maxAge: -1, expires: new Date(0), sameSite: 'none', }); response.cookie('showorg', '', { domain: '.' + new URL(removeSubdomain(process.env.FRONTEND_URL!)).hostname, secure: true, httpOnly: true, maxAge: -1, expires: new Date(0), sameSite: 'none', }); response.cookie('impersonate', '', { domain: '.' + new URL(removeSubdomain(process.env.FRONTEND_URL!)).hostname, secure: true, httpOnly: true, maxAge: -1, expires: new Date(0), sameSite: 'none', }); response.status(200).send(); } }