Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: limit 10 organizations per user #743

Merged
merged 9 commits into from
Jun 3, 2024
10 changes: 10 additions & 0 deletions apps/organization/repositories/organization.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,16 @@ export class OrganizationRepository {
}
}

async userOrganizationCount(userId: string): Promise<number> {
const getOrgCount = await this.prisma.organisation.count({
where: {
userOrgRoles: {
some: { userId }
}
}
});
return getOrgCount;
}
/**
*
* @param name
Expand Down
14 changes: 14 additions & 0 deletions apps/organization/src/organization.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,20 @@ export class OrganizationController {
const { userId, pageNumber, pageSize, search, role } = payload;
return this.organizationService.getOrganizations(userId, pageNumber, pageSize, search, role);
}
/**
* Description: get organization count
* @param
* @returns Get created organization details
*/
@MessagePattern({ cmd: 'get-organizations-count' })
async countTotalOrgs(
@Body() payload: { userId: string}
): Promise<number> {

const { userId } = payload;

return this.organizationService.countTotalOrgs(userId);
}

/**
* @returns Get public organization details
Expand Down
29 changes: 29 additions & 0 deletions apps/organization/src/organization.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
import { ClientCredentialTokenPayloadDto } from '@credebl/client-registration/dtos/client-credential-token-payload.dto';
import { IAccessTokenData } from '@credebl/common/interfaces/interface';
import { IClientRoles } from '@credebl/client-registration/interfaces/client.interface';
import { toNumber } from '@credebl/common/cast.helper';
@Injectable()
export class OrganizationService {
constructor(
Expand Down Expand Up @@ -74,6 +75,12 @@ export class OrganizationService {
keycloakUserId: string
): Promise<organisation> {
try {
const userOrgCount = await this.organizationRepository.userOrganizationCount(userId);

if (userOrgCount >= toNumber(`${process.env.MAX_ORG_LIMIT}`)) {
throw new BadRequestException(ResponseMessages.organisation.error.MaximumOrgsLimit);
}

const organizationExist = await this.organizationRepository.checkOrganizationNameExist(createOrgDto.name);

if (organizationExist) {
Expand All @@ -99,6 +106,7 @@ export class OrganizationService {
createOrgDto.logo = '';
}


const organizationDetails = await this.organizationRepository.createOrganization(createOrgDto);

// To return selective object data
Expand Down Expand Up @@ -516,6 +524,20 @@ export class OrganizationService {

return connectionInvitationData;
}

async countTotalOrgs(
userId: string

): Promise<number> {
try {

const getOrgs = await this.organizationRepository.userOrganizationCount(userId);
return getOrgs;
} catch (error) {
this.logger.error(`In fetch getOrganizations : ${JSON.stringify(error)}`);
throw new RpcException(error.response ? error.response : error);
}
}

/**
* @returns Get created organizations details
Expand Down Expand Up @@ -1052,6 +1074,13 @@ export class OrganizationService {
const { orgId, status, invitationId, userId, keycloakUserId, email } = payload;
const invitation = await this.organizationRepository.getInvitationById(String(invitationId));

if (Invitation.ACCEPTED === payload.status) {
const userOrgCount = await this.organizationRepository.userOrganizationCount(userId);

if (userOrgCount >= toNumber(`${process.env.MAX_ORG_LIMIT}`)) {
throw new BadRequestException(ResponseMessages.organisation.error.MaximumOrgsLimit);
}
}
if (!invitation || (invitation && invitation.email !== email)) {
throw new NotFoundException(ResponseMessages.user.error.invitationNotFound);
}
Expand Down
32 changes: 31 additions & 1 deletion apps/user/src/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import { UserActivityService } from '@credebl/user-activity';
import { SupabaseService } from '@credebl/supabase';
import { UserDevicesRepository } from '../repositories/user-device.repository';
import { v4 as uuidv4 } from 'uuid';
import { EcosystemConfigSettings, UserCertificateId } from '@credebl/enum/enum';
import { EcosystemConfigSettings, Invitation, UserCertificateId } from '@credebl/enum/enum';
import { WinnerTemplate } from '../templates/winner-template';
import { ParticipantTemplate } from '../templates/participant-template';
import { ArbiterTemplate } from '../templates/arbiter-template';
Expand All @@ -60,6 +60,7 @@ import { IUsersActivity } from 'libs/user-activity/interface';
import { ISendVerificationEmail, ISignInUser, IVerifyUserEmail, IUserInvitations, IResetPasswordResponse } from '@credebl/common/interfaces/user.interface';
import { AddPasskeyDetailsDto } from 'apps/api-gateway/src/user/dto/add-user.dto';
import { URLUserResetPasswordTemplate } from '../templates/reset-password-template';
import { toNumber } from '@credebl/common/cast.helper';

@Injectable()
export class UserService {
Expand Down Expand Up @@ -823,13 +824,42 @@ export class UserService {
async acceptRejectInvitations(acceptRejectInvitation: AcceptRejectInvitationDto, userId: string): Promise<IUserInvitations> {
try {
const userData = await this.userRepository.getUserById(userId);

if (Invitation.ACCEPTED === acceptRejectInvitation.status) {
const payload = {userId};
const TotalOrgs = await this._getTotalOrgCount(payload);

if (TotalOrgs >= toNumber(`${process.env.MAX_ORG_LIMIT}`)) {
throw new BadRequestException(ResponseMessages.user.error.userOrgsLimit);
}
}
return this.fetchInvitationsStatus(acceptRejectInvitation, userData.keycloakUserId, userData.email, userId);
} catch (error) {
this.logger.error(`acceptRejectInvitations: ${error}`);
throw new RpcException(error.response ? error.response : error);
}
}

async _getTotalOrgCount(payload): Promise<number> {
const pattern = { cmd: 'get-organizations-count' };

const getOrganizationCount = await this.userServiceProxy
.send(pattern, payload)
.toPromise()
.catch((error) => {
this.logger.error(`catch: ${JSON.stringify(error)}`);
throw new HttpException(
{
status: error.status,
error: error.message
},
error.status
);
});

return getOrganizationCount;
}

async shareUserCertificate(shareUserCertificate: IShareUserCertificate): Promise<string> {

const attributeArray = [];
Expand Down
6 changes: 4 additions & 2 deletions libs/common/src/response-messages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ export const ResponseMessages = {
resetPasswordLink: 'Unable to create reset password token',
invalidResetLink: 'Invalid or expired reset password link',
invalidAccessToken: 'Authentication failed',
invalidRefreshToken: 'Invalid refreshToken provided'
invalidRefreshToken: 'Invalid refreshToken provided',
userOrgsLimit:'Limit reached: You can be associated with or create maximum 10 organizations.'
}
},
organisation: {
Expand Down Expand Up @@ -117,7 +118,8 @@ export const ResponseMessages = {
orgDoesNotMatch: 'Organization does not match',
invalidClient: 'Invalid client credentials',
primaryDid: 'This DID is already set to primary DID',
didNotFound: 'DID does not exist in organiation'
didNotFound: 'DID does not exist in organiation',
MaximumOrgsLimit:'Limit reached: You can be associated with or create maximum 10 organizations.'
}
},

Expand Down