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

N21-1332 adjust group provisioning #4456

Merged
merged 5 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
60 changes: 59 additions & 1 deletion apps/server/src/modules/group/domain/group.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { RoleReference, UserDO } from '@shared/domain';
import { groupFactory, roleFactory, userDoFactory } from '@shared/testing';

import { ObjectId } from 'bson';
import { RoleReference, UserDO } from '@shared/domain';
import { Group } from './group';
import { GroupUser } from './group-user';

Expand Down Expand Up @@ -135,4 +135,62 @@ describe('Group (Domain Object)', () => {
});
});
});

describe('addUser', () => {
describe('when the user already exists in the group', () => {
const setup = () => {
const existingUser: GroupUser = new GroupUser({
userId: new ObjectId().toHexString(),
roleId: new ObjectId().toHexString(),
});
const group = groupFactory.build({
users: [existingUser],
});

return {
group,
existingUser,
};
};

it('should not add the user', () => {
const { group, existingUser } = setup();

group.addUser(existingUser);

expect(group.users.length).toEqual(1);
});
});

describe('when the user does not exist in the group', () => {
const setup = () => {
const newUser: GroupUser = new GroupUser({
userId: new ObjectId().toHexString(),
roleId: new ObjectId().toHexString(),
});
const group = groupFactory.build({
users: [
{
userId: new ObjectId().toHexString(),
roleId: new ObjectId().toHexString(),
},
],
});

return {
group,
newUser,
};
};

it('should add the user', () => {
const { group, newUser } = setup();

group.addUser(newUser);

expect(group.users).toContain(newUser);
expect(group.users.length).toEqual(2);
});
});
});
});
6 changes: 6 additions & 0 deletions apps/server/src/modules/group/domain/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,10 @@ export class Group extends DomainObject<GroupProps> {
isEmpty(): boolean {
return this.props.users.length === 0;
}

addUser(user: GroupUser): void {
if (!this.users.find((u) => u.userId === user.userId)) {
this.users.push(user);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@ describe('OidcProvisioningService', () => {

describe('when provision group', () => {
const setup = () => {
const group: Group = groupFactory.build();
const group: Group = groupFactory.build({ users: [] });
groupService.findByExternalSource.mockResolvedValue(group);

const school: LegacySchoolDo = legacySchoolDoFactory.build({ id: 'schoolId' });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,6 @@ export class OidcProvisioningService {
}

async provisionExternalGroup(externalGroup: ExternalGroupDto, systemId: EntityId): Promise<void> {
if (externalGroup.users.length === 0) {
return;
}

const existingGroup: Group | null = await this.groupService.findByExternalSource(
externalGroup.externalId,
systemId
Expand All @@ -145,6 +141,10 @@ export class OidcProvisioningService {

const users: GroupUser[] = await this.getFilteredGroupUsers(externalGroup, systemId);

if (!users.length) {
return;
}

const group: Group = new Group({
id: existingGroup ? existingGroup.id : new ObjectId().toHexString(),
name: externalGroup.name,
Expand All @@ -156,8 +156,9 @@ export class OidcProvisioningService {
organizationId,
validFrom: externalGroup.from,
validUntil: externalGroup.until,
users,
users: existingGroup ? existingGroup.users : [],
});
users.forEach((user: GroupUser) => group.addUser(user));

await this.groupService.save(group);
}
Expand All @@ -168,7 +169,7 @@ export class OidcProvisioningService {
const user: UserDO | null = await this.userService.findByExternalId(externalGroupUser.externalUserId, systemId);
const roles: RoleDto[] = await this.roleService.findByNames([externalGroupUser.roleName]);

if (!user || !user.id || roles.length !== 1 || !roles[0].id) {
if (!user?.id || roles.length !== 1 || !roles[0].id) {
this.logger.info(new UserForGroupNotFoundLoggable(externalGroupUser));
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@
const setup = () => {
const { sanisResponse } = setupSanisResponse();
const personenkontext: SanisPersonenkontextResponse = sanisResponse.personenkontexte[0];
const group: SanisGruppenResponse = personenkontext.gruppen![0];

Check warning on line 152 in apps/server/src/modules/provisioning/strategy/sanis/sanis-response.mapper.spec.ts

View workflow job for this annotation

GitHub Actions / nest_lint

Forbidden non-null assertion

return {
sanisResponse,
Expand All @@ -163,7 +163,7 @@

const result: ExternalGroupDto[] | undefined = mapper.mapToExternalGroupDtos(sanisResponse);

expect(result![0]).toEqual<ExternalGroupDto>({

Check warning on line 166 in apps/server/src/modules/provisioning/strategy/sanis/sanis-response.mapper.spec.ts

View workflow job for this annotation

GitHub Actions / nest_lint

Forbidden non-null assertion
name: group.gruppe.bezeichnung,
type: GroupTypes.CLASS,
externalOrganizationId: personenkontext.organisation.id,
Expand All @@ -171,10 +171,6 @@
until: group.gruppe.laufzeit.bis,
externalId: group.gruppe.id,
users: [
{
externalUserId: group.sonstige_gruppenzugehoerige![0].ktid,
roleName: RoleName.STUDENT,
},
{
externalUserId: personenkontext.id,
roleName: RoleName.TEACHER,
Expand All @@ -187,7 +183,7 @@
describe('when no group type is provided', () => {
const setup = () => {
const { sanisResponse } = setupSanisResponse();
sanisResponse.personenkontexte[0].gruppen![0]!.gruppe.typ = SanisGroupType.OTHER;

Check warning on line 186 in apps/server/src/modules/provisioning/strategy/sanis/sanis-response.mapper.spec.ts

View workflow job for this annotation

GitHub Actions / nest_lint

Forbidden non-null assertion

Check warning on line 186 in apps/server/src/modules/provisioning/strategy/sanis/sanis-response.mapper.spec.ts

View workflow job for this annotation

GitHub Actions / nest_lint

Forbidden non-null assertion

return {
sanisResponse,
Expand All @@ -206,9 +202,7 @@
describe('when a group role mapping is missing', () => {
const setup = () => {
const { sanisResponse } = setupSanisResponse();
sanisResponse.personenkontexte[0].gruppen![0]!.sonstige_gruppenzugehoerige![0].rollen = [
SanisGroupRole.SCHOOL_SUPPORT,
];
sanisResponse.personenkontexte[0].gruppen![0]!.gruppenzugehoerigkeit.rollen = [SanisGroupRole.SCHOOL_SUPPORT];

Check warning on line 205 in apps/server/src/modules/provisioning/strategy/sanis/sanis-response.mapper.spec.ts

View workflow job for this annotation

GitHub Actions / nest_lint

Forbidden non-null assertion

Check warning on line 205 in apps/server/src/modules/provisioning/strategy/sanis/sanis-response.mapper.spec.ts

View workflow job for this annotation

GitHub Actions / nest_lint

Forbidden non-null assertion

return {
sanisResponse,
Expand All @@ -220,7 +214,7 @@

const result: ExternalGroupDto[] | undefined = mapper.mapToExternalGroupDtos(sanisResponse);

expect(result![0].users).toHaveLength(1);
expect(result![0].users).toHaveLength(0);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class SanisResponseMapper {
}

mapToExternalGroupDtos(source: SanisResponse): ExternalGroupDto[] | undefined {
const groups: SanisGruppenResponse[] | undefined = source.personenkontexte[0].gruppen;
const groups: SanisGruppenResponse[] | undefined = source.personenkontexte[0]?.gruppen;

if (!groups) {
return undefined;
Expand All @@ -81,12 +81,11 @@ export class SanisResponseMapper {
}

const sanisGroupUsers: SanisSonstigeGruppenzugehoerigeResponse[] = [
...(group.sonstige_gruppenzugehoerige ?? []),
{
ktid: source.personenkontexte[0].id,
rollen: group.gruppenzugehoerigkeit.rollen,
},
].sort((a, b) => a.ktid.localeCompare(b.ktid));
].filter((sanisGroupUser) => sanisGroupUser.ktid && sanisGroupUser.rollen);

const gruppenzugehoerigkeiten: ExternalGroupUserDto[] = sanisGroupUsers
.map((relation): ExternalGroupUserDto | null => this.mapToExternalGroupUser(relation))
Expand Down
Loading