feat: Organization services
This commit is contained in:
@@ -24,7 +24,12 @@ export class HttpExceptionFilter implements ExceptionFilter<HttpException> {
|
||||
});
|
||||
}
|
||||
|
||||
if (status === 404) {
|
||||
exception.message = `${exception.message} not found`;
|
||||
}
|
||||
|
||||
response.status(status).json({
|
||||
success: false,
|
||||
message: exception.message,
|
||||
statusCode: status,
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from '@nestjs/common';
|
||||
import { DataResponse, MessageResponse } from 'common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class ResponseInterceptor<T> implements NestInterceptor<T, any> {
|
||||
|
||||
26
common/validators/at-least-one-field.ts
Normal file
26
common/validators/at-least-one-field.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import {
|
||||
registerDecorator,
|
||||
ValidationArguments,
|
||||
ValidationOptions,
|
||||
} from 'class-validator';
|
||||
|
||||
export function AtLeastOneField(validationOptions?: ValidationOptions) {
|
||||
return function (constructor: Function) {
|
||||
registerDecorator({
|
||||
name: 'atLeastOneField',
|
||||
target: constructor,
|
||||
propertyName: undefined as any, // important for class-level
|
||||
options: validationOptions,
|
||||
validator: {
|
||||
validate(_: any, args: ValidationArguments) {
|
||||
const object = args.object as Record<string, any>;
|
||||
|
||||
return Object.values(object).some((value) => value !== undefined);
|
||||
},
|
||||
defaultMessage() {
|
||||
return 'At least one field must be provided';
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
1
common/validators/index.ts
Normal file
1
common/validators/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './at-least-one-field';
|
||||
6
common/validators/query-uuid.dto.ts
Normal file
6
common/validators/query-uuid.dto.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { IsUUID } from 'class-validator';
|
||||
|
||||
export class UUIDQueryDTO {
|
||||
@IsUUID()
|
||||
id: string;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { AsyncLocalStorage } from 'async_hooks';
|
||||
import { RequestContext } from './request-context.type';
|
||||
|
||||
@@ -31,7 +31,9 @@ export class RequestContextService {
|
||||
|
||||
// Helpers
|
||||
get user() {
|
||||
return this.get().user;
|
||||
const user = this.get().user;
|
||||
if (!user) throw new UnauthorizedException();
|
||||
return user;
|
||||
}
|
||||
|
||||
get tx() {
|
||||
|
||||
@@ -36,6 +36,13 @@ export type EnumORGANIZATION_JOIN_REQUESTFilter<$PrismaModel = never> = {
|
||||
not?: Prisma.NestedEnumORGANIZATION_JOIN_REQUESTFilter<$PrismaModel> | $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
}
|
||||
|
||||
export type EnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel = never> = {
|
||||
equals?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE | Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
|
||||
in?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
|
||||
notIn?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel> | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
}
|
||||
|
||||
export type DateTimeFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||
@@ -95,6 +102,16 @@ export type EnumORGANIZATION_JOIN_REQUESTWithAggregatesFilter<$PrismaModel = nev
|
||||
_max?: Prisma.NestedEnumORGANIZATION_JOIN_REQUESTFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type EnumORGANIZATION_JOIN_REQUEST_TYPEWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE | Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
|
||||
in?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
|
||||
notIn?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEWithAggregatesFilter<$PrismaModel> | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||
_min?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel>
|
||||
_max?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type DateTimeWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||
@@ -220,6 +237,13 @@ export type NestedEnumORGANIZATION_JOIN_REQUESTFilter<$PrismaModel = never> = {
|
||||
not?: Prisma.NestedEnumORGANIZATION_JOIN_REQUESTFilter<$PrismaModel> | $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
}
|
||||
|
||||
export type NestedEnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel = never> = {
|
||||
equals?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE | Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
|
||||
in?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
|
||||
notIn?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel> | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
}
|
||||
|
||||
export type NestedDateTimeFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||
@@ -283,6 +307,16 @@ export type NestedEnumORGANIZATION_JOIN_REQUESTWithAggregatesFilter<$PrismaModel
|
||||
_max?: Prisma.NestedEnumORGANIZATION_JOIN_REQUESTFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type NestedEnumORGANIZATION_JOIN_REQUEST_TYPEWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE | Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
|
||||
in?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
|
||||
notIn?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEWithAggregatesFilter<$PrismaModel> | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||
_min?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel>
|
||||
_max?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
|
||||
|
||||
@@ -18,9 +18,18 @@ export const ORGANIZATION_JOIN_REQUEST = {
|
||||
export type ORGANIZATION_JOIN_REQUEST = (typeof ORGANIZATION_JOIN_REQUEST)[keyof typeof ORGANIZATION_JOIN_REQUEST]
|
||||
|
||||
|
||||
export const ORGANIZATION_JOIN_REQUEST_TYPE = {
|
||||
INVITED: 'INVITED',
|
||||
REQUESTED: 'REQUESTED'
|
||||
} as const
|
||||
|
||||
export type ORGANIZATION_JOIN_REQUEST_TYPE = (typeof ORGANIZATION_JOIN_REQUEST_TYPE)[keyof typeof ORGANIZATION_JOIN_REQUEST_TYPE]
|
||||
|
||||
|
||||
export const ORG_ROLE = {
|
||||
owner: 'owner',
|
||||
admin: 'admin',
|
||||
user: 'user'
|
||||
member: 'member'
|
||||
} as const
|
||||
|
||||
export type ORG_ROLE = (typeof ORG_ROLE)[keyof typeof ORG_ROLE]
|
||||
@@ -28,7 +37,7 @@ export type ORG_ROLE = (typeof ORG_ROLE)[keyof typeof ORG_ROLE]
|
||||
|
||||
export const USER_ROLE = {
|
||||
superadmin: 'superadmin',
|
||||
ordinary: 'ordinary'
|
||||
user: 'user'
|
||||
} as const
|
||||
|
||||
export type USER_ROLE = (typeof USER_ROLE)[keyof typeof USER_ROLE]
|
||||
|
||||
@@ -20,7 +20,7 @@ const config: runtime.GetPrismaClientConfig = {
|
||||
"clientVersion": "7.3.0",
|
||||
"engineVersion": "9d6ad21cbbceab97458517b147a6a09ff43aa735",
|
||||
"activeProvider": "postgresql",
|
||||
"inlineSchema": "model OrganizationJoinRequest {\n userId String\n orgId String\n status ORGANIZATION_JOIN_REQUEST @default(PENDING)\n requestedOn DateTime @default(now())\n rejectReason String?\n\n @@unique([userId, orgId])\n @@map(\"organization_join_request\")\n}\n\nenum ORGANIZATION_JOIN_REQUEST {\n PENDING\n ACCEPTED\n REJECTED\n}\n\nmodel OrganizationUserJoinTable {\n userId String\n orgId String\n role ORG_ROLE @default(user)\n joinedDate DateTime @default(now())\n\n @@unique([userId, orgId])\n @@map(\"organization_user_join\")\n}\n\nenum ORG_ROLE {\n admin\n user\n}\n\nmodel Organization {\n id String @id @default(uuid())\n name String\n description String?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@map(\"organization\")\n}\n\n// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?\n// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel User {\n id String @id @default(uuid())\n firstName String\n middleName String?\n lastName String\n email String @unique\n password String\n role USER_ROLE @default(ordinary)\n isVerified Boolean? @default(false) // TODO: Email using queue\n refreshToken String?\n profilePicture String?\n isDeleted Boolean? @default(false)\n deletedAt DateTime?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@map(\"user\")\n}\n\nenum USER_ROLE {\n superadmin\n ordinary\n}\n",
|
||||
"inlineSchema": "model OrganizationJoinRequest {\n userId String\n orgId String\n status ORGANIZATION_JOIN_REQUEST @default(PENDING)\n requestType ORGANIZATION_JOIN_REQUEST_TYPE\n requestedOn DateTime @default(now())\n rejectReason String?\n\n @@unique([userId, orgId])\n @@map(\"organization_join_request\")\n}\n\nenum ORGANIZATION_JOIN_REQUEST {\n PENDING\n ACCEPTED\n REJECTED\n}\n\nenum ORGANIZATION_JOIN_REQUEST_TYPE {\n INVITED\n REQUESTED\n}\n\nmodel OrganizationUserJoinTable {\n userId String\n orgId String\n role ORG_ROLE @default(member)\n joinedDate DateTime @default(now())\n\n @@unique([userId, orgId])\n @@map(\"organization_user_join\")\n}\n\nenum ORG_ROLE {\n owner\n admin\n member\n}\n\nmodel Organization {\n id String @id @default(uuid())\n name String\n description String?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@map(\"organization\")\n}\n\n// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?\n// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel User {\n id String @id @default(uuid())\n firstName String\n middleName String?\n lastName String\n email String @unique\n password String\n role USER_ROLE @default(user)\n isVerified Boolean? @default(false) // TODO: Email using queue\n refreshToken String?\n profilePicture String?\n isDeleted Boolean? @default(false)\n deletedAt DateTime?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@map(\"user\")\n}\n\nenum USER_ROLE {\n superadmin\n user\n}\n",
|
||||
"runtimeDataModel": {
|
||||
"models": {},
|
||||
"enums": {},
|
||||
@@ -28,7 +28,7 @@ const config: runtime.GetPrismaClientConfig = {
|
||||
}
|
||||
}
|
||||
|
||||
config.runtimeDataModel = JSON.parse("{\"models\":{\"OrganizationJoinRequest\":{\"fields\":[{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"orgId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"ORGANIZATION_JOIN_REQUEST\"},{\"name\":\"requestedOn\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"rejectReason\",\"kind\":\"scalar\",\"type\":\"String\"}],\"dbName\":\"organization_join_request\"},\"OrganizationUserJoinTable\":{\"fields\":[{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"orgId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"role\",\"kind\":\"enum\",\"type\":\"ORG_ROLE\"},{\"name\":\"joinedDate\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":\"organization_user_join\"},\"Organization\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"description\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":\"organization\"},\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"firstName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"middleName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"lastName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"password\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"role\",\"kind\":\"enum\",\"type\":\"USER_ROLE\"},{\"name\":\"isVerified\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"refreshToken\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"profilePicture\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"isDeleted\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"deletedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":\"user\"}},\"enums\":{},\"types\":{}}")
|
||||
config.runtimeDataModel = JSON.parse("{\"models\":{\"OrganizationJoinRequest\":{\"fields\":[{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"orgId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"ORGANIZATION_JOIN_REQUEST\"},{\"name\":\"requestType\",\"kind\":\"enum\",\"type\":\"ORGANIZATION_JOIN_REQUEST_TYPE\"},{\"name\":\"requestedOn\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"rejectReason\",\"kind\":\"scalar\",\"type\":\"String\"}],\"dbName\":\"organization_join_request\"},\"OrganizationUserJoinTable\":{\"fields\":[{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"orgId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"role\",\"kind\":\"enum\",\"type\":\"ORG_ROLE\"},{\"name\":\"joinedDate\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":\"organization_user_join\"},\"Organization\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"description\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":\"organization\"},\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"firstName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"middleName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"lastName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"password\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"role\",\"kind\":\"enum\",\"type\":\"USER_ROLE\"},{\"name\":\"isVerified\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"refreshToken\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"profilePicture\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"isDeleted\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"deletedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":\"user\"}},\"enums\":{},\"types\":{}}")
|
||||
|
||||
async function decodeBase64AsWasm(wasmBase64: string): Promise<WebAssembly.Module> {
|
||||
const { Buffer } = await import('node:buffer')
|
||||
|
||||
@@ -746,6 +746,7 @@ export const OrganizationJoinRequestScalarFieldEnum = {
|
||||
userId: 'userId',
|
||||
orgId: 'orgId',
|
||||
status: 'status',
|
||||
requestType: 'requestType',
|
||||
requestedOn: 'requestedOn',
|
||||
rejectReason: 'rejectReason'
|
||||
} as const
|
||||
@@ -852,6 +853,20 @@ export type ListEnumORGANIZATION_JOIN_REQUESTFieldRefInput<$PrismaModel> = Field
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'ORGANIZATION_JOIN_REQUEST_TYPE'
|
||||
*/
|
||||
export type EnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ORGANIZATION_JOIN_REQUEST_TYPE'>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'ORGANIZATION_JOIN_REQUEST_TYPE[]'
|
||||
*/
|
||||
export type ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ORGANIZATION_JOIN_REQUEST_TYPE[]'>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'DateTime'
|
||||
*/
|
||||
|
||||
@@ -77,6 +77,7 @@ export const OrganizationJoinRequestScalarFieldEnum = {
|
||||
userId: 'userId',
|
||||
orgId: 'orgId',
|
||||
status: 'status',
|
||||
requestType: 'requestType',
|
||||
requestedOn: 'requestedOn',
|
||||
rejectReason: 'rejectReason'
|
||||
} as const
|
||||
|
||||
@@ -28,6 +28,7 @@ export type OrganizationJoinRequestMinAggregateOutputType = {
|
||||
userId: string | null
|
||||
orgId: string | null
|
||||
status: $Enums.ORGANIZATION_JOIN_REQUEST | null
|
||||
requestType: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE | null
|
||||
requestedOn: Date | null
|
||||
rejectReason: string | null
|
||||
}
|
||||
@@ -36,6 +37,7 @@ export type OrganizationJoinRequestMaxAggregateOutputType = {
|
||||
userId: string | null
|
||||
orgId: string | null
|
||||
status: $Enums.ORGANIZATION_JOIN_REQUEST | null
|
||||
requestType: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE | null
|
||||
requestedOn: Date | null
|
||||
rejectReason: string | null
|
||||
}
|
||||
@@ -44,6 +46,7 @@ export type OrganizationJoinRequestCountAggregateOutputType = {
|
||||
userId: number
|
||||
orgId: number
|
||||
status: number
|
||||
requestType: number
|
||||
requestedOn: number
|
||||
rejectReason: number
|
||||
_all: number
|
||||
@@ -54,6 +57,7 @@ export type OrganizationJoinRequestMinAggregateInputType = {
|
||||
userId?: true
|
||||
orgId?: true
|
||||
status?: true
|
||||
requestType?: true
|
||||
requestedOn?: true
|
||||
rejectReason?: true
|
||||
}
|
||||
@@ -62,6 +66,7 @@ export type OrganizationJoinRequestMaxAggregateInputType = {
|
||||
userId?: true
|
||||
orgId?: true
|
||||
status?: true
|
||||
requestType?: true
|
||||
requestedOn?: true
|
||||
rejectReason?: true
|
||||
}
|
||||
@@ -70,6 +75,7 @@ export type OrganizationJoinRequestCountAggregateInputType = {
|
||||
userId?: true
|
||||
orgId?: true
|
||||
status?: true
|
||||
requestType?: true
|
||||
requestedOn?: true
|
||||
rejectReason?: true
|
||||
_all?: true
|
||||
@@ -151,6 +157,7 @@ export type OrganizationJoinRequestGroupByOutputType = {
|
||||
userId: string
|
||||
orgId: string
|
||||
status: $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
requestType: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
requestedOn: Date
|
||||
rejectReason: string | null
|
||||
_count: OrganizationJoinRequestCountAggregateOutputType | null
|
||||
@@ -180,6 +187,7 @@ export type OrganizationJoinRequestWhereInput = {
|
||||
userId?: Prisma.StringFilter<"OrganizationJoinRequest"> | string
|
||||
orgId?: Prisma.StringFilter<"OrganizationJoinRequest"> | string
|
||||
status?: Prisma.EnumORGANIZATION_JOIN_REQUESTFilter<"OrganizationJoinRequest"> | $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
requestType?: Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEFilter<"OrganizationJoinRequest"> | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
requestedOn?: Prisma.DateTimeFilter<"OrganizationJoinRequest"> | Date | string
|
||||
rejectReason?: Prisma.StringNullableFilter<"OrganizationJoinRequest"> | string | null
|
||||
}
|
||||
@@ -188,6 +196,7 @@ export type OrganizationJoinRequestOrderByWithRelationInput = {
|
||||
userId?: Prisma.SortOrder
|
||||
orgId?: Prisma.SortOrder
|
||||
status?: Prisma.SortOrder
|
||||
requestType?: Prisma.SortOrder
|
||||
requestedOn?: Prisma.SortOrder
|
||||
rejectReason?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||
}
|
||||
@@ -200,6 +209,7 @@ export type OrganizationJoinRequestWhereUniqueInput = Prisma.AtLeast<{
|
||||
userId?: Prisma.StringFilter<"OrganizationJoinRequest"> | string
|
||||
orgId?: Prisma.StringFilter<"OrganizationJoinRequest"> | string
|
||||
status?: Prisma.EnumORGANIZATION_JOIN_REQUESTFilter<"OrganizationJoinRequest"> | $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
requestType?: Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEFilter<"OrganizationJoinRequest"> | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
requestedOn?: Prisma.DateTimeFilter<"OrganizationJoinRequest"> | Date | string
|
||||
rejectReason?: Prisma.StringNullableFilter<"OrganizationJoinRequest"> | string | null
|
||||
}, "userId_orgId">
|
||||
@@ -208,6 +218,7 @@ export type OrganizationJoinRequestOrderByWithAggregationInput = {
|
||||
userId?: Prisma.SortOrder
|
||||
orgId?: Prisma.SortOrder
|
||||
status?: Prisma.SortOrder
|
||||
requestType?: Prisma.SortOrder
|
||||
requestedOn?: Prisma.SortOrder
|
||||
rejectReason?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||
_count?: Prisma.OrganizationJoinRequestCountOrderByAggregateInput
|
||||
@@ -222,6 +233,7 @@ export type OrganizationJoinRequestScalarWhereWithAggregatesInput = {
|
||||
userId?: Prisma.StringWithAggregatesFilter<"OrganizationJoinRequest"> | string
|
||||
orgId?: Prisma.StringWithAggregatesFilter<"OrganizationJoinRequest"> | string
|
||||
status?: Prisma.EnumORGANIZATION_JOIN_REQUESTWithAggregatesFilter<"OrganizationJoinRequest"> | $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
requestType?: Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEWithAggregatesFilter<"OrganizationJoinRequest"> | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
requestedOn?: Prisma.DateTimeWithAggregatesFilter<"OrganizationJoinRequest"> | Date | string
|
||||
rejectReason?: Prisma.StringNullableWithAggregatesFilter<"OrganizationJoinRequest"> | string | null
|
||||
}
|
||||
@@ -230,6 +242,7 @@ export type OrganizationJoinRequestCreateInput = {
|
||||
userId: string
|
||||
orgId: string
|
||||
status?: $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
requestType: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
requestedOn?: Date | string
|
||||
rejectReason?: string | null
|
||||
}
|
||||
@@ -238,6 +251,7 @@ export type OrganizationJoinRequestUncheckedCreateInput = {
|
||||
userId: string
|
||||
orgId: string
|
||||
status?: $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
requestType: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
requestedOn?: Date | string
|
||||
rejectReason?: string | null
|
||||
}
|
||||
@@ -246,6 +260,7 @@ export type OrganizationJoinRequestUpdateInput = {
|
||||
userId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
orgId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
status?: Prisma.EnumORGANIZATION_JOIN_REQUESTFieldUpdateOperationsInput | $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
requestType?: Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEFieldUpdateOperationsInput | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
requestedOn?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||
rejectReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||
}
|
||||
@@ -254,6 +269,7 @@ export type OrganizationJoinRequestUncheckedUpdateInput = {
|
||||
userId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
orgId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
status?: Prisma.EnumORGANIZATION_JOIN_REQUESTFieldUpdateOperationsInput | $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
requestType?: Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEFieldUpdateOperationsInput | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
requestedOn?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||
rejectReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||
}
|
||||
@@ -262,6 +278,7 @@ export type OrganizationJoinRequestCreateManyInput = {
|
||||
userId: string
|
||||
orgId: string
|
||||
status?: $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
requestType: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
requestedOn?: Date | string
|
||||
rejectReason?: string | null
|
||||
}
|
||||
@@ -270,6 +287,7 @@ export type OrganizationJoinRequestUpdateManyMutationInput = {
|
||||
userId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
orgId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
status?: Prisma.EnumORGANIZATION_JOIN_REQUESTFieldUpdateOperationsInput | $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
requestType?: Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEFieldUpdateOperationsInput | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
requestedOn?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||
rejectReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||
}
|
||||
@@ -278,6 +296,7 @@ export type OrganizationJoinRequestUncheckedUpdateManyInput = {
|
||||
userId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
orgId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
status?: Prisma.EnumORGANIZATION_JOIN_REQUESTFieldUpdateOperationsInput | $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
requestType?: Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEFieldUpdateOperationsInput | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
requestedOn?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||
rejectReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||
}
|
||||
@@ -291,6 +310,7 @@ export type OrganizationJoinRequestCountOrderByAggregateInput = {
|
||||
userId?: Prisma.SortOrder
|
||||
orgId?: Prisma.SortOrder
|
||||
status?: Prisma.SortOrder
|
||||
requestType?: Prisma.SortOrder
|
||||
requestedOn?: Prisma.SortOrder
|
||||
rejectReason?: Prisma.SortOrder
|
||||
}
|
||||
@@ -299,6 +319,7 @@ export type OrganizationJoinRequestMaxOrderByAggregateInput = {
|
||||
userId?: Prisma.SortOrder
|
||||
orgId?: Prisma.SortOrder
|
||||
status?: Prisma.SortOrder
|
||||
requestType?: Prisma.SortOrder
|
||||
requestedOn?: Prisma.SortOrder
|
||||
rejectReason?: Prisma.SortOrder
|
||||
}
|
||||
@@ -307,6 +328,7 @@ export type OrganizationJoinRequestMinOrderByAggregateInput = {
|
||||
userId?: Prisma.SortOrder
|
||||
orgId?: Prisma.SortOrder
|
||||
status?: Prisma.SortOrder
|
||||
requestType?: Prisma.SortOrder
|
||||
requestedOn?: Prisma.SortOrder
|
||||
rejectReason?: Prisma.SortOrder
|
||||
}
|
||||
@@ -319,6 +341,10 @@ export type EnumORGANIZATION_JOIN_REQUESTFieldUpdateOperationsInput = {
|
||||
set?: $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
}
|
||||
|
||||
export type EnumORGANIZATION_JOIN_REQUEST_TYPEFieldUpdateOperationsInput = {
|
||||
set?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
}
|
||||
|
||||
export type DateTimeFieldUpdateOperationsInput = {
|
||||
set?: Date | string
|
||||
}
|
||||
@@ -333,6 +359,7 @@ export type OrganizationJoinRequestSelect<ExtArgs extends runtime.Types.Extensio
|
||||
userId?: boolean
|
||||
orgId?: boolean
|
||||
status?: boolean
|
||||
requestType?: boolean
|
||||
requestedOn?: boolean
|
||||
rejectReason?: boolean
|
||||
}, ExtArgs["result"]["organizationJoinRequest"]>
|
||||
@@ -341,6 +368,7 @@ export type OrganizationJoinRequestSelectCreateManyAndReturn<ExtArgs extends run
|
||||
userId?: boolean
|
||||
orgId?: boolean
|
||||
status?: boolean
|
||||
requestType?: boolean
|
||||
requestedOn?: boolean
|
||||
rejectReason?: boolean
|
||||
}, ExtArgs["result"]["organizationJoinRequest"]>
|
||||
@@ -349,6 +377,7 @@ export type OrganizationJoinRequestSelectUpdateManyAndReturn<ExtArgs extends run
|
||||
userId?: boolean
|
||||
orgId?: boolean
|
||||
status?: boolean
|
||||
requestType?: boolean
|
||||
requestedOn?: boolean
|
||||
rejectReason?: boolean
|
||||
}, ExtArgs["result"]["organizationJoinRequest"]>
|
||||
@@ -357,11 +386,12 @@ export type OrganizationJoinRequestSelectScalar = {
|
||||
userId?: boolean
|
||||
orgId?: boolean
|
||||
status?: boolean
|
||||
requestType?: boolean
|
||||
requestedOn?: boolean
|
||||
rejectReason?: boolean
|
||||
}
|
||||
|
||||
export type OrganizationJoinRequestOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"userId" | "orgId" | "status" | "requestedOn" | "rejectReason", ExtArgs["result"]["organizationJoinRequest"]>
|
||||
export type OrganizationJoinRequestOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"userId" | "orgId" | "status" | "requestType" | "requestedOn" | "rejectReason", ExtArgs["result"]["organizationJoinRequest"]>
|
||||
|
||||
export type $OrganizationJoinRequestPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||
name: "OrganizationJoinRequest"
|
||||
@@ -370,6 +400,7 @@ export type $OrganizationJoinRequestPayload<ExtArgs extends runtime.Types.Extens
|
||||
userId: string
|
||||
orgId: string
|
||||
status: $Enums.ORGANIZATION_JOIN_REQUEST
|
||||
requestType: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
requestedOn: Date
|
||||
rejectReason: string | null
|
||||
}, ExtArgs["result"]["organizationJoinRequest"]>
|
||||
@@ -798,6 +829,7 @@ export interface OrganizationJoinRequestFieldRefs {
|
||||
readonly userId: Prisma.FieldRef<"OrganizationJoinRequest", 'String'>
|
||||
readonly orgId: Prisma.FieldRef<"OrganizationJoinRequest", 'String'>
|
||||
readonly status: Prisma.FieldRef<"OrganizationJoinRequest", 'ORGANIZATION_JOIN_REQUEST'>
|
||||
readonly requestType: Prisma.FieldRef<"OrganizationJoinRequest", 'ORGANIZATION_JOIN_REQUEST_TYPE'>
|
||||
readonly requestedOn: Prisma.FieldRef<"OrganizationJoinRequest", 'DateTime'>
|
||||
readonly rejectReason: Prisma.FieldRef<"OrganizationJoinRequest", 'String'>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- The values [user] on the enum `ORG_ROLE` will be removed. If these variants are still used in the database, this will fail.
|
||||
- The values [ordinary] on the enum `USER_ROLE` will be removed. If these variants are still used in the database, this will fail.
|
||||
|
||||
*/
|
||||
|
||||
-- AlterEnum
|
||||
BEGIN;
|
||||
CREATE TYPE "ORG_ROLE_new" AS ENUM ('owner', 'admin', 'member');
|
||||
ALTER TABLE "public"."organization_user_join" ALTER COLUMN "role" DROP DEFAULT;
|
||||
ALTER TABLE "organization_user_join" ALTER COLUMN "role" TYPE "ORG_ROLE_new" USING ("role"::text::"ORG_ROLE_new");
|
||||
ALTER TYPE "ORG_ROLE" RENAME TO "ORG_ROLE_old";
|
||||
ALTER TYPE "ORG_ROLE_new" RENAME TO "ORG_ROLE";
|
||||
DROP TYPE "public"."ORG_ROLE_old";
|
||||
ALTER TABLE "organization_user_join" ALTER COLUMN "role" SET DEFAULT 'member';
|
||||
COMMIT;
|
||||
|
||||
-- AlterEnum
|
||||
BEGIN;
|
||||
CREATE TYPE "USER_ROLE_new" AS ENUM ('superadmin', 'user');
|
||||
ALTER TABLE "public"."user" ALTER COLUMN "role" DROP DEFAULT;
|
||||
ALTER TABLE "user" ALTER COLUMN "role" TYPE "USER_ROLE_new" USING ("role"::text::"USER_ROLE_new");
|
||||
ALTER TYPE "USER_ROLE" RENAME TO "USER_ROLE_old";
|
||||
ALTER TYPE "USER_ROLE_new" RENAME TO "USER_ROLE";
|
||||
DROP TYPE "public"."USER_ROLE_old";
|
||||
ALTER TABLE "user" ALTER COLUMN "role" SET DEFAULT 'user';
|
||||
COMMIT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "organization_user_join" ALTER COLUMN "role" SET DEFAULT 'member';
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "user" ALTER COLUMN "role" SET DEFAULT 'user';
|
||||
1
prisma/migrations/20260221131903_new_enum/migration.sql
Normal file
1
prisma/migrations/20260221131903_new_enum/migration.sql
Normal file
@@ -0,0 +1 @@
|
||||
-- This is an empty migration.
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- Added the required column `requestType` to the `organization_join_request` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ORGANIZATION_JOIN_REQUEST_TYPE" AS ENUM ('INVITED', 'REQUESTED');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "organization_join_request" ADD COLUMN "requestType" "ORGANIZATION_JOIN_REQUEST_TYPE" NOT NULL;
|
||||
@@ -1,8 +1,10 @@
|
||||
model OrganizationJoinRequest {
|
||||
userId String
|
||||
orgId String
|
||||
status ORGANIZATION_JOIN_REQUEST @default(PENDING)
|
||||
requestedOn DateTime @default(now())
|
||||
status ORGANIZATION_JOIN_REQUEST @default(PENDING)
|
||||
requestType ORGANIZATION_JOIN_REQUEST_TYPE
|
||||
requestedOn DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
rejectReason String?
|
||||
|
||||
@@unique([userId, orgId])
|
||||
@@ -14,3 +16,8 @@ enum ORGANIZATION_JOIN_REQUEST {
|
||||
ACCEPTED
|
||||
REJECTED
|
||||
}
|
||||
|
||||
enum ORGANIZATION_JOIN_REQUEST_TYPE {
|
||||
INVITED
|
||||
REQUESTED
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
model OrganizationUserJoinTable {
|
||||
userId String
|
||||
orgId String
|
||||
role ORG_ROLE @default(user)
|
||||
role ORG_ROLE @default(member)
|
||||
joinedDate DateTime @default(now())
|
||||
|
||||
@@unique([userId, orgId])
|
||||
@@ -9,6 +9,7 @@ model OrganizationUserJoinTable {
|
||||
}
|
||||
|
||||
enum ORG_ROLE {
|
||||
owner
|
||||
admin
|
||||
user
|
||||
member
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ model User {
|
||||
lastName String
|
||||
email String @unique
|
||||
password String
|
||||
role USER_ROLE @default(ordinary)
|
||||
role USER_ROLE @default(user)
|
||||
isVerified Boolean? @default(false) // TODO: Email using queue
|
||||
refreshToken String?
|
||||
profilePicture String?
|
||||
@@ -20,5 +20,5 @@ model User {
|
||||
|
||||
enum USER_ROLE {
|
||||
superadmin
|
||||
ordinary
|
||||
user
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';
|
||||
import { ResponseInterceptor } from 'common/interceptors/response.interceptor';
|
||||
import { ExceptionsHandler } from '@nestjs/core/exceptions/exceptions-handler';
|
||||
import { HttpExceptionFilter } from 'common/exceptions/exception-filter';
|
||||
import { OrganizationModule } from './organization/organization.module';
|
||||
import { OrganizationMembershipModule } from './organization-membership/organization-membership.module';
|
||||
import { AuthorizationModule } from './authorization/authorization.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -21,6 +24,9 @@ import { HttpExceptionFilter } from 'common/exceptions/exception-filter';
|
||||
AuthModule,
|
||||
RequestContextModule,
|
||||
PrismaModule,
|
||||
OrganizationModule,
|
||||
OrganizationMembershipModule,
|
||||
AuthorizationModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [
|
||||
|
||||
@@ -15,8 +15,10 @@ import {
|
||||
} from './dto';
|
||||
import { Response } from 'express';
|
||||
import { DataResponse } from 'common/http';
|
||||
import { Public } from './decorators';
|
||||
|
||||
@Controller('auth')
|
||||
@Public()
|
||||
export class AuthController {
|
||||
constructor(private readonly authService: AuthService) {}
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@ import { RequestContextModule } from 'core/als/request-context.module';
|
||||
AuthService,
|
||||
{
|
||||
provide: APP_GUARD,
|
||||
useFactory: () => AuthGuard,
|
||||
inject: [Reflector],
|
||||
useClass: AuthGuard,
|
||||
},
|
||||
],
|
||||
controllers: [AuthController],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
Injectable,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import { RequestContextService } from 'core/als/request-context.service';
|
||||
@@ -10,6 +11,7 @@ import { Request } from 'express';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { PUBLIC_KEY } from 'common/keys';
|
||||
|
||||
@Injectable()
|
||||
export class AuthGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly reflector: Reflector,
|
||||
@@ -30,7 +32,9 @@ export class AuthGuard implements CanActivate {
|
||||
if (!token) throw new UnauthorizedException();
|
||||
|
||||
try {
|
||||
const payload: JwtPayload = await this.jwtService.verifyAsync(token);
|
||||
const payload: JwtPayload = await this.jwtService.verifyAsync(token, {
|
||||
secret: 'demo',
|
||||
});
|
||||
this.requestContext.set('user', payload);
|
||||
|
||||
return true;
|
||||
|
||||
10
src/authorization/authorization.module.ts
Normal file
10
src/authorization/authorization.module.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AuthorizationService } from './authorization.service';
|
||||
import { PrismaModule } from 'src/prisma/prisma.module';
|
||||
|
||||
@Module({
|
||||
providers: [AuthorizationService],
|
||||
imports: [PrismaModule],
|
||||
exports: [AuthorizationService],
|
||||
})
|
||||
export class AuthorizationModule {}
|
||||
18
src/authorization/authorization.service.spec.ts
Normal file
18
src/authorization/authorization.service.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AuthorizationService } from './authorization.service';
|
||||
|
||||
describe('AuthorizationService', () => {
|
||||
let service: AuthorizationService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [AuthorizationService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<AuthorizationService>(AuthorizationService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
71
src/authorization/authorization.service.ts
Normal file
71
src/authorization/authorization.service.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import { USER_ORGANIZATION_OPERATIONS } from './operations';
|
||||
import { ORG_ROLE } from 'prisma/generated/prisma/enums';
|
||||
|
||||
@Injectable()
|
||||
export class AuthorizationService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
// can perform operation
|
||||
async canPerformOperation(
|
||||
userId: string,
|
||||
orgId: string,
|
||||
operation: USER_ORGANIZATION_OPERATIONS,
|
||||
) {
|
||||
switch (operation) {
|
||||
case USER_ORGANIZATION_OPERATIONS.DELETE_ORGANIZATION:
|
||||
return await this.isOwner(userId, orgId);
|
||||
case USER_ORGANIZATION_OPERATIONS.UPDATE_ORGANIZATION:
|
||||
return await this.isOwner(userId, orgId);
|
||||
case USER_ORGANIZATION_OPERATIONS.INVITE_USERS:
|
||||
return await this.canInvite(userId, orgId);
|
||||
}
|
||||
}
|
||||
|
||||
private async isOwner(userId: string, orgId: string) {
|
||||
const isUserPartOfOrganization = await this.isUserPartOfOrganization(
|
||||
userId,
|
||||
orgId,
|
||||
);
|
||||
|
||||
return isUserPartOfOrganization
|
||||
? isUserPartOfOrganization.role === ORG_ROLE.owner
|
||||
: !!isUserPartOfOrganization;
|
||||
}
|
||||
|
||||
private async canInvite(userId: string, orgId: string) {
|
||||
const isUserPartOfOrganization = await this.isUserPartOfOrganization(
|
||||
userId,
|
||||
orgId,
|
||||
);
|
||||
|
||||
return isUserPartOfOrganization
|
||||
? isUserPartOfOrganization.role === ORG_ROLE.admin ||
|
||||
isUserPartOfOrganization.role === ORG_ROLE.owner
|
||||
: !!isUserPartOfOrganization;
|
||||
}
|
||||
|
||||
private async isAdmin(userId: string, orgId: string) {
|
||||
const isUserPartOfOrganization = await this.isUserPartOfOrganization(
|
||||
userId,
|
||||
orgId,
|
||||
);
|
||||
|
||||
return isUserPartOfOrganization
|
||||
? isUserPartOfOrganization.role === ORG_ROLE.admin
|
||||
: !!isUserPartOfOrganization;
|
||||
}
|
||||
|
||||
// HELPER FUNCTION
|
||||
private async isUserPartOfOrganization(userId: string, orgId: string) {
|
||||
return await this.prisma.organizationUserJoinTable.findUnique({
|
||||
where: {
|
||||
userId_orgId: {
|
||||
orgId,
|
||||
userId,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
5
src/authorization/operations.ts
Normal file
5
src/authorization/operations.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export enum USER_ORGANIZATION_OPERATIONS {
|
||||
UPDATE_ORGANIZATION = 'update_organization',
|
||||
DELETE_ORGANIZATION = 'delete_organization',
|
||||
INVITE_USERS = 'invite_users',
|
||||
}
|
||||
1
src/organization-membership/dto/index.ts
Normal file
1
src/organization-membership/dto/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './invite-to-org.dto';
|
||||
16
src/organization-membership/dto/invite-to-org.dto.ts
Normal file
16
src/organization-membership/dto/invite-to-org.dto.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { IsEnum, IsNotEmpty, IsUUID } from 'class-validator';
|
||||
import { ORG_ROLE } from 'prisma/generated/prisma/enums';
|
||||
|
||||
export class InviteUserToOrganizationRequestDTO {
|
||||
@IsUUID()
|
||||
@IsNotEmpty()
|
||||
invitedUserId: string;
|
||||
|
||||
@IsUUID()
|
||||
@IsNotEmpty()
|
||||
orgId: string;
|
||||
|
||||
@IsEnum(ORG_ROLE)
|
||||
@IsNotEmpty()
|
||||
role: ORG_ROLE;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { OrganizationMembershipController } from './organization-membership.controller';
|
||||
|
||||
describe('OrganizationMembershipController', () => {
|
||||
let controller: OrganizationMembershipController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [OrganizationMembershipController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<OrganizationMembershipController>(OrganizationMembershipController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
import { Controller } from '@nestjs/common';
|
||||
|
||||
@Controller('organization-membership')
|
||||
export class OrganizationMembershipController {}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { OrganizationMembershipController } from './organization-membership.controller';
|
||||
import { OrganizationMembershipService } from './organization-membership.service';
|
||||
import { OrganizationModule } from 'src/organization/organization.module';
|
||||
import { UserModule } from 'src/user/user.module';
|
||||
import { PrismaModule } from 'src/prisma/prisma.module';
|
||||
import { AuthorizationModule } from 'src/authorization/authorization.module';
|
||||
|
||||
@Module({
|
||||
controllers: [OrganizationMembershipController],
|
||||
providers: [OrganizationMembershipService],
|
||||
imports: [OrganizationModule, UserModule, PrismaModule, AuthorizationModule],
|
||||
})
|
||||
export class OrganizationMembershipModule {}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { OrganizationMembershipService } from './organization-membership.service';
|
||||
|
||||
describe('OrganizationMembershipService', () => {
|
||||
let service: OrganizationMembershipService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [OrganizationMembershipService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<OrganizationMembershipService>(OrganizationMembershipService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
148
src/organization-membership/organization-membership.service.ts
Normal file
148
src/organization-membership/organization-membership.service.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
ForbiddenException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { OrganizationService } from 'src/organization/organization.service';
|
||||
import { UserService } from 'src/user/user.service';
|
||||
import { InviteUserToOrganizationRequestDTO } from './dto';
|
||||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import {
|
||||
ORGANIZATION_JOIN_REQUEST,
|
||||
ORGANIZATION_JOIN_REQUEST_TYPE,
|
||||
} from 'prisma/generated/prisma/enums';
|
||||
import { AuthorizationService } from 'src/authorization/authorization.service';
|
||||
import { USER_ORGANIZATION_OPERATIONS } from 'src/authorization/operations';
|
||||
import { Prisma } from 'prisma/generated/prisma/client';
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationMembershipService {
|
||||
constructor(
|
||||
private readonly userService: UserService,
|
||||
private readonly orgService: OrganizationService,
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly authorization: AuthorizationService,
|
||||
) {}
|
||||
async inviteUserToOrg(
|
||||
userId: string,
|
||||
dto: InviteUserToOrganizationRequestDTO,
|
||||
) {
|
||||
const [orgExists, invitedUser] = await Promise.all([
|
||||
this.orgService.findById(dto.orgId),
|
||||
this.userService.getById(dto.invitedUserId),
|
||||
]);
|
||||
|
||||
if (!orgExists) throw new NotFoundException('Organization');
|
||||
if (!invitedUser) throw new NotFoundException('User');
|
||||
|
||||
const userAlreadyPart =
|
||||
await this.prisma.organizationUserJoinTable.findUnique({
|
||||
where: {
|
||||
userId_orgId: {
|
||||
orgId: dto.orgId,
|
||||
userId,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (userAlreadyPart)
|
||||
throw new BadRequestException('User already part of this organization');
|
||||
|
||||
const canInviteUser = await this.authorization.canPerformOperation(
|
||||
userId,
|
||||
dto.orgId,
|
||||
USER_ORGANIZATION_OPERATIONS.INVITE_USERS,
|
||||
);
|
||||
if (!canInviteUser) throw new ForbiddenException('Insufficient Permission');
|
||||
|
||||
try {
|
||||
const invitation = await this.prisma.organizationJoinRequest.create({
|
||||
data: {
|
||||
...dto,
|
||||
userId: dto.invitedUserId,
|
||||
requestType: ORGANIZATION_JOIN_REQUEST_TYPE.INVITED,
|
||||
},
|
||||
});
|
||||
|
||||
return invitation;
|
||||
} catch (err) {
|
||||
if (err instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
if (err.code === 'P2002')
|
||||
throw new BadRequestException('User invitation already sent.');
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
requestToJoin() {}
|
||||
|
||||
// TODO: reject, rejectReason
|
||||
async acceptInvite(userId: string, orgId: string) {
|
||||
const orgExists = await this.orgService.findById(orgId);
|
||||
if (!orgExists) throw new NotFoundException('Organization');
|
||||
|
||||
const [userAlreadyPart, isUserInvited] = await Promise.all([
|
||||
this.prisma.organizationUserJoinTable.findUnique({
|
||||
where: {
|
||||
userId_orgId: {
|
||||
orgId,
|
||||
userId,
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
||||
this.prisma.organizationJoinRequest.findUnique({
|
||||
where: {
|
||||
userId_orgId: {
|
||||
orgId,
|
||||
userId,
|
||||
},
|
||||
status: ORGANIZATION_JOIN_REQUEST.PENDING,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
if (userAlreadyPart)
|
||||
throw new BadRequestException('User already part of this organization');
|
||||
if (!isUserInvited)
|
||||
throw new BadRequestException(
|
||||
'User has no invitations from this organization',
|
||||
);
|
||||
|
||||
return await this.prisma.$transaction(async (tx) => {
|
||||
await tx.organizationJoinRequest.update({
|
||||
where: {
|
||||
userId_orgId: {
|
||||
userId,
|
||||
orgId,
|
||||
},
|
||||
},
|
||||
data: {
|
||||
status: ORGANIZATION_JOIN_REQUEST.ACCEPTED,
|
||||
},
|
||||
});
|
||||
|
||||
return await tx.organizationUserJoinTable.create({
|
||||
data: {
|
||||
orgId,
|
||||
userId,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async getUserInvitations(
|
||||
userId: string,
|
||||
requestType: ORGANIZATION_JOIN_REQUEST_TYPE,
|
||||
status: ORGANIZATION_JOIN_REQUEST = ORGANIZATION_JOIN_REQUEST.PENDING,
|
||||
) {
|
||||
return await this.prisma.organizationJoinRequest.findMany({
|
||||
where: {
|
||||
userId: userId,
|
||||
status: status,
|
||||
requestType: requestType,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
2
src/organization/dtos/index.ts
Normal file
2
src/organization/dtos/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './organization.dto';
|
||||
export * from './organization-response.dto';
|
||||
15
src/organization/dtos/organization-response.dto.ts
Normal file
15
src/organization/dtos/organization-response.dto.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Organization } from 'prisma/generated/prisma/client';
|
||||
|
||||
export class OrganizationDTO {
|
||||
readonly name: string;
|
||||
readonly description: string | null;
|
||||
readonly createdAt: Date;
|
||||
|
||||
constructor(organization: Organization) {
|
||||
this.name = organization.name;
|
||||
this.description = organization.description;
|
||||
this.createdAt = organization.createdAt;
|
||||
}
|
||||
}
|
||||
|
||||
export class CreateNewOrganizationResponseDTO extends OrganizationDTO {}
|
||||
30
src/organization/dtos/organization.dto.ts
Normal file
30
src/organization/dtos/organization.dto.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
import { AtLeastOneField } from 'common/validators';
|
||||
|
||||
export class CreateNewOrganizationRequestDTO {
|
||||
@ApiProperty({
|
||||
description: "Organization's name",
|
||||
example: 'Lions',
|
||||
type: 'string',
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
name: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'Short description for organization',
|
||||
example: 'A cool organization active for over 10 years.',
|
||||
type: 'string',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
description?: string;
|
||||
}
|
||||
|
||||
@AtLeastOneField({
|
||||
message: 'Provide at least one field to update',
|
||||
})
|
||||
export class UpdateOrganizationRequestDTO extends PartialType(
|
||||
CreateNewOrganizationRequestDTO,
|
||||
) {}
|
||||
18
src/organization/organization.controller.spec.ts
Normal file
18
src/organization/organization.controller.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { OrganizationController } from './organization.controller';
|
||||
|
||||
describe('OrganizationController', () => {
|
||||
let controller: OrganizationController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [OrganizationController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<OrganizationController>(OrganizationController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
94
src/organization/organization.controller.ts
Normal file
94
src/organization/organization.controller.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Param,
|
||||
Post,
|
||||
Put,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
CreateNewOrganizationRequestDTO,
|
||||
OrganizationDTO,
|
||||
UpdateOrganizationRequestDTO,
|
||||
} from './dtos';
|
||||
import { OrganizationService } from './organization.service';
|
||||
import { RequestContextService } from 'core/als/request-context.service';
|
||||
import { ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { DataResponse } from 'common/http';
|
||||
|
||||
@Controller('organization')
|
||||
@ApiBearerAuth('access-token')
|
||||
export class OrganizationController {
|
||||
constructor(
|
||||
private readonly orgService: OrganizationService,
|
||||
private readonly requestContext: RequestContextService,
|
||||
) {}
|
||||
|
||||
@Post('')
|
||||
async createNewOrganization(
|
||||
@Body() body: CreateNewOrganizationRequestDTO,
|
||||
): Promise<DataResponse<OrganizationDTO>> {
|
||||
const user = this.requestContext.user;
|
||||
const newOrg = await this.orgService.createNewOrganization(
|
||||
user.userId,
|
||||
body,
|
||||
);
|
||||
|
||||
return new DataResponse<OrganizationDTO>(
|
||||
new OrganizationDTO(newOrg),
|
||||
'Organization created successfully.',
|
||||
);
|
||||
}
|
||||
|
||||
@Get('')
|
||||
async getOrganizations(): Promise<DataResponse<OrganizationDTO[]>> {
|
||||
const organizations = await this.orgService.getOrganizations();
|
||||
|
||||
return new DataResponse(
|
||||
organizations.map((organization) => new OrganizationDTO(organization)),
|
||||
);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
async getAnOrganization(
|
||||
@Param('id') id: string,
|
||||
): Promise<DataResponse<OrganizationDTO>> {
|
||||
const organization = await this.orgService.getOrganizationById(id);
|
||||
return new DataResponse(new OrganizationDTO(organization));
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
async updateAnOrganization(
|
||||
@Param('id') orgId: string,
|
||||
@Body() body: UpdateOrganizationRequestDTO,
|
||||
): Promise<DataResponse<OrganizationDTO>> {
|
||||
const user = this.requestContext.user;
|
||||
const updatedOrg = await this.orgService.updateAnOrganization(
|
||||
user.userId,
|
||||
orgId,
|
||||
body,
|
||||
);
|
||||
|
||||
return new DataResponse<OrganizationDTO>(
|
||||
new OrganizationDTO(updatedOrg),
|
||||
'Organization updated successfully',
|
||||
);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
async deleteAnOrganization(
|
||||
@Param('id') orgId: string,
|
||||
): Promise<DataResponse<OrganizationDTO>> {
|
||||
const user = this.requestContext.user;
|
||||
const deletedOrg = await this.orgService.deleteAnOrganization(
|
||||
user.userId,
|
||||
orgId,
|
||||
);
|
||||
|
||||
return new DataResponse<OrganizationDTO>(
|
||||
new OrganizationDTO(deletedOrg),
|
||||
'Organization deleted successfully',
|
||||
);
|
||||
}
|
||||
}
|
||||
20
src/organization/organization.module.ts
Normal file
20
src/organization/organization.module.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { OrganizationController } from './organization.controller';
|
||||
import { OrganizationService } from './organization.service';
|
||||
import { PrismaModule } from 'src/prisma/prisma.module';
|
||||
import { RequestContextModule } from 'core/als/request-context.module';
|
||||
import { UserModule } from 'src/user/user.module';
|
||||
import { AuthorizationModule } from 'src/authorization/authorization.module';
|
||||
|
||||
@Module({
|
||||
controllers: [OrganizationController],
|
||||
providers: [OrganizationService],
|
||||
imports: [
|
||||
PrismaModule,
|
||||
RequestContextModule,
|
||||
UserModule,
|
||||
AuthorizationModule,
|
||||
],
|
||||
exports: [OrganizationService],
|
||||
})
|
||||
export class OrganizationModule {}
|
||||
18
src/organization/organization.service.spec.ts
Normal file
18
src/organization/organization.service.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { OrganizationService } from './organization.service';
|
||||
|
||||
describe('OrganizationService', () => {
|
||||
let service: OrganizationService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [OrganizationService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<OrganizationService>(OrganizationService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
120
src/organization/organization.service.ts
Normal file
120
src/organization/organization.service.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import {
|
||||
ForbiddenException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
CreateNewOrganizationRequestDTO,
|
||||
UpdateOrganizationRequestDTO,
|
||||
} from './dtos';
|
||||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import { RequestContextService } from 'core/als/request-context.service';
|
||||
import { ORG_ROLE } from 'prisma/generated/prisma/enums';
|
||||
import { AuthorizationService } from 'src/authorization/authorization.service';
|
||||
import { USER_ORGANIZATION_OPERATIONS } from 'src/authorization/operations';
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationService {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
// private readonly reqContext: RequestContextService,
|
||||
private readonly authorization: AuthorizationService,
|
||||
) {}
|
||||
async createNewOrganization(
|
||||
userId: string,
|
||||
dto: CreateNewOrganizationRequestDTO,
|
||||
) {
|
||||
return await this.prisma.$transaction(async (tx) => {
|
||||
const newOrganization = await tx.organization.create({
|
||||
data: dto,
|
||||
});
|
||||
|
||||
await tx.organizationUserJoinTable.create({
|
||||
data: {
|
||||
orgId: newOrganization.id,
|
||||
userId: userId,
|
||||
role: ORG_ROLE.owner,
|
||||
},
|
||||
});
|
||||
|
||||
return newOrganization;
|
||||
});
|
||||
}
|
||||
|
||||
// NOTE: Pagination
|
||||
async getOrganizations() {
|
||||
return await this.prisma.organization.findMany();
|
||||
}
|
||||
|
||||
async getOrganizationById(orgId: string) {
|
||||
const orgExists = await this.findById(orgId);
|
||||
if (!orgExists) throw new NotFoundException('Organization');
|
||||
|
||||
return orgExists;
|
||||
}
|
||||
|
||||
async updateAnOrganization(
|
||||
userId: string,
|
||||
orgId: string,
|
||||
dto: UpdateOrganizationRequestDTO,
|
||||
) {
|
||||
const orgExists = await this.findById(orgId);
|
||||
if (!orgExists) throw new NotFoundException('Organization');
|
||||
|
||||
const canUserUpdateOrganization =
|
||||
await this.authorization.canPerformOperation(
|
||||
userId,
|
||||
orgId,
|
||||
USER_ORGANIZATION_OPERATIONS.UPDATE_ORGANIZATION,
|
||||
);
|
||||
|
||||
if (!canUserUpdateOrganization)
|
||||
throw new ForbiddenException('Not enough permission');
|
||||
|
||||
return this.prisma.organization.update({
|
||||
where: {
|
||||
id: orgId,
|
||||
},
|
||||
data: dto,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Either empty or choose someone to be owner
|
||||
async deleteAnOrganization(userId: string, orgId: string) {
|
||||
const orgExists = await this.findById(orgId);
|
||||
if (!orgExists) throw new NotFoundException('Organization');
|
||||
|
||||
const canUserDeleteOrganization =
|
||||
await this.authorization.canPerformOperation(
|
||||
userId,
|
||||
orgId,
|
||||
USER_ORGANIZATION_OPERATIONS.DELETE_ORGANIZATION,
|
||||
);
|
||||
|
||||
if (!canUserDeleteOrganization)
|
||||
throw new ForbiddenException('Not enough permission');
|
||||
|
||||
return await this.prisma.$transaction(async (tx) => {
|
||||
const deletedOrganization = await tx.organization.delete({
|
||||
where: {
|
||||
id: orgId,
|
||||
},
|
||||
});
|
||||
|
||||
await tx.organizationUserJoinTable.delete({
|
||||
where: {
|
||||
userId_orgId: {
|
||||
userId,
|
||||
orgId,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return deletedOrganization;
|
||||
});
|
||||
}
|
||||
|
||||
async findById(orgId: string) {
|
||||
return await this.prisma.organization.findUnique({ where: { id: orgId } });
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,14 @@ export class UserService {
|
||||
});
|
||||
}
|
||||
|
||||
async getById(id: string) {
|
||||
return await this.prisma.user.findUnique({
|
||||
where: {
|
||||
id: id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async updateRefreshToken(id: string, refreshToken: string) {
|
||||
return await this.prisma.user.update({
|
||||
where: { id },
|
||||
|
||||
Reference in New Issue
Block a user