299 lines
8.9 KiB
TypeScript
299 lines
8.9 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 { getCookieUrlFromDomain } 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 { EmailNotificationsDto } from '@gitroom/nestjs-libraries/dtos/users/email-notifications.dto';
|
|
import { HttpForbiddenException } from '@gitroom/nestjs-libraries/services/exception.filter';
|
|
import { RealIP } from 'nestjs-real-ip';
|
|
import { UserAgent } from '@gitroom/nestjs-libraries/user/user.agent';
|
|
import { TrackEnum } from '@gitroom/nestjs-libraries/user/track.enum';
|
|
import { TrackService } from '@gitroom/nestjs-libraries/track/track.service';
|
|
import { makeId } from '@gitroom/nestjs-libraries/services/make.is';
|
|
import { AuthorizationActions, Sections } from '@gitroom/backend/services/auth/permissions/permission.exception.class';
|
|
|
|
@ApiTags('User')
|
|
@Controller('/user')
|
|
export class UsersController {
|
|
constructor(
|
|
private _subscriptionService: SubscriptionService,
|
|
private _stripeService: StripeService,
|
|
private _authService: AuthService,
|
|
private _orgService: OrganizationService,
|
|
private _userService: UsersService,
|
|
private _trackService: TrackService
|
|
) {}
|
|
@Get('/self')
|
|
async getSelf(
|
|
@GetUserFromRequest() user: User,
|
|
@GetOrgFromRequest() organization: Organization,
|
|
@Req() req: Request
|
|
) {
|
|
if (!organization) {
|
|
throw new HttpForbiddenException();
|
|
}
|
|
|
|
const impersonate = req.cookies.impersonate || req.headers.impersonate;
|
|
// @ts-ignore
|
|
return {
|
|
...user,
|
|
orgId: organization.id,
|
|
// @ts-ignore
|
|
totalChannels: !process.env.STRIPE_PUBLISHABLE_KEY ? 10000 : organization?.subscription?.totalChannels || pricing.FREE.channel,
|
|
// @ts-ignore
|
|
tier: organization?.subscription?.subscriptionTier || (!process.env.STRIPE_PUBLISHABLE_KEY ? 'ULTIMATE' : 'FREE'),
|
|
// @ts-ignore
|
|
role: organization?.users[0]?.role,
|
|
// @ts-ignore
|
|
isLifetime: !!organization?.subscription?.isLifetime,
|
|
admin: !!user.isSuperAdmin,
|
|
impersonate: !!impersonate,
|
|
isTrailing: !process.env.STRIPE_PUBLISHABLE_KEY ? false : organization?.isTrailing,
|
|
allowTrial: organization?.allowTrial,
|
|
// @ts-ignore
|
|
publicApi: organization?.users[0]?.role === 'SUPERADMIN' || organization?.users[0]?.role === 'ADMIN' ? organization?.apiKey : '',
|
|
};
|
|
}
|
|
|
|
@Get('/personal')
|
|
async getPersonalInformation(@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: getCookieUrlFromDomain(process.env.FRONTEND_URL!),
|
|
...(!process.env.NOT_SECURED
|
|
? {
|
|
secure: true,
|
|
httpOnly: true,
|
|
sameSite: 'none',
|
|
}
|
|
: {}),
|
|
expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),
|
|
});
|
|
|
|
if (process.env.NOT_SECURED) {
|
|
response.header('impersonate', id);
|
|
}
|
|
}
|
|
|
|
@Post('/personal')
|
|
async changePersonal(
|
|
@GetUserFromRequest() user: User,
|
|
@Body() body: UserDetailDto
|
|
) {
|
|
return this._userService.changePersonal(user.id, body);
|
|
}
|
|
|
|
@Get('/email-notifications')
|
|
async getEmailNotifications(@GetUserFromRequest() user: User) {
|
|
return this._userService.getEmailNotifications(user.id);
|
|
}
|
|
|
|
@Post('/email-notifications')
|
|
async updateEmailNotifications(
|
|
@GetUserFromRequest() user: User,
|
|
@Body() body: EmailNotificationsDto
|
|
) {
|
|
return this._userService.updateEmailNotifications(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: getCookieUrlFromDomain(process.env.FRONTEND_URL!),
|
|
...(!process.env.NOT_SECURED
|
|
? {
|
|
secure: true,
|
|
httpOnly: true,
|
|
sameSite: 'none',
|
|
}
|
|
: {}),
|
|
expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),
|
|
});
|
|
|
|
if (process.env.NOT_SECURED) {
|
|
response.header('showorg', id);
|
|
}
|
|
|
|
response.status(200).send();
|
|
}
|
|
|
|
@Post('/logout')
|
|
logout(@Res({ passthrough: true }) response: Response) {
|
|
response.header('logout', 'true');
|
|
response.cookie('auth', '', {
|
|
domain: getCookieUrlFromDomain(process.env.FRONTEND_URL!),
|
|
...(!process.env.NOT_SECURED
|
|
? {
|
|
secure: true,
|
|
httpOnly: true,
|
|
sameSite: 'none',
|
|
}
|
|
: {}),
|
|
maxAge: -1,
|
|
expires: new Date(0),
|
|
});
|
|
|
|
response.cookie('showorg', '', {
|
|
domain: getCookieUrlFromDomain(process.env.FRONTEND_URL!),
|
|
...(!process.env.NOT_SECURED
|
|
? {
|
|
secure: true,
|
|
httpOnly: true,
|
|
sameSite: 'none',
|
|
}
|
|
: {}),
|
|
maxAge: -1,
|
|
expires: new Date(0),
|
|
});
|
|
|
|
response.cookie('impersonate', '', {
|
|
domain: getCookieUrlFromDomain(process.env.FRONTEND_URL!),
|
|
...(!process.env.NOT_SECURED
|
|
? {
|
|
secure: true,
|
|
httpOnly: true,
|
|
sameSite: 'none',
|
|
}
|
|
: {}),
|
|
maxAge: -1,
|
|
expires: new Date(0),
|
|
});
|
|
|
|
response.status(200).send();
|
|
}
|
|
|
|
@Post('/t')
|
|
async trackEvent(
|
|
@Res({ passthrough: true }) res: Response,
|
|
@Req() req: Request,
|
|
@GetUserFromRequest() user: User,
|
|
@RealIP() ip: string,
|
|
@UserAgent() userAgent: string,
|
|
@Body()
|
|
body: { tt: TrackEnum; fbclid: string; additional: Record<string, any> }
|
|
) {
|
|
const uniqueId = req?.cookies?.track || makeId(10);
|
|
const fbclid = req?.cookies?.fbclid || body.fbclid;
|
|
await this._trackService.track(
|
|
uniqueId,
|
|
ip,
|
|
userAgent,
|
|
body.tt,
|
|
body.additional,
|
|
fbclid,
|
|
user
|
|
);
|
|
if (!req.cookies.track) {
|
|
res.cookie('track', uniqueId, {
|
|
domain: getCookieUrlFromDomain(process.env.FRONTEND_URL!),
|
|
...(!process.env.NOT_SECURED
|
|
? {
|
|
secure: true,
|
|
httpOnly: true,
|
|
sameSite: 'none',
|
|
}
|
|
: {}),
|
|
expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),
|
|
});
|
|
}
|
|
|
|
res.status(200).json({
|
|
track: uniqueId,
|
|
});
|
|
}
|
|
}
|