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

Added roleSetCacheModule and added cache invalidation on invitation / application removal #4955

Merged
merged 13 commits into from
Feb 20, 2025
Merged
2 changes: 2 additions & 0 deletions src/domain/access/application/application.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { ApplicationAuthorizationService } from './application.service.authoriza
import { ApplicationResolverMutations } from './application.resolver.mutations';
import { ApplicationLifecycleResolverFields } from './application.resolver.fields.lifecycle';
import { ApplicationLifecycleService } from './application.service.lifecycle';
import { RoleSetCacheModule } from '../role-set/role.set.service.cache.module';

@Module({
imports: [
Expand All @@ -21,6 +22,7 @@ import { ApplicationLifecycleService } from './application.service.lifecycle';
LifecycleModule,
UserModule,
TypeOrmModule.forFeature([Application]),
RoleSetCacheModule,
],
providers: [
ApplicationService,
Expand Down
14 changes: 13 additions & 1 deletion src/domain/access/application/application.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { IQuestion } from '@domain/common/question/question.interface';
import { IContributor } from '../../community/contributor/contributor.interface';
import { AuthorizationPolicyType } from '@common/enums/authorization.policy.type';
import { ApplicationLifecycleService } from './application.service.lifecycle';
import { RoleSetCacheService } from '../role-set/role.set.service.cache';

@Injectable()
export class ApplicationService {
Expand All @@ -34,6 +35,7 @@ export class ApplicationService {
private lifecycleService: LifecycleService,
private applicationLifecycleService: ApplicationLifecycleService,
private nvpService: NVPService,
private roleSetCacheService: RoleSetCacheService,
@Inject(WINSTON_MODULE_NEST_PROVIDER) private readonly logger: LoggerService
) {}

Expand All @@ -60,7 +62,9 @@ export class ApplicationService {
deleteData: DeleteApplicationInput
): Promise<IApplication> {
const applicationID = deleteData.ID;
const application = await this.getApplicationOrFail(applicationID);
const application = await this.getApplicationOrFail(applicationID, {
relations: { roleSet: true, user: true },
});
if (application.questions) {
for (const question of application.questions) {
await this.nvpService.removeNVP(question.id);
Expand All @@ -75,6 +79,14 @@ export class ApplicationService {
application as Application
);
result.id = applicationID;

if (application.user?.id && application.roleSet?.id) {
await this.roleSetCacheService.deleteOpenApplicationFromCache(
application.user?.id,
application.roleSet?.id
);
}

return result;
}

Expand Down
2 changes: 2 additions & 0 deletions src/domain/access/invitation/invitation.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { InvitationLifecycleService } from './invitation.service.lifecycle';
import { AccountLookupModule } from '@domain/space/account.lookup/account.lookup.module';
import { VirtualContributorLookupModule } from '@domain/community/virtual-contributor-lookup/virtual.contributor.lookup.module';
import { UserLookupModule } from '@domain/community/user-lookup/user.lookup.module';
import { RoleSetCacheModule } from '../role-set/role.set.service.cache.module';

@Module({
imports: [
Expand All @@ -25,6 +26,7 @@ import { UserLookupModule } from '@domain/community/user-lookup/user.lookup.modu
UserLookupModule,
AccountLookupModule,
TypeOrmModule.forFeature([Invitation]),
RoleSetCacheModule,
],
providers: [
InvitationService,
Expand Down
16 changes: 15 additions & 1 deletion src/domain/access/invitation/invitation.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { IContributor } from '@domain/community/contributor/contributor.interfac
import { IUser } from '@domain/community/user/user.interface';
import { InvitationLifecycleService } from './invitation.service.lifecycle';
import { UserLookupService } from '@domain/community/user-lookup/user.lookup.service';
import { RoleSetCacheService } from '../role-set/role.set.service.cache';

@Injectable()
export class InvitationService {
Expand All @@ -35,6 +36,7 @@ export class InvitationService {
private contributorService: ContributorService,
private lifecycleService: LifecycleService,
private invitationLifecycleService: InvitationLifecycleService,
private roleSetCacheService: RoleSetCacheService,
@Inject(WINSTON_MODULE_NEST_PROVIDER) private readonly logger: LoggerService
) {}

Expand Down Expand Up @@ -62,7 +64,11 @@ export class InvitationService {
deleteData: DeleteInvitationInput
): Promise<IInvitation> {
const invitationID = deleteData.ID;
const invitation = await this.getInvitationOrFail(invitationID);
const invitation = await this.getInvitationOrFail(invitationID, {
relations: {
roleSet: true,
},
});
await this.lifecycleService.deleteLifecycle(invitation.lifecycle.id);

if (invitation.authorization)
Expand All @@ -72,6 +78,14 @@ export class InvitationService {
invitation as Invitation
);
result.id = invitationID;

if (invitation.createdBy && invitation.roleSet) {
await this.roleSetCacheService.deleteOpenInvitationFromCache(
invitation.createdBy,
invitation.roleSet.id
);
}

return result;
}

Expand Down
4 changes: 2 additions & 2 deletions src/domain/access/role-set/role.set.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { OrganizationLookupModule } from '@domain/community/organization-lookup/
import { UserModule } from '@domain/community/user/user.module';
import { RoleSetAgentRolesDataLoader } from './role.set.data.loaders.agent.roles';
import { RoleSetMembershipStatusDataLoader } from './role.set.data.loader.membership.status';
import { RoleSetCacheService } from './role.set.service.cache';
import { RoleSetCacheModule } from './role.set.service.cache.module';

@Module({
imports: [
Expand All @@ -61,6 +61,7 @@ import { RoleSetCacheService } from './role.set.service.cache';
LifecycleModule,
CommunityCommunicationModule,
TypeOrmModule.forFeature([RoleSet]),
RoleSetCacheModule,
],
providers: [
RoleSetService,
Expand All @@ -74,7 +75,6 @@ import { RoleSetCacheService } from './role.set.service.cache';
RoleSetServiceLifecycleInvitation,
RoleSetAgentRolesDataLoader,
RoleSetMembershipStatusDataLoader,
RoleSetCacheService,
],
exports: [RoleSetService, RoleSetAuthorizationService, RoleSetLicenseService],
})
Expand Down
88 changes: 84 additions & 4 deletions src/domain/access/role-set/role.set.resolver.mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ import { AccountLookupService } from '@domain/space/account.lookup/account.looku
import { UserLookupService } from '@domain/community/user-lookup/user.lookup.service';
import { RoleSetType } from '@common/enums/role.set.type';
import { ValidationException } from '@common/exceptions';
import { RoleSetCacheService } from './role.set.service.cache';

@Resolver()
export class RoleSetResolverMutations {
Expand All @@ -94,6 +95,7 @@ export class RoleSetResolverMutations {
private platformInvitationService: PlatformInvitationService,
private licenseService: LicenseService,
private lifecycleService: LifecycleService,
private roleSetCacheService: RoleSetCacheService,
@Inject(WINSTON_MODULE_NEST_PROVIDER) private readonly logger: LoggerService
) {}

Expand Down Expand Up @@ -462,6 +464,10 @@ export class RoleSetResolverMutations {
@CurrentUser() agentInfo: AgentInfo,
@Args('applicationData') applicationData: ApplyForEntryRoleOnRoleSetInput
): Promise<IApplication> {
await this.roleSetCacheService.deleteOpenApplicationFromCache(
agentInfo.userID,
applicationData.roleSetID
);
const roleSet = await this.roleSetService.getRoleSetOrFail(
applicationData.roleSetID,
{
Expand Down Expand Up @@ -534,6 +540,10 @@ export class RoleSetResolverMutations {
@Args('invitationData')
invitationData: InviteForEntryRoleOnRoleSetInput
): Promise<IInvitation[]> {
await this.roleSetCacheService.deleteOpenInvitationFromCache(
agentInfo.userID,
invitationData.roleSetID
);
const roleSet = await this.roleSetService.getRoleSetOrFail(
invitationData.roleSetID,
{
Expand Down Expand Up @@ -830,9 +840,14 @@ export class RoleSetResolverMutations {

// Reload to trigger actions
application = await this.applicationService.getApplicationOrFail(
eventData.applicationID
eventData.applicationID,
{
relations: {
roleSet: true,
},
}
);
const applicationState = this.lifecycleService.getState(
let applicationState = this.lifecycleService.getState(
application.lifecycle,
this.roleSetServiceLifecycleApplication.getApplicationMachine()
);
Expand All @@ -852,6 +867,25 @@ export class RoleSetResolverMutations {
});
}

if (agentInfo.userID && application.roleSet) {
applicationState = this.lifecycleService.getState(
application.lifecycle,
this.roleSetServiceLifecycleApplication.getApplicationMachine()
);
const isMember = applicationState === ApplicationLifecycleState.APPROVED;
if (agentInfo.userID && application.roleSet) {
await this.roleSetCacheService.deleteOpenApplicationFromCache(
agentInfo.userID,
application.roleSet?.id
);
await this.roleSetCacheService.setAgentIsMemberCache(
agentInfo.agentID,
application.roleSet?.id,
isMember
);
}
}

return await this.applicationService.getApplicationOrFail(
eventData.applicationID
);
Expand All @@ -867,7 +901,12 @@ export class RoleSetResolverMutations {
@CurrentUser() agentInfo: AgentInfo
): Promise<IInvitation> {
let invitation = await this.invitationService.getInvitationOrFail(
eventData.invitationID
eventData.invitationID,
{
relations: {
roleSet: true,
},
}
);
this.authorizationService.grantAccessOrFail(
agentInfo,
Expand All @@ -894,10 +933,16 @@ export class RoleSetResolverMutations {
invitation = await this.invitationService.getInvitationOrFail(
eventData.invitationID
);
const invitationState = await this.invitationService.getLifecycleState(
let invitationState = await this.invitationService.getLifecycleState(
invitation.id
);
if (invitationState === InvitationLifecycleState.ACCEPTING) {
if (invitation.roleSet && agentInfo.userID) {
await this.roleSetCacheService.deleteOpenInvitationFromCache(
agentInfo.userID,
invitation.roleSet.id
);
}
await this.roleSetService.acceptInvitationToRoleSet(
eventData.invitationID,
agentInfo
Expand All @@ -911,6 +956,41 @@ export class RoleSetResolverMutations {
});
}

if (agentInfo.userID && invitation.roleSet) {
const isOpenInvitation =
await this.invitationService.isFinalizedInvitation(invitation.id);
invitationState = this.lifecycleService.getState(
invitation.lifecycle,
this.roleSetServiceLifecycleApplication.getApplicationMachine()
);
const isMember = invitationState === ApplicationLifecycleState.APPROVED;
if (agentInfo.userID && invitation.roleSet) {
if (!isOpenInvitation) {
await this.roleSetCacheService.deleteOpenInvitationFromCache(
agentInfo.userID,
invitation.roleSet?.id
);
}
await this.roleSetCacheService.setAgentIsMemberCache(
agentInfo.agentID,
invitation.roleSet?.id,
isMember
);
}
}

if (agentInfo.userID && invitation.roleSet) {
await this.roleSetCacheService.deleteOpenApplicationFromCache(
agentInfo.userID,
invitation.roleSet?.id
);
await this.roleSetCacheService.setAgentIsMemberCache(
agentInfo.agentID,
invitation.roleSet?.id,
true
);
}

return await this.invitationService.getInvitationOrFail(invitation.id);
}

Expand Down
9 changes: 9 additions & 0 deletions src/domain/access/role-set/role.set.service.cache.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { RoleSetCacheService } from './role.set.service.cache';

@Module({
imports: [],
providers: [RoleSetCacheService],
exports: [RoleSetCacheService],
})
export class RoleSetCacheModule {}
22 changes: 21 additions & 1 deletion src/domain/access/role-set/role.set.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,16 @@ export class RoleSetService {
agent,
RoleSetContributorType.USER
);

await this.roleSetCacheService.deleteOpenApplicationFromCache(
userID,
roleSet.id
);
await this.roleSetCacheService.deleteOpenInvitationFromCache(
userID,
roleSet.id
);

switch (roleSet.type) {
case RoleSetType.SPACE: {
if (roleName === RoleName.ADMIN && parentRoleSet) {
Expand Down Expand Up @@ -726,6 +736,7 @@ export class RoleSetService {

await this.contributorAddedToRole(
user,
agent.id,
roleSet,
roleName,
agentInfo,
Expand All @@ -750,6 +761,7 @@ export class RoleSetService {
},
}
);

const contributorID = invitation.invitedContributorID;
const roleSet = invitation.roleSet;
if (!contributorID || !roleSet) {
Expand Down Expand Up @@ -875,6 +887,7 @@ export class RoleSetService {
}
private async contributorAddedToRole(
contributor: IContributor,
contributorAgentId: string,
roleSet: IRoleSet,
role: RoleName,
agentInfo?: AgentInfo,
Expand All @@ -891,11 +904,17 @@ export class RoleSetService {
await this.communityResolverService.getCommunicationForRoleSet(
roleSet.id
);
this.communityCommunicationService.addMemberToCommunication(
await this.communityCommunicationService.addMemberToCommunication(
communication,
contributor
);

await this.roleSetCacheService.setMembershipStatusCache(
contributorAgentId,
roleSet.id,
CommunityMembershipStatus.MEMBER
);

if (agentInfo) {
await this.roleSetEventsService.registerCommunityNewMemberActivity(
roleSet,
Expand Down Expand Up @@ -957,6 +976,7 @@ export class RoleSetService {

await this.contributorAddedToRole(
virtualContributor,
agent.id,
roleSet,
roleType,
agentInfo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,13 @@ export class LookupByNameResolverFields {
@Args('NAMEID', { type: () => NameID }) nameid: string
): Promise<ISpace> {
const space = await this.spaceService.getSpaceByNameIdOrFail(nameid);
this.authorizationService.grantAccessOrFail(
agentInfo,
space.authorization,
AuthorizationPrivilege.READ_ABOUT,
`lookup L0 Space by NameID: ${nameid}`
);
//toDo fix this, but for now that is uniform with lookupByID
// this.authorizationService.grantAccessOrFail(
// agentInfo,
// space.authorization,
// AuthorizationPrivilege.READ_ABOUT,
// `lookup L0 Space by NameID: ${nameid}`
// );

return space;
}
Expand Down