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:
+5
-5
@@ -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}`)
|
||||
|
||||
+11
-5
@@ -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);
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user