feat: distinguish managed platform users (#14207)

* feat: add isPlatformManaged property to user

* do not allow deleting non managed users

* refactor: rename managed user create and update inputs

* refactor response code

* feat: add isPlatformManaged when creating managed user

* fix TS
This commit is contained in:
Lauris Skraucis
2024-03-25 18:48:51 +01:00
committed by GitHub
parent bec1453148
commit ef498c6ed6
12 changed files with 52 additions and 27 deletions
@@ -7,8 +7,8 @@ import {
CreateUserResponse,
UserReturned,
} from "@/modules/oauth-clients/controllers/oauth-client-users/oauth-client-users.controller";
import { CreateUserInput } from "@/modules/users/inputs/create-user.input";
import { UpdateUserInput } from "@/modules/users/inputs/update-user.input";
import { CreateManagedPlatformUserInput } from "@/modules/users/inputs/create-managed-platform-user.input";
import { UpdateManagedPlatformUserInput } from "@/modules/users/inputs/update-managed-platform-user.input";
import { UsersModule } from "@/modules/users/users.module";
import { INestApplication } from "@nestjs/common";
import { NestExpressApplication } from "@nestjs/platform-express";
@@ -117,7 +117,7 @@ describe("OAuth Client Users Endpoints", () => {
});
it(`should fail /POST with incorrect timeZone`, async () => {
const requestBody: CreateUserInput = {
const requestBody: CreateManagedPlatformUserInput = {
email: "oauth-client-user@gmail.com",
timeZone: "incorrect-time-zone",
};
@@ -130,7 +130,7 @@ describe("OAuth Client Users Endpoints", () => {
});
it(`/POST`, async () => {
const requestBody: CreateUserInput = {
const requestBody: CreateManagedPlatformUserInput = {
email: "oauth-client-user@gmail.com",
};
@@ -195,7 +195,7 @@ describe("OAuth Client Users Endpoints", () => {
it(`/PUT/:id`, async () => {
const userUpdatedEmail = "pineapple-pizza@gmail.com";
const body: UpdateUserInput = { email: userUpdatedEmail };
const body: UpdateManagedPlatformUserInput = { email: userUpdatedEmail };
const response = await request(app.getHttpServer())
.patch(`/api/v2/oauth-clients/${oAuthClient.id}/users/${postResponseData.user.id}`)
@@ -3,8 +3,8 @@ import { AccessTokenGuard } from "@/modules/auth/guards/access-token/access-toke
import { OAuthClientCredentialsGuard } from "@/modules/oauth-clients/guards/oauth-client-credentials/oauth-client-credentials.guard";
import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repository";
import { OAuthClientUsersService } from "@/modules/oauth-clients/services/oauth-clients-users.service";
import { CreateUserInput } from "@/modules/users/inputs/create-user.input";
import { UpdateUserInput } from "@/modules/users/inputs/update-user.input";
import { CreateManagedPlatformUserInput } from "@/modules/users/inputs/create-managed-platform-user.input";
import { UpdateManagedPlatformUserInput } from "@/modules/users/inputs/update-managed-platform-user.input";
import { UsersRepository } from "@/modules/users/users.repository";
import {
Body,
@@ -43,7 +43,7 @@ export class OAuthClientUsersController {
@UseGuards(OAuthClientCredentialsGuard)
async createUser(
@Param("clientId") oAuthClientId: string,
@Body() body: CreateUserInput
@Body() body: CreateManagedPlatformUserInput
): Promise<ApiResponse<CreateUserResponse>> {
this.logger.log(
`Creating user with data: ${JSON.stringify(body, null, 2)} for OAuth Client with ID ${oAuthClientId}`
@@ -55,9 +55,11 @@ export class OAuthClientUsersController {
}
const client = await this.oauthRepository.getOAuthClient(oAuthClientId);
const isPlatformManaged = true;
const { user, tokens } = await this.oAuthClientUsersService.createOauthClientUser(
oAuthClientId,
body,
isPlatformManaged,
client?.organizationId
);
@@ -113,7 +115,7 @@ export class OAuthClientUsersController {
@Param("clientId") _: string,
@GetUser("id") accessTokenUserId: number,
@Param("userId") userId: number,
@Body() body: UpdateUserInput
@Body() body: UpdateManagedPlatformUserInput
): Promise<ApiResponse<UserReturned>> {
if (accessTokenUserId !== userId) {
throw new BadRequestException("userId parameter does not match access token");
@@ -152,7 +154,11 @@ export class OAuthClientUsersController {
const existingUser = await this.userRepository.findById(userId);
if (!existingUser) {
throw new NotFoundException(`User with ${userId} does not exist`);
throw new NotFoundException(`User with ID=${userId} does not exist`);
}
if (!existingUser.isPlatformManaged) {
throw new BadRequestException(`Can't delete non managed user with ID=${userId}`);
}
const user = await this.userRepository.delete(userId);
@@ -1,6 +1,6 @@
import { EventTypesService } from "@/ee/event-types/services/event-types.service";
import { TokensRepository } from "@/modules/tokens/tokens.repository";
import { CreateUserInput } from "@/modules/users/inputs/create-user.input";
import { CreateManagedPlatformUserInput } from "@/modules/users/inputs/create-managed-platform-user.input";
import { UsersRepository } from "@/modules/users/users.repository";
import { Injectable } from "@nestjs/common";
import { User } from "@prisma/client";
@@ -16,11 +16,16 @@ export class OAuthClientUsersService {
private readonly eventTypesService: EventTypesService
) {}
async createOauthClientUser(oAuthClientId: string, body: CreateUserInput, organizationId?: number) {
async createOauthClientUser(
oAuthClientId: string,
body: CreateManagedPlatformUserInput,
isPlatformManaged: boolean,
organizationId?: number
) {
let user: User;
if (!organizationId) {
const username = generateShortHash(body.email, oAuthClientId);
user = await this.userRepository.create(body, username, oAuthClientId);
user = await this.userRepository.create(body, username, oAuthClientId, isPlatformManaged);
} else {
const [_, emailDomain] = body.email.split("@");
user = (
@@ -41,6 +46,7 @@ export class OAuthClientUsersService {
autoAccept: true,
},
},
isPlatformManaged,
})
)[0];
await this.userRepository.addToOAuthClient(user.id, oAuthClientId);
@@ -2,7 +2,7 @@ import { IsTimeFormat } from "@/modules/users/inputs/validators/is-time-format";
import { IsWeekStart } from "@/modules/users/inputs/validators/is-week-start";
import { IsNumber, IsOptional, IsTimeZone, IsString, Validate } from "class-validator";
export class CreateUserInput {
export class CreateManagedPlatformUserInput {
@IsString()
email!: string;
@@ -2,7 +2,7 @@ import { IsTimeFormat } from "@/modules/users/inputs/validators/is-time-format";
import { IsWeekStart } from "@/modules/users/inputs/validators/is-week-start";
import { IsNumber, IsOptional, IsString, IsTimeZone, Validate } from "class-validator";
export class UpdateUserInput {
export class UpdateManagedPlatformUserInput {
@IsString()
@IsOptional()
email?: string;
@@ -1,7 +1,7 @@
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
import { CreateUserInput } from "@/modules/users/inputs/create-user.input";
import { UpdateUserInput } from "@/modules/users/inputs/update-user.input";
import { CreateManagedPlatformUserInput } from "@/modules/users/inputs/create-managed-platform-user.input";
import { UpdateManagedPlatformUserInput } from "@/modules/users/inputs/update-managed-platform-user.input";
import { Injectable } from "@nestjs/common";
import type { Profile, User } from "@prisma/client";
@@ -13,7 +13,12 @@ export type UserWithProfile = User & {
export class UsersRepository {
constructor(private readonly dbRead: PrismaReadService, private readonly dbWrite: PrismaWriteService) {}
async create(user: CreateUserInput, username: string, oAuthClientId: string) {
async create(
user: CreateManagedPlatformUserInput,
username: string,
oAuthClientId: string,
isPlatformManaged: boolean
) {
this.formatInput(user);
return this.dbRead.prisma.user.create({
@@ -23,6 +28,7 @@ export class UsersRepository {
platformOAuthClients: {
connect: { id: oAuthClientId },
},
isPlatformManaged,
},
});
}
@@ -77,7 +83,7 @@ export class UsersRepository {
});
}
async update(userId: number, updateData: UpdateUserInput) {
async update(userId: number, updateData: UpdateManagedPlatformUserInput) {
this.formatInput(updateData);
return this.dbWrite.prisma.user.update({
@@ -92,7 +98,7 @@ export class UsersRepository {
});
}
formatInput(userInput: CreateUserInput | UpdateUserInput) {
formatInput(userInput: CreateManagedPlatformUserInput | UpdateManagedPlatformUserInput) {
if (userInput.weekStart) {
userInput.weekStart = capitalize(userInput.weekStart);
}