postiz/apps/backend/src/api/routes/users.controller.ts

212 lines
6.1 KiB
TypeScript

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();
}
}