feat: Added methods for organization
This commit is contained in:
16
src/auth/decorators/authorization.decorator.ts
Normal file
16
src/auth/decorators/authorization.decorator.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { applyDecorators, SetMetadata, UseGuards } from "@nestjs/common";
|
||||
import { CAN_PERFORM_KEY } from "common/keys";
|
||||
import { ORG_ROLE } from "prisma/generated/prisma/enums";
|
||||
import { AuthorizationGuard } from "../guards";
|
||||
|
||||
/*
|
||||
*Is this user part of the organization (And optionally, has required role)
|
||||
* */
|
||||
|
||||
export function Authorization(role?: ORG_ROLE[]) {
|
||||
return applyDecorators(
|
||||
SetMetadata(CAN_PERFORM_KEY, role),
|
||||
UseGuards(AuthorizationGuard)
|
||||
)
|
||||
}
|
||||
//export const Authorization = (role?: ORG_ROLE[]) => SetMetadata(CAN_PERFORM_KEY, role)
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './public.decorator';
|
||||
export * from './role.decorator';
|
||||
export * from './authorization.decorator';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { SetMetadata } from '@nestjs/common';
|
||||
import { ROLE_KEY } from 'common/keys';
|
||||
import { ORG_ROLE_KEY, ROLE_KEY } from 'common/keys';
|
||||
|
||||
export const Roles = (role: string) => SetMetadata(ROLE_KEY, role);
|
||||
|
||||
export const OrgRole = (role: string) => SetMetadata(ORG_ROLE_KEY, role);
|
||||
|
||||
57
src/auth/guards/authorization.guard.ts
Normal file
57
src/auth/guards/authorization.guard.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
ForbiddenException,
|
||||
Injectable,
|
||||
UnauthorizedException
|
||||
} from "@nestjs/common";
|
||||
import { Reflector } from "@nestjs/core";
|
||||
import { CAN_PERFORM_KEY } from "common/keys";
|
||||
import { RequestContextService } from "core/als/request-context.service";
|
||||
import { ORG_ROLE } from "prisma/generated/prisma/enums";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
|
||||
@Injectable()
|
||||
export class AuthorizationGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly reqeustContext: RequestContextService,
|
||||
private readonly reflector: Reflector,
|
||||
private readonly prisma: PrismaService,
|
||||
) { };
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const requiredRole = this.reflector.getAllAndOverride<ORG_ROLE[] | undefined>(
|
||||
CAN_PERFORM_KEY,
|
||||
[context.getHandler(), context.getClass()]
|
||||
)
|
||||
|
||||
const userId = this.reqeustContext.user.userId;
|
||||
if (!userId)
|
||||
throw new UnauthorizedException()
|
||||
|
||||
const request = context.switchToHttp().getRequest()
|
||||
const orgId = request.params.orgId;
|
||||
|
||||
if (!orgId)
|
||||
throw new BadRequestException()
|
||||
|
||||
const userIsPartOfOrg = await this.prisma.organizationUserJoinTable.findUnique({
|
||||
where: {
|
||||
userId_orgId: {
|
||||
userId,
|
||||
orgId
|
||||
},
|
||||
...(requiredRole ? { role: { in: requiredRole } } : {})
|
||||
},
|
||||
select: {
|
||||
userId: true
|
||||
}
|
||||
})
|
||||
if (!userIsPartOfOrg)
|
||||
throw new ForbiddenException()
|
||||
|
||||
this.reqeustContext.orgId = orgId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./authorization.guard"
|
||||
|
||||
@@ -11,7 +11,7 @@ export class RbacGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly reflector: Reflector,
|
||||
private readonly requestContext: RequestContextService,
|
||||
) {}
|
||||
) { }
|
||||
canActivate(context: ExecutionContext) {
|
||||
const requiredRole = this.reflector.getAllAndOverride<string>(ROLE_KEY, [
|
||||
context.getHandler(),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './invite-to-org.dto';
|
||||
export * from './join-request.dto'
|
||||
export * from "./user-invitation-action.dto"
|
||||
export * from "./org-request-action.dto"
|
||||
|
||||
@@ -21,3 +21,14 @@ export class InviteUserToOrganizationRequestDTO {
|
||||
@IsNotEmpty()
|
||||
role: ORG_ROLE;
|
||||
}
|
||||
|
||||
export class CancelInviteUserToOrganizationRequestDTO {
|
||||
@ApiProperty({
|
||||
description: 'Who to cancel',
|
||||
example: 'bb1c81da-ce8f-4231-aee8-2b976124a589',
|
||||
type: 'string',
|
||||
})
|
||||
@IsUUID()
|
||||
@IsNotEmpty()
|
||||
userId: string;
|
||||
}
|
||||
|
||||
23
src/organization-membership/dto/org-request-action.dto.ts
Normal file
23
src/organization-membership/dto/org-request-action.dto.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"
|
||||
import { IsEnum, IsNotEmpty, IsOptional, IsString } from "class-validator"
|
||||
import { USER_ORG_ACCEPT_REJECT_ACTION } from "../constants"
|
||||
|
||||
export class UserOrganizationRequestActionRequestDTO {
|
||||
@ApiProperty({
|
||||
description: 'Action',
|
||||
example: USER_ORG_ACCEPT_REJECT_ACTION.ACCEPT,
|
||||
type: 'string',
|
||||
})
|
||||
@IsEnum(USER_ORG_ACCEPT_REJECT_ACTION)
|
||||
@IsNotEmpty()
|
||||
action: USER_ORG_ACCEPT_REJECT_ACTION
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'Message(reject reason)',
|
||||
example: 'Bad sry or smth',
|
||||
type: 'string',
|
||||
})
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
message?: string
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||
import { IsEnum, IsNotEmpty, IsOptional, IsString, IsUUID } from "class-validator";
|
||||
import { IsEnum, IsNotEmpty, IsOptional, IsString } from "class-validator";
|
||||
import { USER_ORG_ACCEPT_REJECT_ACTION } from "../constants";
|
||||
|
||||
|
||||
|
||||
@@ -2,8 +2,9 @@ import { Body, Controller, Delete, Get, Param, ParseEnumPipe, ParseUUIDPipe, Pat
|
||||
import { OrganizationMembershipService } from './organization-membership.service';
|
||||
import { RequestContextService } from 'core/als/request-context.service';
|
||||
import { ApiBearerAuth, ApiOperation, ApiParam, ApiQuery } from '@nestjs/swagger';
|
||||
import { JoinRequestToOrganizationRequestDTO, UserOrganizationInvitationActionRequestDTO } from './dto';
|
||||
import { ORGANIZATION_JOIN_REQUEST_TYPE } from 'prisma/generated/prisma/enums';
|
||||
import { CancelInviteUserToOrganizationRequestDTO, InviteUserToOrganizationRequestDTO, JoinRequestToOrganizationRequestDTO, UserOrganizationInvitationActionRequestDTO, UserOrganizationRequestActionRequestDTO } from './dto';
|
||||
import { ORG_ROLE, ORGANIZATION_JOIN_REQUEST_TYPE } from 'prisma/generated/prisma/enums';
|
||||
import { Authorization } from 'src/auth/decorators';
|
||||
|
||||
/* NOTE: Regarding endpoint path naming
|
||||
* - Since we follow REST style, endpoint are resource based.
|
||||
@@ -42,10 +43,17 @@ export class OrganizationMembershipController {
|
||||
name: 'orgId',
|
||||
type: String,
|
||||
})
|
||||
@Delete('organization/:orgId/join-request')
|
||||
async cancelRequestToJoinOrg(@Param('orgId', new ParseUUIDPipe()) orgId: string) {
|
||||
@Delete('organization/:orgId/join-request/:id')
|
||||
async cancelRequestToJoinOrg(
|
||||
@Param('orgId', new ParseUUIDPipe()) orgId: string,
|
||||
@Param('id', new ParseUUIDPipe()) joinReqId: string
|
||||
) {
|
||||
const user = this.requestContext.user;
|
||||
return await this.orgMemService.userCancelOrgJoinRequest(user.userId, orgId)
|
||||
return await this.orgMemService.userCancelOrgJoinRequest(
|
||||
user.userId,
|
||||
orgId,
|
||||
joinReqId
|
||||
)
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Accept or reject an invitation from an organization' })
|
||||
@@ -53,15 +61,17 @@ export class OrganizationMembershipController {
|
||||
name: 'orgId',
|
||||
type: String,
|
||||
})
|
||||
@Patch('organization/:orgId/invitation')
|
||||
@Patch('organization/:orgId/invitation/:id')
|
||||
async acceptOrRejectInvitation(
|
||||
@Param('orgId', new ParseUUIDPipe()) orgId: string,
|
||||
@Param('id', new ParseUUIDPipe()) invitationId: string,
|
||||
@Body() body: UserOrganizationInvitationActionRequestDTO
|
||||
) {
|
||||
const user = this.requestContext.user;
|
||||
return await this.orgMemService.userOrganiaztionRequestAction(
|
||||
user.userId,
|
||||
orgId,
|
||||
invitationId,
|
||||
body
|
||||
)
|
||||
}
|
||||
@@ -110,36 +120,66 @@ export class OrganizationMembershipController {
|
||||
* ORGANIZATION OPERATIONS
|
||||
* */
|
||||
|
||||
// @ApiOperation({ summary: 'Invite user to organization' })
|
||||
// @ApiParam({
|
||||
// name: 'orgId',
|
||||
// type: String,
|
||||
// })
|
||||
// @Post('organization/:orgId/invitation')
|
||||
// async inviteUserToOrg(
|
||||
// @Param('orgId', new ParseUUIDPipe()) orgId: string,
|
||||
// @Body() body: InviteUserToOrganizationRequestDTO
|
||||
// ) {
|
||||
// const user = this.requestContext.user;
|
||||
// return await this.orgMemService.inviteUserToOrg(
|
||||
// user.userId,
|
||||
// orgId,
|
||||
// body
|
||||
// );
|
||||
// }
|
||||
// @Get('organization/:id/members')
|
||||
// async getOrganizationMemebers(@Param('id') orgId: string) {
|
||||
// return await this.orgMemService.getMemebersOfOrganization(orgId);
|
||||
// }
|
||||
//
|
||||
// @Get('organization/:id/invitations')
|
||||
// async getOrganizationInvitations(@Param('id') orgId: string) {
|
||||
// return await this.orgMemService.getOrganizationRequestList(orgId);
|
||||
// }
|
||||
//
|
||||
// @Patch('organization/:id/accept-request')
|
||||
// acceptJoinRequest() { }
|
||||
//
|
||||
// @Patch('organization/:id/reject-request')
|
||||
// rejectJoinRequest() { }
|
||||
@ApiOperation({ summary: 'Invite user to organization' })
|
||||
@ApiParam({
|
||||
name: 'orgId',
|
||||
type: String,
|
||||
})
|
||||
@Authorization([ORG_ROLE.admin, ORG_ROLE.owner])
|
||||
@Post('organization/:orgId/invitation')
|
||||
async inviteUserToOrg(
|
||||
@Param('orgId', new ParseUUIDPipe()) orgId: string,
|
||||
@Body() body: InviteUserToOrganizationRequestDTO
|
||||
) {
|
||||
return await this.orgMemService.inviteUserToOrg(
|
||||
orgId,
|
||||
body
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Cancel a sent invitation to user' })
|
||||
@ApiParam({
|
||||
name: 'userId',
|
||||
type: String,
|
||||
})
|
||||
@Authorization([ORG_ROLE.admin, ORG_ROLE.owner])
|
||||
@Delete('organization/:orgId/invitation/:id')
|
||||
async cancelInvitationsToUser(
|
||||
@Param('orgId', new ParseUUIDPipe()) orgId: string,
|
||||
@Param('id', new ParseUUIDPipe()) invitationId: string,
|
||||
@Body() body: CancelInviteUserToOrganizationRequestDTO
|
||||
) {
|
||||
const userId = body.userId;
|
||||
return await this.orgMemService.orgCancelUserInviteRequest(userId, orgId, invitationId)
|
||||
}
|
||||
|
||||
@Get('organization/:orgId/members')
|
||||
@Authorization()
|
||||
async getOrganizationMemebers(@Param('orgId') orgId: string) {
|
||||
const user = this.requestContext.user;
|
||||
return await this.orgMemService.getMemebersOfOrganization(user.userId, orgId);
|
||||
}
|
||||
|
||||
@Get('organization/:orgId/invitations')
|
||||
@Authorization([ORG_ROLE.admin, ORG_ROLE.owner])
|
||||
async getOrganizationInvitations(@Param('orgId') orgId: string) {
|
||||
const user = this.requestContext.user;
|
||||
return await this.orgMemService.getOrganizationRequestList(user.userId, orgId);
|
||||
}
|
||||
|
||||
@Patch('organization/:orgId/request/:id')
|
||||
@Authorization([ORG_ROLE.admin, ORG_ROLE.owner])
|
||||
async acceptOrRejectRequest(
|
||||
@Param('orgId', new ParseUUIDPipe()) orgId: string,
|
||||
@Param('id', new ParseUUIDPipe()) invitationId: string,
|
||||
@Body() body: UserOrganizationRequestActionRequestDTO
|
||||
) {
|
||||
const user = this.requestContext.user;
|
||||
return await this.orgMemService.organizationUserJoinRequestAction(
|
||||
user.userId,
|
||||
orgId,
|
||||
invitationId,
|
||||
body
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from '@nestjs/common';
|
||||
import { OrganizationService } from 'src/organization/organization.service';
|
||||
import { UserService } from 'src/user/user.service';
|
||||
import { InviteUserToOrganizationRequestDTO, UserOrganizationInvitationActionRequestDTO } from './dto';
|
||||
import { InviteUserToOrganizationRequestDTO, UserOrganizationInvitationActionRequestDTO, UserOrganizationRequestActionRequestDTO } from './dto';
|
||||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import {
|
||||
ORGANIZATION_JOIN_REQUEST,
|
||||
@@ -26,60 +26,6 @@ export class OrganizationMembershipService {
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly authorization: AuthorizationService,
|
||||
) { }
|
||||
async inviteUserToOrg(
|
||||
userId: string,
|
||||
orgId: string,
|
||||
dto: InviteUserToOrganizationRequestDTO,
|
||||
) {
|
||||
const { invitedUserEmail, ...rest } = dto;
|
||||
const [orgExists, invitedUser] = await Promise.all([
|
||||
this.orgService.findById(orgId),
|
||||
this.userService.findByEmail(invitedUserEmail),
|
||||
]);
|
||||
|
||||
if (!orgExists) throw new NotFoundException('Organization');
|
||||
if (!invitedUser) throw new NotFoundException('User');
|
||||
|
||||
const userAlreadyPart =
|
||||
await this.prisma.organizationUserJoinTable.findUnique({
|
||||
where: {
|
||||
userId_orgId: {
|
||||
orgId: orgId,
|
||||
userId: invitedUser.id,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (userAlreadyPart)
|
||||
throw new BadRequestException('User already part of this organization');
|
||||
|
||||
const canInviteUser = await this.authorization.canPerformOperation(
|
||||
userId,
|
||||
orgId,
|
||||
USER_ORGANIZATION_OPERATIONS.INVITE_USERS,
|
||||
);
|
||||
if (!canInviteUser) throw new ForbiddenException('Insufficient Permission');
|
||||
|
||||
try {
|
||||
const invitation = await this.prisma.organizationJoinRequest.create({
|
||||
data: {
|
||||
...rest,
|
||||
userId: invitedUser.id,
|
||||
orgId,
|
||||
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.');
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* *
|
||||
* USER OPERATIONS
|
||||
@@ -95,22 +41,17 @@ export class OrganizationMembershipService {
|
||||
userAlreadyPartOf
|
||||
] = await Promise.all([
|
||||
this.orgService.findById(orgId),
|
||||
this.prisma.organizationJoinRequest.findUnique({
|
||||
this.prisma.organizationJoinRequest.findFirst({
|
||||
where: {
|
||||
userId_orgId: {
|
||||
userId,
|
||||
orgId: orgId
|
||||
},
|
||||
orgId,
|
||||
userId,
|
||||
status: ORGANIZATION_JOIN_REQUEST.PENDING
|
||||
},
|
||||
select: { orgId: true }
|
||||
}),
|
||||
this.prisma.organizationUserJoinTable.findUnique({
|
||||
this.prisma.organizationUserJoinTable.findFirst({
|
||||
where: {
|
||||
userId_orgId: {
|
||||
orgId: orgId,
|
||||
userId
|
||||
}
|
||||
orgId,
|
||||
userId,
|
||||
},
|
||||
select: { userId: true }
|
||||
})
|
||||
@@ -136,15 +77,15 @@ export class OrganizationMembershipService {
|
||||
|
||||
async userCancelOrgJoinRequest(
|
||||
userId: string,
|
||||
orgId: string
|
||||
orgId: string,
|
||||
id: string,
|
||||
) {
|
||||
try {
|
||||
await this.prisma.organizationJoinRequest.update({
|
||||
where: {
|
||||
userId_orgId: {
|
||||
userId,
|
||||
orgId
|
||||
},
|
||||
id,
|
||||
userId,
|
||||
orgId
|
||||
},
|
||||
data: {
|
||||
status: ORGANIZATION_JOIN_REQUEST.CANCELLED,
|
||||
@@ -174,8 +115,9 @@ export class OrganizationMembershipService {
|
||||
return await this.prisma.organizationJoinRequest.findMany({
|
||||
where: {
|
||||
userId,
|
||||
requestType: joinReqType
|
||||
}
|
||||
requestType: joinReqType,
|
||||
},
|
||||
include: { user: { select: { firstName: true, email: true } } }
|
||||
})
|
||||
}
|
||||
|
||||
@@ -183,24 +125,19 @@ export class OrganizationMembershipService {
|
||||
async userOrganiaztionRequestAction(
|
||||
userId: string,
|
||||
orgId: string,
|
||||
id: string,
|
||||
dto: UserOrganizationInvitationActionRequestDTO
|
||||
) {
|
||||
const [orgExists, hasUserSendRequest] = await Promise.all([
|
||||
this.orgService.findById(orgId),
|
||||
this.prisma.organizationJoinRequest.findUnique({
|
||||
where: {
|
||||
userId_orgId: {
|
||||
userId,
|
||||
orgId: orgId
|
||||
},
|
||||
status: ORGANIZATION_JOIN_REQUEST.PENDING,
|
||||
requestType: ORGANIZATION_JOIN_REQUEST_TYPE.REQUESTED
|
||||
}
|
||||
})
|
||||
])
|
||||
const hasUserSendRequest = await this.prisma.organizationJoinRequest.findUnique({
|
||||
where: {
|
||||
id,
|
||||
userId,
|
||||
orgId,
|
||||
status: ORGANIZATION_JOIN_REQUEST.PENDING,
|
||||
requestType: ORGANIZATION_JOIN_REQUEST_TYPE.REQUESTED
|
||||
}
|
||||
})
|
||||
|
||||
if (!orgExists)
|
||||
throw new NotFoundException("Organization")
|
||||
if (!hasUserSendRequest)
|
||||
throw new BadRequestException("No pending join request")
|
||||
|
||||
@@ -212,10 +149,9 @@ export class OrganizationMembershipService {
|
||||
|
||||
await tx.organizationJoinRequest.update({
|
||||
where: {
|
||||
userId_orgId: {
|
||||
userId,
|
||||
orgId: orgId,
|
||||
}
|
||||
id,
|
||||
userId,
|
||||
orgId,
|
||||
},
|
||||
data: {
|
||||
status: userAction,
|
||||
@@ -322,9 +258,9 @@ export class OrganizationMembershipService {
|
||||
}
|
||||
|
||||
async getOrganizationsOfUser(userId: string) {
|
||||
return await this.prisma.organizationJoinRequest.findMany({
|
||||
return await this.prisma.organizationUserJoinTable.findMany({
|
||||
where: {
|
||||
userId
|
||||
userId,
|
||||
},
|
||||
include: {
|
||||
organization: {
|
||||
@@ -351,41 +287,166 @@ export class OrganizationMembershipService {
|
||||
return true;
|
||||
}
|
||||
|
||||
async inviteUserToOrg(
|
||||
orgId: string,
|
||||
dto: InviteUserToOrganizationRequestDTO,
|
||||
) {
|
||||
const { invitedUserEmail, ...rest } = dto;
|
||||
|
||||
const invitedUser = await this.userService.findByEmail(invitedUserEmail);
|
||||
if (!invitedUser) throw new NotFoundException('User');
|
||||
|
||||
const userAlreadyPart =
|
||||
await this.prisma.organizationUserJoinTable.findUnique({
|
||||
where: {
|
||||
userId_orgId: {
|
||||
orgId: orgId,
|
||||
userId: invitedUser.id,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (userAlreadyPart)
|
||||
throw new BadRequestException('User already part of this organization');
|
||||
|
||||
// TODO: Test in Authorization and remove
|
||||
// const canInviteUser = await this.authorization.canPerformOperation(
|
||||
// userId,
|
||||
// orgId,
|
||||
// USER_ORGANIZATION_OPERATIONS.INVITE_USERS,
|
||||
// );
|
||||
// if (!canInviteUser) throw new ForbiddenException('Insufficient Permission');
|
||||
|
||||
try {
|
||||
const invitation = await this.prisma.organizationJoinRequest.create({
|
||||
data: {
|
||||
...rest,
|
||||
userId: invitedUser.id,
|
||||
orgId,
|
||||
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.');
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async orgCancelUserInviteRequest(
|
||||
userId: string,
|
||||
orgId: string,
|
||||
id: string,
|
||||
) {
|
||||
try {
|
||||
return await this.prisma.organizationJoinRequest.update({
|
||||
where: {
|
||||
id,
|
||||
userId,
|
||||
orgId,
|
||||
requestType: ORGANIZATION_JOIN_REQUEST_TYPE.INVITED,
|
||||
status: ORGANIZATION_JOIN_REQUEST.PENDING
|
||||
},
|
||||
data: {
|
||||
status: ORGANIZATION_JOIN_REQUEST.CANCELLED
|
||||
}
|
||||
})
|
||||
}
|
||||
catch (err) {
|
||||
// TODO: Check error type and use it
|
||||
throw new BadRequestException("Invitation not found")
|
||||
}
|
||||
}
|
||||
|
||||
async organizationUserJoinRequestAction(
|
||||
userId: string,
|
||||
orgId: string,
|
||||
id: string,
|
||||
dto: UserOrganizationRequestActionRequestDTO
|
||||
) {
|
||||
// NOTE: Experiment, don't know if its better
|
||||
try {
|
||||
return await this.prisma.$transaction(async (tx) => {
|
||||
const updatedJoinReq = await tx.organizationJoinRequest.update({
|
||||
where: {
|
||||
id,
|
||||
orgId,
|
||||
status: ORGANIZATION_JOIN_REQUEST.PENDING,
|
||||
requestType: ORGANIZATION_JOIN_REQUEST_TYPE.REQUESTED
|
||||
},
|
||||
data: {
|
||||
status: dto.action === USER_ORG_ACCEPT_REJECT_ACTION.ACCEPT
|
||||
? ORGANIZATION_JOIN_REQUEST.ACCEPTED
|
||||
: ORGANIZATION_JOIN_REQUEST.REJECTED,
|
||||
|
||||
...((dto.action === USER_ORG_ACCEPT_REJECT_ACTION.REJECT && dto.message) ? {
|
||||
rejectReason: dto.message
|
||||
} : {})
|
||||
}
|
||||
});
|
||||
console.log(updatedJoinReq)
|
||||
|
||||
return await tx.organizationUserJoinTable.create({
|
||||
data: {
|
||||
userId: updatedJoinReq.userId,
|
||||
orgId,
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
throw new BadRequestException()
|
||||
}
|
||||
}
|
||||
|
||||
async getOrganizationRequestList(
|
||||
userId: string,
|
||||
orgId: string,
|
||||
requestType: ORGANIZATION_JOIN_REQUEST_TYPE = ORGANIZATION_JOIN_REQUEST_TYPE.REQUESTED,
|
||||
status: ORGANIZATION_JOIN_REQUEST = ORGANIZATION_JOIN_REQUEST.PENDING,
|
||||
) {
|
||||
// TODO: Check can perform
|
||||
return await this.prisma.organizationJoinRequest.findMany({
|
||||
where: {
|
||||
orgId: orgId,
|
||||
status: status,
|
||||
requestType: requestType,
|
||||
},
|
||||
include: {
|
||||
user: {
|
||||
select: { email: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
orgId,
|
||||
requestType: requestType
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async getMemebersOfOrganization(orgId: string) {
|
||||
const orgExists = await this.orgService.findById(orgId);
|
||||
if (!orgExists) throw new NotFoundException('Organization');
|
||||
|
||||
return await this.prisma.organizationUserJoinTable.findMany({
|
||||
async getMemebersOfOrganization(userId: string, orgId: string) {
|
||||
const members = await this.prisma.organization.findFirst({
|
||||
where: {
|
||||
orgId: orgId,
|
||||
id: orgId,
|
||||
members: {
|
||||
some: {
|
||||
userId: userId
|
||||
}
|
||||
}
|
||||
},
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
email: true,
|
||||
members: {
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
firstName: true,
|
||||
email: true
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
if (!members)
|
||||
throw new NotFoundException("Organization")
|
||||
|
||||
return members;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
Param,
|
||||
Post,
|
||||
Put,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
CreateNewOrganizationRequestDTO,
|
||||
@@ -16,6 +17,7 @@ import { OrganizationService } from './organization.service';
|
||||
import { RequestContextService } from 'core/als/request-context.service';
|
||||
import { ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { DataResponse } from 'common/http';
|
||||
import { AuthorizationGuard } from 'src/auth/guards';
|
||||
|
||||
@Controller('organization')
|
||||
@ApiBearerAuth('access-token')
|
||||
@@ -23,7 +25,7 @@ export class OrganizationController {
|
||||
constructor(
|
||||
private readonly orgService: OrganizationService,
|
||||
private readonly requestContext: RequestContextService,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
@Post('')
|
||||
async createNewOrganization(
|
||||
@@ -50,17 +52,18 @@ export class OrganizationController {
|
||||
);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@Get(':orgId')
|
||||
@UseGuards(AuthorizationGuard)
|
||||
async getAnOrganization(
|
||||
@Param('id') id: string,
|
||||
@Param('orgId') orgId: string,
|
||||
): Promise<DataResponse<OrganizationDTO>> {
|
||||
const organization = await this.orgService.getOrganizationById(id);
|
||||
const organization = await this.orgService.getOrganizationById(orgId);
|
||||
return new DataResponse(new OrganizationDTO(organization));
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@Put(':orgId')
|
||||
async updateAnOrganization(
|
||||
@Param('id') orgId: string,
|
||||
@Param('orgId') orgId: string,
|
||||
@Body() body: UpdateOrganizationRequestDTO,
|
||||
): Promise<DataResponse<OrganizationDTO>> {
|
||||
const user = this.requestContext.user;
|
||||
@@ -76,9 +79,9 @@ export class OrganizationController {
|
||||
);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@Delete(':orgId')
|
||||
async deleteAnOrganization(
|
||||
@Param('id') orgId: string,
|
||||
@Param('orgId') orgId: string,
|
||||
): Promise<DataResponse<OrganizationDTO>> {
|
||||
const user = this.requestContext.user;
|
||||
const deletedOrg = await this.orgService.deleteAnOrganization(
|
||||
|
||||
Reference in New Issue
Block a user