Skip to content

Commit

Permalink
Merge pull request #147 from souravbhowmik1999/userTenantMapping
Browse files Browse the repository at this point in the history
Jira Tusk #PS-267 API to map a user to multiple tenants
  • Loading branch information
vaivk369 authored May 7, 2024
2 parents ee85332 + 8fda1b4 commit 57ba955
Show file tree
Hide file tree
Showing 16 changed files with 571 additions and 57 deletions.
17 changes: 17 additions & 0 deletions src/adapters/hasura/userTenantMapping.adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { BadRequestException, ConsoleLogger, HttpStatus, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Repository } from 'typeorm';
import { UserTenantMapping } from 'src/userTenantMapping/entities/user-tenant-mapping.entity';
import { UserTenantMappingDto } from "src/userTenantMapping/dto/user-tenant-mapping.dto";

@Injectable()
export class HasuraAssignTenantService {
constructor(
@InjectRepository(UserTenantMapping)
private userTenantMappingRepository: Repository<UserTenantMapping>,

) { }
public async userTenantMapping(request: any, assignTenantMappingDto:UserTenantMappingDto) {
}

}
28 changes: 15 additions & 13 deletions src/adapters/postgres/potsgres-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,23 @@ import { AttendanceEntity } from "src/attendance/entities/attendance.entity";
import { PostgresAttendanceService } from "./attendance-adapter";
import { PostgresFieldsService } from "./fields-adapter";
import { Cohort } from "src/cohort/entities/cohort.entity";

import { UserTenantMapping } from "src/userTenantMapping/entities/user-tenant-mapping.entity";
import { Tenants } from "src/userTenantMapping/entities/tenant.entity";


@Module({
imports: [HttpModule,
TypeOrmModule.forFeature([
User,
Field,
FieldValues,
CohortMembers,
AttendanceEntity,
Fields,
Cohort
])
TypeOrmModule.forFeature([
User,
Field,
FieldValues,
CohortMembers,
AttendanceEntity,
Fields,
Cohort,
UserTenantMapping,
Tenants
])
],
providers: [
PostgresUserService,
Expand All @@ -37,6 +40,5 @@ import { Cohort } from "src/cohort/entities/cohort.entity";
PostgresAttendanceService,
PostgresFieldsService
],
})
export class PostgresModule {}

})
export class PostgresModule { }
180 changes: 143 additions & 37 deletions src/adapters/postgres/user-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ import axios, { AxiosInstance, AxiosRequestConfig } from "axios"
import { ErrorResponseTypeOrm } from 'src/error-response-typeorm';
import { isUUID } from 'class-validator';
import { UserSearchDto } from 'src/user/dto/user-search.dto';

import { UserTenantMapping } from "src/userTenantMapping/entities/user-tenant-mapping.entity";
import { Tenants } from "src/userTenantMapping/entities/tenant.entity";

