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

RoleSet + Role: shareable role management #4544

Merged
merged 54 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
6db71cd
initial pass at having roles data driven
techsmyth Sep 15, 2024
01ac150
refactor community functionality to use RoleManager module
techsmyth Sep 15, 2024
37b43da
renamed RoleManager to RoleSet
techsmyth Sep 16, 2024
4874102
tidied up module imports RoleSet
techsmyth Sep 16, 2024
8551ee6
remoed circular dependencies
techsmyth Sep 16, 2024
88a3bbf
moved application, invitation to be under access namespace
techsmyth Sep 16, 2024
f938896
removed community role module + put parts in other locations
techsmyth Sep 16, 2024
9b97770
addressed module imports for RoleSet
techsmyth Sep 16, 2024
94895a8
renamed DTOs related to RoleSet
techsmyth Sep 16, 2024
098fe4c
revert testing changes
techsmyth Sep 17, 2024
3a2a1fe
merge from develop
techsmyth Sep 20, 2024
ec4b232
Merge branch 'develop' into roles
techsmyth Sep 20, 2024
2bd55f3
made retrieval of credentials for roles async; fixed issue with modul…
techsmyth Sep 20, 2024
2105786
first pass at migration
techsmyth Sep 20, 2024
5c1957d
remove an additional index
techsmyth Sep 20, 2024
67d8ef9
parent role not required if the community does not have a parent
techsmyth Sep 20, 2024
16c2be0
fixes to api as work through client codegen fixes
techsmyth Sep 21, 2024
a54975f
fixes to api as work through client codegen fixes
techsmyth Sep 21, 2024
2e7d6a1
tidied up DTO fields for RoleSet mgmt
techsmyth Sep 21, 2024
57496f7
added base role type to roleset
techsmyth Sep 22, 2024
1d6c304
moved my roles / membership status to roleset as that is more logical
techsmyth Sep 22, 2024
bac4ae4
added back on communication addition / removal on role assignment
techsmyth Sep 22, 2024
d4e00a8
added back in triggering of new member events
techsmyth Sep 22, 2024
8abce79
moved join to be on RoleSet; renamed base role to entry role
techsmyth Sep 22, 2024
58093f2
tidied up namings after chat with Carlos
techsmyth Sep 23, 2024
61bbcb9
Merge branch 'develop' into roles
ccanos Sep 23, 2024
9ef4ffb
Migration fix
ccanos Sep 24, 2024
6f69d7d
set roleset hierarchy
techsmyth Sep 24, 2024
0fdae8e
fixed lookup of applications for a given roleset
techsmyth Sep 24, 2024
5dbf4c8
fixed a couple of issues with creating space
techsmyth Sep 24, 2024
3e35777
removed enabled on contributor role policy
techsmyth Sep 24, 2024
dd8c7d0
updated defaults
techsmyth Sep 24, 2024
d78f77f
updefault for space level requires parent role
techsmyth Sep 24, 2024
7955340
fixed setting of resourceID on credentials in new RoleSet
techsmyth Sep 25, 2024
c90465c
removed community-parentCommunity relationship; fixed issues with cre…
techsmyth Sep 25, 2024
bd77ca3
tidied up authorization between community + roleset
techsmyth Sep 25, 2024
8e031da
fixed deletion of space
techsmyth Sep 25, 2024
f851685
fix roles test spec
techsmyth Sep 25, 2024
7800a20
additional error fixed
techsmyth Sep 25, 2024
116c0e3
Fix migration foreign key
ccanos Sep 25, 2024
7236c1e
streamline logging of events; additional info when cannot delete space
techsmyth Sep 25, 2024
3dc3ebc
added DTOs used for roleset to validation
techsmyth Sep 25, 2024
487ebc0
updated access logic for RoleSet; split RoleSet field resolver into t…
techsmyth Sep 26, 2024
20fcf54
fix test import
techsmyth Sep 26, 2024
06e4e19
tidy up error messages
techsmyth Sep 26, 2024
fe801b7
fixed auth reset on RoleSet
techsmyth Sep 26, 2024
4b7c2f7
fix error messages; updated error messages
techsmyth Sep 27, 2024
9332966
Merge remote-tracking branch 'origin/develop' into roles
ccanos Sep 27, 2024
3eccb5d
Fix something about whiteboard templates
ccanos Sep 27, 2024
c8cfe1b
Fix communityId instead of roleSetId
ccanos Sep 27, 2024
084eeff
Merge branch 'develop' into roles
ccanos Sep 30, 2024
74c8c2a
fix build
ccanos Oct 1, 2024
4420b5d
Fix infinite recursion call
ccanos Oct 1, 2024
627a345
Fix roleSet authorization empty credentialsRules issue
ccanos Oct 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/common/enums/alkemio.error.status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ export enum AlkemioErrorStatus {
PAGINATION_INPUT_OUT_OF_BOUND = 'PAGINATION_INPUT_OUT_OF_BOUND',
PAGINATION_NOT_FOUND = 'PAGINATION_NOT_FOUND',
PAGINATION_PARAM_NOT_FOUND = 'PAGINATION_PARAM_NOT_FOUND',
COMMUNITY_POLICY_ROLE_LIMITS_VIOLATED = 'COMMUNITY_POLICY_ROLE_LIMITS_VIOLATED',
COMMUNITY_MEMBERSHIP = 'COMMUNITY_MEMBERSHIP',
COMMUNITY_INVITATION = 'COMMUNITY_INVITATION',
ROLE_SET_POLICY_ROLE_LIMITS_VIOLATED = 'COMMUNITY_POLICY_ROLE_LIMITS_VIOLATED',
ROLE_SET_MEMBERSHIP = 'COMMUNITY_MEMBERSHIP',
ROLE_SET_INVITATION = 'COMMUNITY_INVITATION',
LOGIN_FLOW_INIT = 'LOGIN_FLOW_INIT',
LOGIN_FLOW = 'LOGIN_FLOW',
SESSION_EXTEND = 'SESSION_EXTEND',
Expand Down
1 change: 1 addition & 0 deletions src/common/enums/authorization.policy.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export enum AuthorizationPolicyType {
ROOM = 'room',
AI_PERSONA = 'ai-persona',
APPLICATION = 'application',
ROLE_SET = 'role-set',
COMMUNITY = 'community',
COMMUNITY_GUIDELINES = 'community-guidelines',
INVITATION = 'invitation',
Expand Down
6 changes: 3 additions & 3 deletions src/common/enums/community.role.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { registerEnumType } from '@nestjs/graphql';

export enum CommunityRole {
export enum CommunityRoleType {
MEMBER = 'member',
LEAD = 'lead',
ADMIN = 'admin',
}

registerEnumType(CommunityRole, {
name: 'CommunityRole',
registerEnumType(CommunityRoleType, {
name: 'CommunityRoleType',
});
2 changes: 1 addition & 1 deletion src/common/exceptions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export * from './relationship.not.found.exception';
export * from './validation.exception';
export * from './registration.exception';
export * from './matrix.entity.not.found.exception';
export * from './community.policy.role.limits.exception';
export * from './role.set.policy.role.limits.exception';
export * from './subscription';

export * from './pagination';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { LogContext, AlkemioErrorStatus } from '@common/enums';
import { BaseException } from './base.exception';

export class CommunityInvitationException extends BaseException {
export class RoleSetInvitationException extends BaseException {
constructor(error: string, context: LogContext, code?: AlkemioErrorStatus) {
super(error, context, code ?? AlkemioErrorStatus.COMMUNITY_INVITATION);
super(error, context, code ?? AlkemioErrorStatus.ROLE_SET_INVITATION);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { LogContext, AlkemioErrorStatus } from '@common/enums';
import { BaseException } from './base.exception';

export class CommunityMembershipException extends BaseException {
export class RoleSetMembershipException extends BaseException {
constructor(error: string, context: LogContext, code?: AlkemioErrorStatus) {
super(error, context, code ?? AlkemioErrorStatus.COMMUNITY_MEMBERSHIP);
super(error, context, code ?? AlkemioErrorStatus.ROLE_SET_MEMBERSHIP);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { LogContext, AlkemioErrorStatus } from '@common/enums';
import { BaseException } from './base.exception';

export class CommunityPolicyRoleLimitsException extends BaseException {
export class RoleSetPolicyRoleLimitsException extends BaseException {
constructor(error: string, context: LogContext, code?: AlkemioErrorStatus) {
super(
error,
context,
code ?? AlkemioErrorStatus.COMMUNITY_POLICY_ROLE_LIMITS_VIOLATED
code ?? AlkemioErrorStatus.ROLE_SET_POLICY_ROLE_LIMITS_VIOLATED
);
}
}
1 change: 1 addition & 0 deletions src/common/utils/stringify.util.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export function stringifyWithoutAuthorizationMetaInfo(object: any): string {
return JSON.stringify(object, (key, value) => {
if (
key === 'credentials' ||
key === 'authorization' ||
key === 'createdDate' ||
key === 'updatedDate' ||
Expand Down
6 changes: 3 additions & 3 deletions src/core/authorization/authorization.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class AuthorizationService {

if (this.isAccessGranted(agentInfo, auth, privilegeRequired)) return true;

const errorMsg = `Authorization: unable to grant '${privilegeRequired}' privilege: ${msg} user: ${agentInfo.userID} on authorization of type '${auth.type}'`;
const errorMsg = `Authorization: unable to grant '${privilegeRequired}' privilege: ${msg} user: ${agentInfo.userID} on authorization ${auth.id} of type '${auth.type}'`;
this.logCredentialCheckFailDetails(errorMsg, agentInfo, auth);
// If you get to here then no match was found
throw new ForbiddenAuthorizationPolicyException(
Expand Down Expand Up @@ -130,7 +130,7 @@ export class AuthorizationService {
for (const privilege of rule.grantedPrivileges) {
if (privilege === privilegeRequired) {
this.logger.verbose?.(
`[CredentialRule] Granted privilege '${privilegeRequired}' using rule '${rule.name}'`,
`[CredentialRule] Granted privilege '${privilegeRequired}' using rule '${rule.name}' on authorization ${authorization.id}`,
LogContext.AUTH_POLICY
);
return true;
Expand Down Expand Up @@ -172,7 +172,7 @@ export class AuthorizationService {
if (grantedPrivileges.includes(rule.sourcePrivilege)) {
if (rule.grantedPrivileges.includes(privilegeRequired)) {
this.logger.verbose?.(
`[PrivilegeRule] Granted privilege '${privilegeRequired}' using privilege rule '${rule.name}'`,
`[PrivilegeRule] Granted privilege '${privilegeRequired}' using privilege rule '${rule.name}' on authorization ${authorization.id}`,
LogContext.AUTH_POLICY
);
return true;
Expand Down
35 changes: 25 additions & 10 deletions src/core/validation/handlers/base/base.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
CreateTagsetOnProfileInput,
UpdateProfileInput,
} from '@domain/common/profile/dto';
import { ApplicationEventInput } from '@domain/community/application/dto/application.dto.event';
import { ApplicationEventInput } from '@domain/access/application/dto/application.dto.event';
import { OrganizationVerificationEventInput } from '@domain/community/organization-verification/dto/organization.verification.dto.event';
import { RoomSendMessageInput } from '@domain/communication/room/dto/room.dto.send.message';
import { UpdatePostInput } from '@domain/collaboration/post/dto/post.dto.update';
Expand All @@ -35,7 +35,6 @@ import { SendMessageOnCalloutInput } from '@domain/collaboration/callout/dto/cal
import { CreateCalloutOnCollaborationInput } from '@domain/collaboration/collaboration/dto/collaboration.dto.create.callout';
import { CreateCalendarEventOnCalendarInput } from '@domain/timeline/calendar/dto/calendar.dto.create.event';
import { UpdateCalendarEventInput } from '@domain/timeline/event';
import { UpdateCommunityApplicationFormInput } from '@domain/community/community/dto/community.dto.update.application.form';
import { CreateTemplateOnTemplatesSetInput } from '@domain/template/templates-set/dto/templates.set.dto.create.template';
import { UpdateTemplateInput } from '@domain/template/template/dto/template.dto.update';
import { CreateDocumentInput } from '@domain/storage/document/dto/document.dto.create';
Expand Down Expand Up @@ -70,18 +69,38 @@ import { UpdateSpaceSettingsInput } from '@domain/space/space/dto/space.dto.upda
import { CreateAccountInput } from '@domain/space/account/dto';
import { UpdateCommunityGuidelinesInput } from '@domain/community/community-guidelines/dto/community.guidelines.dto.update';
import { ForumCreateDiscussionInput } from '@platform/forum/dto/forum.dto.create.discussion';
import { CommunityRoleApplyInput } from '@domain/community/community-role/dto/community.role.dto.apply';
import { CreateInvitationForContributorsOnCommunityInput } from '@domain/community/community-role/dto/community.role.dto.invite.contributor';
import { CreatePlatformInvitationOnCommunityInput } from '@domain/community/community-role/dto/community.role.dto.platform.invitation.community';
import { CreateCollaborationOnSpaceInput } from '@domain/space/space/dto/space.dto.create.collaboration';
import { UpdateInnovationFlowEntityInput } from '@domain/collaboration/innovation-flow/dto/innovation.flow.dto.update.entity';
import { InviteNewContributorForRoleOnRoleSetInput } from '@domain/access/role-set/dto/role.set.dto.platform.invitation.community';
import { ApplyForEntryRoleOnRoleSetInput } from '@domain/access/role-set/dto/role.set.dto.entry.role.apply';
import { InviteForEntryRoleOnRoleSetInput } from '@domain/access/role-set/dto/role.set.dto.entry.role.invite';
import { AssignRoleOnRoleSetToUserInput } from '@domain/access/role-set/dto/role.set.dto.role.assign.user';
import { AssignRoleOnRoleSetToOrganizationInput } from '@domain/access/role-set/dto/role.set.dto.role.assign.organization';
import { AssignRoleOnRoleSetToVirtualContributorInput } from '@domain/access/role-set/dto/role.set.dto.role.assign.virtual';
import { RemoveRoleOnRoleSetFromUserInput } from '@domain/access/role-set/dto/role.set.dto.role.remove.user';
import { RemoveRoleOnRoleSetFromOrganizationInput } from '@domain/access/role-set/dto/role.set.dto.role.remove.organization';
import { RemoveRoleOnRoleSetFromVirtualContributorInput } from '@domain/access/role-set/dto/role.set.dto.role.remove.virtual';
import { UpdateApplicationFormOnRoleSetInput } from '@domain/access/role-set/dto/role.set.dto.update.application.form';
import { JoinAsEntryRoleOnRoleSetInput } from '@domain/access/role-set/dto/role.set.dto.entry.role.join';
import { RolesUserInput } from '@services/api/roles/dto/roles.dto.input.user';

export class BaseHandler extends AbstractHandler {
public async handle(
value: any,
metatype: Function
): Promise<ValidationError[]> {
const types: Function[] = [
AssignRoleOnRoleSetToUserInput,
AssignRoleOnRoleSetToOrganizationInput,
AssignRoleOnRoleSetToVirtualContributorInput,
RemoveRoleOnRoleSetFromUserInput,
RemoveRoleOnRoleSetFromOrganizationInput,
RemoveRoleOnRoleSetFromVirtualContributorInput,
UpdateApplicationFormOnRoleSetInput,
JoinAsEntryRoleOnRoleSetInput,
ApplyForEntryRoleOnRoleSetInput,
RolesUserInput,
InviteForEntryRoleOnRoleSetInput,
InviteNewContributorForRoleOnRoleSetInput,
ApplicationEventInput,
UpdateInnovationFlowInput,
RoomSendMessageInput,
Expand Down Expand Up @@ -113,7 +132,6 @@ export class BaseHandler extends AbstractHandler {
UpdateCalloutContributionDefaultsInput,
UpdateCalloutContributionPolicyInput,
UpdateTemplateInput,
UpdateCommunityApplicationFormInput,
UpdateCommunityGuidelinesInput,
UpdateSpaceInput,
UpdateSpaceSettingsEntityInput,
Expand All @@ -131,9 +149,6 @@ export class BaseHandler extends AbstractHandler {
UpdateSpaceSettingsEntityInput,
UpdateSpaceSettingsInput,
VisualUploadImageInput,
CommunityRoleApplyInput,
CreateInvitationForContributorsOnCommunityInput,
CreatePlatformInvitationOnCommunityInput,
ForumCreateDiscussionInput,
SendMessageOnCalloutInput,
CreateCalloutOnCollaborationInput,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import {
ManyToOne,
OneToOne,
} from 'typeorm';
import { Community } from '@domain/community/community/community.entity';
import { Lifecycle } from '@domain/common/lifecycle/lifecycle.entity';
import { IApplication } from './application.interface';
import { NVP } from '@domain/common/nvp/nvp.entity';
import { User } from '@domain/community/user/user.entity';
import { AuthorizableEntity } from '@domain/common/entity/authorizable-entity';
import { IQuestion } from '@domain/common/question/question.interface';
import { RoleSet } from '@domain/access/role-set/role.set.entity';
@Entity()
export class Application extends AuthorizableEntity implements IApplication {
@OneToOne(() => Lifecycle, {
Expand All @@ -34,10 +34,10 @@ export class Application extends AuthorizableEntity implements IApplication {
})
user?: User;

@ManyToOne(() => Community, community => community.applications, {
@ManyToOne(() => RoleSet, manager => manager.applications, {
eager: false,
cascade: false,
onDelete: 'CASCADE',
})
community?: Community;
roleSet?: RoleSet;
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { ILifecycle } from '@domain/common/lifecycle/lifecycle.interface';
import { ICommunity } from '@domain/community/community/community.interface';
import { IUser } from '@domain/community/user/user.interface';
import { Field, ObjectType } from '@nestjs/graphql';
import { IAuthorizable } from '@domain/common/entity/authorizable-entity';
import { IQuestion } from '@domain/common/question/question.interface';
import { IRoleSet } from '@domain/access/role-set/role.set.interface';

@ObjectType('Application')
export abstract class IApplication extends IAuthorizable {
user?: IUser;

community?: ICommunity;
roleSet?: IRoleSet;

@Field(() => ILifecycle, { nullable: false })
lifecycle?: ILifecycle;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { LifecycleModule } from '@domain/common/lifecycle/lifecycle.module';
import { NVPModule } from '@domain/common/nvp/nvp.module';
import { Application } from '@domain/community/application';
import { ApplicationService } from '@domain/community/application/application.service';
import { Application } from '@domain/access/application';
import { ApplicationService } from '@domain/access/application/application.service';
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserModule } from '@domain/community/user/user.module';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { Resolver } from '@nestjs/graphql';
import { Parent, ResolveField } from '@nestjs/graphql';
import { ApplicationService } from './application.service';
import { AuthorizationPrivilege } from '@common/enums';
import { Application, IApplication } from '@domain/community/application';
import { Application, IApplication } from '@domain/access/application';
import { GraphqlGuard } from '@core/authorization';
import { AuthorizationAgentPrivilege, Profiling } from '@src/common/decorators';
import { IQuestion } from '@domain/common/question/question.interface';
import { IContributor } from '../contributor/contributor.interface';
import { IContributor } from '../../community/contributor/contributor.interface';

@Resolver(() => IApplication)
export class ApplicationResolverFields {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { UseGuards } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { CurrentUser } from '@src/common/decorators';
import { IApplication } from '@domain/community/application';
import { ApplicationService } from '@domain/community/application/application.service';
import { IApplication } from '@domain/access/application';
import { ApplicationService } from '@domain/access/application/application.service';
import { GraphqlGuard } from '@core/authorization';
import { AgentInfo } from '@core/authentication.agent.info/agent.info';
import { AuthorizationPrivilege } from '@common/enums';
Expand Down Expand Up @@ -31,7 +31,7 @@ export class ApplicationResolverMutations {
agentInfo,
application.authorization,
AuthorizationPrivilege.DELETE,
`delete application community: ${application.id}`
`delete application on RoleSet: ${application.id}`
);
return await this.applicationService.deleteApplication(deleteData);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { CreateApplicationInput } from '@domain/community/application';
import { CreateApplicationInput } from '@domain/access/application';
import {
Application,
IApplication,
DeleteApplicationInput,
} from '@domain/community/application';
} from '@domain/access/application';

import { Inject, Injectable, LoggerService } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
Expand All @@ -17,12 +17,12 @@ import { FindManyOptions, FindOneOptions, Repository } from 'typeorm';
import { NVPService } from '@domain/common/nvp/nvp.service';
import { UserService } from '@domain/community/user/user.service';
import { LifecycleService } from '@domain/common/lifecycle/lifecycle.service';
import { applicationLifecycleConfig } from '@domain/community/application/application.lifecycle.config';
import { applicationLifecycleConfig } from '@domain/access/application/application.lifecycle.config';
import { AuthorizationPolicy } from '@domain/common/authorization-policy';
import { AuthorizationPolicyService } from '@domain/common/authorization-policy/authorization.policy.service';
import { IQuestion } from '@domain/common/question/question.interface';
import { asyncFilter } from '@common/utils';
import { IContributor } from '../contributor/contributor.interface';
import { IContributor } from '../../community/contributor/contributor.interface';
import { AuthorizationPolicyType } from '@common/enums/authorization.policy.type';

@Injectable()
Expand Down Expand Up @@ -131,19 +131,18 @@ export class ApplicationService {

async findExistingApplications(
userID: string,
communityID: string
roleSetID: string
): Promise<IApplication[]> {
const existingApplications = await this.applicationRepository
.createQueryBuilder('application')
.leftJoinAndSelect('application.user', 'user')
.leftJoinAndSelect('application.community', 'community')
.where('user.id = :userID')
.andWhere('community.id = :communityID')
.setParameters({
userID: `${userID}`,
communityID: communityID,
})
.getMany();
const existingApplications = await this.applicationRepository.find({
where: {
user: { id: userID },
roleSet: { id: roleSetID },
},
relations: {
roleSet: true,
user: true,
},
});
if (existingApplications.length > 0) return existingApplications;
return [];
}
Expand All @@ -153,7 +152,7 @@ export class ApplicationService {
states: string[] = []
): Promise<IApplication[]> {
const findOpts: FindManyOptions<Application> = {
relations: { community: true },
relations: { roleSet: true },
where: { user: { id: userID } },
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { CreateNVPInput } from '@domain/common/nvp';
export class CreateApplicationInput {
userID!: string;

parentID!: string;
roleSetID!: string;

questions!: CreateNVPInput[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ export class CreateInvitationInput {

createdBy!: string;

communityID!: string;
roleSetID!: string;
invitedToParent!: boolean;
}
Loading