@Injectable()
export class PostgresUserService {
axios = require("axios");

constructor(
// private axiosInstance: AxiosInstance,
@InjectRepository(User)
Expand All @@ -33,18 +35,23 @@ export class PostgresUserService {
@InjectRepository(Field)
private fieldsRepository: Repository<Field>,
@InjectRepository(CohortMembers)
private cohortMemberRepository: Repository<CohortMembers>
private cohortMemberRepository: Repository<CohortMembers>,
@InjectRepository(UserTenantMapping)
private userTenantMappingRepository: Repository<UserTenantMapping>,
@InjectRepository(Tenants)
private tenantsRepository: Repository<Tenants>,
) { }
async searchUser(tenantId: string,
async searchUser(tenantId: string,
request: any,
response: any,
userSearchDto: UserSearchDto){
userSearchDto: UserSearchDto) {
try {
let findData = await this.findAllUserDetails(userSearchDto);
if(!findData){
return new SuccessResponse({
statusCode: HttpStatus.BAD_REQUEST,
message: 'No Data Found For User',});
if (!findData) {
return new SuccessResponse({
statusCode: HttpStatus.BAD_REQUEST,
message: 'No Data Found For User',
});
}
return new SuccessResponse({
statusCode: HttpStatus.OK,
Expand All @@ -59,7 +66,7 @@ export class PostgresUserService {
}
}

async findAllUserDetails(userSearchDto){
async findAllUserDetails(userSearchDto) {
let { limit, page, filters } = userSearchDto;

let offset = 0;
Expand Down Expand Up @@ -89,8 +96,8 @@ export class PostgresUserService {
try {
if (!isUUID(userData.userId)) {
return new SuccessResponse({
statusCode: HttpStatus.BAD_REQUEST,
message: 'Please Enter Valid User ID',
statusCode: HttpStatus.BAD_REQUEST,
message: 'Please Enter Valid User ID',
});
}
const result = {
Expand All @@ -103,13 +110,13 @@ export class PostgresUserService {
this.findFilledValues(userData.userId),
this.findUserDetails(userData.userId)
]);
if(!userDetails){
if (!userDetails) {
return new SuccessResponse({
statusCode: HttpStatus.NOT_FOUND,
message: 'User Not Found',
});
}
if(!userData.fieldValue){
if (!userData.fieldValue) {
return new SuccessResponse({
statusCode: HttpStatus.OK,
message: 'Ok.',
Expand Down Expand Up @@ -333,6 +340,42 @@ export class PostgresUserService {
userCreateDto.createdBy = decoded?.sub
userCreateDto.updatedBy = decoded?.sub

//Check duplicate field entry
if (userCreateDto.fieldValues) {
let field_value_array = userCreateDto.fieldValues.split("|");
const validateField = await this.validateFieldValues(field_value_array);

if(validateField == false){
return new ErrorResponseTypeOrm({
statusCode: HttpStatus.CONFLICT,
errorMessage: "Duplicate fieldId found in fieldValues.",
});
}
}

// Check if tenant array is not empty
const tenantIds = userCreateDto.tenantId;
const userId = userCreateDto.userId;
let errors = [];

if (!tenantIds || tenantIds.length === 0) {
return new SuccessResponse({
statusCode: HttpStatus.BAD_REQUEST,
message: "Tenants array cannot be empty.",
});
}

//Check tenent is exist or not
for (const tenantId of tenantIds) {
const validate = await this.validateUserTenantMapping(userId, tenantId);
if (validate == false) {
return new ErrorResponseTypeOrm({
statusCode: HttpStatus.BAD_REQUEST,
errorMessage: `Tenant ${tenantId} does not exist.`,
});
}
}

userCreateDto.username = userCreateDto.username.toLocaleLowerCase();
const userSchema = new UserCreateDto(userCreateDto);

Expand Down Expand Up @@ -360,24 +403,40 @@ export class PostgresUserService {
}
);
userCreateDto.userId = resKeycloak;





if (errors.length > 0) {
return {
statusCode: HttpStatus.BAD_REQUEST,
errorCount: errors.length,
errors,
};
}


let result = await this.createUserInDatabase(request, userCreateDto, cohortId);

let field_value_array = userCreateDto.fieldValues?.split("|");

let fieldData = {};
if (result && field_value_array?.length > 0) {
let userId = result?.userId;
for (let i = 0; i < field_value_array?.length; i++) {
let fieldValues = field_value_array[i].split(":");
fieldData = {
fieldId: fieldValues[0],
value: fieldValues[1]
}
let result = await this.updateCustomFields(userId, fieldData);
if (!result) {
return new ErrorResponseTypeOrm({
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
errorMessage: `Error is ${result}`,
});
if (userCreateDto.fieldValues) {
let field_value_array = userCreateDto.fieldValues.split("|");
if (result && field_value_array?.length > 0) {
let userId = result?.userId;
for (let i = 0; i < field_value_array?.length; i++) {
let fieldValues = field_value_array[i].split(":");
fieldData = {
fieldId: fieldValues[0],
value: fieldValues[1]
}
let result = await this.updateCustomFields(userId, fieldData);
if (!result) {
return new ErrorResponseTypeOrm({
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
errorMessage: `Error is ${result}`,
});
}
}
}
}
Expand All @@ -389,7 +448,7 @@ export class PostgresUserService {
} catch (e) {
return new ErrorResponseTypeOrm({
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
errorMessage: `Error is ${e}`,
errorMessage: `Error is ${e}`,
});
}
}
Expand All @@ -414,14 +473,14 @@ export class PostgresUserService {
user.name = userCreateDto?.name
user.role = userCreateDto?.role
user.mobile = Number(userCreateDto?.mobile) || null,
user.tenantId = userCreateDto?.tenantId
user.tenantId = null
user.createdBy = userCreateDto?.createdBy
user.updatedBy = userCreateDto?.updatedBy
user.userId = userCreateDto?.userId,
user.state = userCreateDto?.state,
user.district = userCreateDto?.district,
user.address = userCreateDto?.address,
user.pincode = userCreateDto?.pincode
user.state = userCreateDto?.state,
user.district = userCreateDto?.district,
user.address = userCreateDto?.address,
user.pincode = userCreateDto?.pincode

if (userCreateDto?.dob) {
user.dob = new Date(userCreateDto.dob);
Expand All @@ -432,16 +491,50 @@ export class PostgresUserService {
let cohortData = {
userId: result?.userId,
role: result?.role,
// createdBy:result?.userId,
// updatedBy:result?.userId,
tenantId: result?.tenantId,
cohortId: cohortId
}
await this.addCohortMember(cohortData);

let tenantsData = {
userId: result?.userId,
tenantIds: userCreateDto?.tenantId,
}
await this.assignUserToTenant(tenantsData, request);
}
return result;
}

async assignUserToTenant(tenantsData, request) {
try {
const tenantIds = tenantsData.tenantIds;
const userId = tenantsData.userId;
let result = [];
let errors = [];

for (const tenantId of tenantIds) {
const data = await this.userTenantMappingRepository.save({
userId: userId,
tenantId: tenantId,
createdBy: request['user'].userId,
updatedBy: request['user'].userId
})
}
} catch (error) {
throw new Error(error)
}
}

public async validateUserTenantMapping(userId: string, tenantId: string) {
// check if tenant exists
const tenantExist = await this.tenantsRepository.findOne({ where: { tenantId: tenantId } });
if (!tenantExist) {
return false
} else {
return true
}
}

async addCohortMember(cohortData) {
try {
let result = await this.cohortMemberRepository.insert(cohortData);
Expand Down Expand Up @@ -566,6 +659,19 @@ export class PostgresUserService {
}
}

public async validateFieldValues(field_value_array: string[]) {
let encounteredKeys = []
for (const fieldValue of field_value_array) {
const [fieldId] = fieldValue.split(":").map(value => value.trim());

if (encounteredKeys.includes(fieldId)) {
return false
}
encounteredKeys.push(fieldId);

};
}

}


Expand Down
Loading

0 comments on commit 57ba955

Please sign in to comment.