Skip to content

Commit

Permalink
N21-2022 closes the import user migration wizard when closing user lo…
Browse files Browse the repository at this point in the history
…gin migration
  • Loading branch information
arnegns committed Jun 21, 2024
1 parent 2d62bb3 commit cac1e80
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 56 deletions.
1 change: 1 addition & 0 deletions apps/server/src/modules/user-import/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { ImportUserModule } from './user-import.module';
export { UserImportConfigModule } from './user-import-config.module';
export { IUserImportFeatures, UserImportConfiguration } from './config';
export { UserImportService } from './service';
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { MongoMemoryDatabaseModule } from '@infra/database';
import { EntityManager, ObjectId } from '@mikro-orm/mongodb';
import { LegacySchoolService } from '@modules/legacy-school';
import { UserService } from '@modules/user';
import { InternalServerErrorException } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
Expand All @@ -19,7 +20,7 @@ import {
} from '@shared/testing';
import { Logger } from '@src/core/logger';
import { IUserImportFeatures, UserImportFeatures } from '../config';
import { UserMigrationIsNotEnabled } from '../loggable';
import { UserMigrationCanceledLoggable, UserMigrationIsNotEnabled } from '../loggable';
import { UserImportService } from './user-import.service';

describe(UserImportService.name, () => {
Expand All @@ -31,6 +32,7 @@ describe(UserImportService.name, () => {
let legacySystemRepo: DeepMocked<LegacySystemRepo>;
let userService: DeepMocked<UserService>;
let logger: DeepMocked<Logger>;
let schoolService: DeepMocked<LegacySchoolService>;

const features: IUserImportFeatures = {
userMigrationSystemId: new ObjectId().toHexString(),
Expand Down Expand Up @@ -65,6 +67,10 @@ describe(UserImportService.name, () => {
provide: Logger,
useValue: createMock<Logger>(),
},
{
provide: LegacySchoolService,
useValue: createMock<LegacySchoolService>(),
},
],
}).compile();

Expand All @@ -74,6 +80,7 @@ describe(UserImportService.name, () => {
legacySystemRepo = module.get(LegacySystemRepo);
userService = module.get(UserService);
logger = module.get(Logger);
schoolService = module.get(LegacySchoolService);
});

afterAll(async () => {
Expand Down Expand Up @@ -356,4 +363,49 @@ describe(UserImportService.name, () => {
});
});
});

describe('resetMigrationForUsersSchool', () => {
describe('when resetting the migration for a school', () => {
const setup = () => {
const currentUser: User = userFactory.build();
const school: LegacySchoolDo = legacySchoolDoFactory.build();

return {
currentUser,
school,
};
};

it('should delete import users for school', async () => {
const { currentUser, school } = setup();

await service.resetMigrationForUsersSchool(currentUser, school);

expect(importUserRepo.deleteImportUsersBySchool).toHaveBeenCalledWith(currentUser.school);
});

it('should save school with reset migration flags', async () => {
const { currentUser, school } = setup();

await service.resetMigrationForUsersSchool(currentUser, school);

expect(schoolService.save).toHaveBeenCalledWith(
{
...school,
inUserMigration: undefined,
inMaintenanceSince: undefined,
},
true
);
});

it('should log canceled migration', async () => {
const { currentUser, school } = setup();

await service.resetMigrationForUsersSchool(currentUser, school);

expect(logger.notice).toHaveBeenCalledWith(new UserMigrationCanceledLoggable(expect.any(LegacySchoolDo)));
});
});
});
});
19 changes: 16 additions & 3 deletions apps/server/src/modules/user-import/service/user-import.service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { LegacySchoolService } from '@modules/legacy-school';
import { UserService } from '@modules/user';
import { Inject, Injectable, InternalServerErrorException } from '@nestjs/common';
import { LegacySchoolDo } from '@shared/domain/domainobject';
import { ImportUser, MatchCreator, SchoolEntity, SystemEntity, User } from '@shared/domain/entity';
import { SchoolFeature } from '@shared/domain/types';
import { ImportUserRepo, LegacySystemRepo } from '@shared/repo';
import { UserService } from '@modules/user';
import { Logger } from '@src/core/logger';
import { IUserImportFeatures, UserImportFeatures } from '../config';
import { UserMigrationIsNotEnabled } from '../loggable';
import { UserMigrationCanceledLoggable, UserMigrationIsNotEnabled } from '../loggable';

@Injectable()
export class UserImportService {
Expand All @@ -15,7 +16,8 @@ export class UserImportService {
private readonly systemRepo: LegacySystemRepo,
private readonly userService: UserService,
@Inject(UserImportFeatures) private readonly userImportFeatures: IUserImportFeatures,
private readonly logger: Logger
private readonly logger: Logger,
private readonly schoolService: LegacySchoolService
) {}

public async saveImportUsers(importUsers: ImportUser[]): Promise<void> {
Expand Down Expand Up @@ -74,4 +76,15 @@ export class UserImportService {
public async deleteImportUsersBySchool(school: SchoolEntity): Promise<void> {
await this.userImportRepo.deleteImportUsersBySchool(school);
}

public async resetMigrationForUsersSchool(currentUser: User, school: LegacySchoolDo): Promise<void> {
await this.userImportRepo.deleteImportUsersBySchool(currentUser.school);

school.inUserMigration = undefined;
school.inMaintenanceSince = undefined;

await this.schoolService.save(school, true);

this.logger.notice(new UserMigrationCanceledLoggable(school));
}
}
36 changes: 4 additions & 32 deletions apps/server/src/modules/user-import/uc/user-import.uc.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ObjectId } from '@mikro-orm/mongodb';
import { Account, AccountService } from '@modules/account';
import { AuthorizationService } from '@modules/authorization';
import { LegacySchoolService } from '@modules/legacy-school';
import { UserService } from '@modules/user';
import { UserLoginMigrationNotActiveLoggableException } from '@modules/user-import/loggable/user-login-migration-not-active.loggable-exception';
import { UserLoginMigrationService, UserMigrationService } from '@modules/user-login-migration';
import { BadRequestException, ForbiddenException } from '@nestjs/common';
Expand All @@ -26,14 +27,8 @@ import {
} from '@shared/testing';
import { systemEntityFactory } from '@shared/testing/factory/systemEntityFactory';
import { Logger } from '@src/core/logger';
import { UserService } from '@modules/user';
import { IUserImportFeatures, UserImportFeatures } from '../config';
import {
SchoolNotMigratedLoggableException,
UserAlreadyMigratedLoggable,
UserMigrationCanceledLoggable,
} from '../loggable';

import { SchoolNotMigratedLoggableException, UserAlreadyMigratedLoggable } from '../loggable';
import { UserImportService } from '../service';
import {
LdapAlreadyPersistedException,
Expand Down Expand Up @@ -1195,35 +1190,12 @@ describe('[ImportUserModule]', () => {
expect(userImportService.checkFeatureEnabled).toHaveBeenCalled();
});

it('should delete import users for school', async () => {
const { user } = setup();

await uc.cancelMigration(user.id);

expect(importUserRepo.deleteImportUsersBySchool).toHaveBeenCalledWith(user.school);
});

it('should save school with reset migration flags', async () => {
it('should call reset migration', async () => {
const { user, school } = setup();

await uc.cancelMigration(user.id);

expect(schoolService.save).toHaveBeenCalledWith(
{
...school,
inUserMigration: undefined,
inMaintenanceSince: undefined,
},
true
);
});

it('should log canceled migration', async () => {
const { user } = setup();

await uc.cancelMigration(user.id);

expect(logger.notice).toHaveBeenCalledWith(new UserMigrationCanceledLoggable(expect.any(LegacySchoolDo)));
expect(userImportService.resetMigrationForUsersSchool).toHaveBeenCalledWith(user, school);
});
});
});
Expand Down
12 changes: 2 additions & 10 deletions apps/server/src/modules/user-import/uc/user-import.uc.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Account, AccountSave, AccountService } from '@modules/account';
import { AuthorizationService } from '@modules/authorization';
import { LegacySchoolService } from '@modules/legacy-school';
import { UserService } from '@modules/user';
import { UserLoginMigrationNotActiveLoggableException } from '@modules/user-import/loggable/user-login-migration-not-active.loggable-exception';
import { UserLoginMigrationService, UserMigrationService } from '@modules/user-login-migration';
import { BadRequestException, ForbiddenException, Inject, Injectable } from '@nestjs/common';
Expand All @@ -12,7 +13,6 @@ import { IFindOptions, Permission } from '@shared/domain/interface';
import { Counted, EntityId, IImportUserScope, MatchCreatorScope, NameMatch } from '@shared/domain/types';
import { ImportUserRepo, LegacySystemRepo, UserRepo } from '@shared/repo';
import { Logger } from '@src/core/logger';
import { UserService } from '@modules/user';
import { IUserImportFeatures, UserImportFeatures } from '../config';
import {
MigrationMayBeCompleted,
Expand All @@ -22,7 +22,6 @@ import {
SchoolInUserMigrationStartLoggable,
SchoolNotMigratedLoggableException,
UserAlreadyMigratedLoggable,
UserMigrationCanceledLoggable,
} from '../loggable';

import { UserImportService } from '../service';
Expand Down Expand Up @@ -332,14 +331,7 @@ export class UserImportUc {

this.userImportService.checkFeatureEnabled(school);

await this.importUserRepo.deleteImportUsersBySchool(currentUser.school);

school.inUserMigration = undefined;
school.inMaintenanceSince = undefined;

await this.schoolService.save(school, true);

this.logger.notice(new UserMigrationCanceledLoggable(school));
await this.userImportService.resetMigrationForUsersSchool(currentUser, school);
}

private async getCurrentUser(currentUserId: EntityId, permission: UserImportPermissions): Promise<User> {
Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/modules/user-import/user-import.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import { UserImportConfigModule } from './user-import-config.module';
UserImportService,
SchulconnexFetchImportUsersService,
],
exports: [],
exports: [UserImportService],
})
/**
* Module to provide user migration,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { ObjectId } from '@mikro-orm/mongodb';
import { AuthorizationContextBuilder, AuthorizationService } from '@modules/authorization';
import { LegacySchoolService } from '@modules/legacy-school';
import { UserImportService } from '@modules/user-import';
import { Test, TestingModule } from '@nestjs/testing';

import { UserLoginMigrationDO } from '@shared/domain/domainobject';
import { Permission } from '@shared/domain/interface';
import { setupEntities, userFactory, userLoginMigrationDOFactory } from '@shared/testing';
import {
legacySchoolDoFactory,
schoolEntityFactory,
setupEntities,
userFactory,
userLoginMigrationDOFactory,
} from '@shared/testing';
import { UserLoginMigrationNotFoundLoggableException } from '../loggable';
import { SchoolMigrationService, UserLoginMigrationRevertService, UserLoginMigrationService } from '../service';
import { CloseUserLoginMigrationUc } from './close-user-login-migration.uc';
Expand All @@ -18,6 +25,8 @@ describe(CloseUserLoginMigrationUc.name, () => {
let schoolMigrationService: DeepMocked<SchoolMigrationService>;
let userLoginMigrationRevertService: DeepMocked<UserLoginMigrationRevertService>;
let authorizationService: DeepMocked<AuthorizationService>;
let schoolService: DeepMocked<LegacySchoolService>;
let userImportService: DeepMocked<UserImportService>;

beforeAll(async () => {
await setupEntities();
Expand All @@ -41,6 +50,14 @@ describe(CloseUserLoginMigrationUc.name, () => {
provide: AuthorizationService,
useValue: createMock<AuthorizationService>(),
},
{
provide: LegacySchoolService,
useValue: createMock<LegacySchoolService>(),
},
{
provide: UserImportService,
useValue: createMock<UserImportService>(),
},
],
}).compile();

Expand All @@ -49,6 +66,8 @@ describe(CloseUserLoginMigrationUc.name, () => {
schoolMigrationService = module.get(SchoolMigrationService);
userLoginMigrationRevertService = module.get(UserLoginMigrationRevertService);
authorizationService = module.get(AuthorizationService);
schoolService = module.get(LegacySchoolService);
userImportService = module.get(UserImportService);
});

afterAll(async () => {
Expand All @@ -62,18 +81,20 @@ describe(CloseUserLoginMigrationUc.name, () => {
describe('closeMigration', () => {
describe('when the user login migration was closed after a migration', () => {
const setup = () => {
const user = userFactory.buildWithId();
const schoolId = new ObjectId().toHexString();
const user = userFactory.buildWithId({ school: schoolEntityFactory.build({ _id: schoolId }) });
const userLoginMigration = userLoginMigrationDOFactory.buildWithId();
const closedUserLoginMigration = new UserLoginMigrationDO({
...userLoginMigration,
closedAt: new Date(2023, 1),
});
const schoolId = new ObjectId().toHexString();
const school = legacySchoolDoFactory.build({ id: schoolId, inUserMigration: false });

userLoginMigrationService.findMigrationBySchool.mockResolvedValueOnce(userLoginMigration);
authorizationService.getUserWithPermissions.mockResolvedValueOnce(user);
userLoginMigrationService.closeMigration.mockResolvedValueOnce(closedUserLoginMigration);
schoolMigrationService.hasSchoolMigratedUser.mockResolvedValueOnce(true);
schoolService.getSchoolById.mockResolvedValueOnce(school);

return {
user,
Expand Down Expand Up @@ -144,18 +165,20 @@ describe(CloseUserLoginMigrationUc.name, () => {

describe('when the user login migration was closed without any migration', () => {
const setup = () => {
const user = userFactory.buildWithId();
const schoolId = new ObjectId().toHexString();
const user = userFactory.buildWithId({ school: schoolEntityFactory.build({ _id: schoolId }) });
const userLoginMigration = userLoginMigrationDOFactory.buildWithId();
const closedUserLoginMigration = new UserLoginMigrationDO({
...userLoginMigration,
closedAt: new Date(2023, 1),
});
const schoolId = 'schoolId';
const school = legacySchoolDoFactory.build({ id: schoolId, inUserMigration: false });

userLoginMigrationService.findMigrationBySchool.mockResolvedValueOnce(userLoginMigration);
authorizationService.getUserWithPermissions.mockResolvedValueOnce(user);
userLoginMigrationService.closeMigration.mockResolvedValueOnce(closedUserLoginMigration);
schoolMigrationService.hasSchoolMigratedUser.mockResolvedValueOnce(false);
schoolService.getSchoolById.mockResolvedValueOnce(school);

return {
user,
Expand Down Expand Up @@ -201,5 +224,46 @@ describe(CloseUserLoginMigrationUc.name, () => {
expect(result).toBeUndefined();
});
});

describe('when migration wizard is active', () => {
const setup = () => {
const schoolId = new ObjectId().toHexString();
const user = userFactory.buildWithId({ school: schoolEntityFactory.build({ _id: schoolId }) });
const userLoginMigration = userLoginMigrationDOFactory.buildWithId();
const closedUserLoginMigration = new UserLoginMigrationDO({
...userLoginMigration,
closedAt: new Date(2023, 1),
});
const school = legacySchoolDoFactory.build({ id: schoolId, inUserMigration: true });

userLoginMigrationService.findMigrationBySchool.mockResolvedValueOnce(userLoginMigration);
authorizationService.getUserWithPermissions.mockResolvedValueOnce(user);
userLoginMigrationService.closeMigration.mockResolvedValueOnce(closedUserLoginMigration);
schoolMigrationService.hasSchoolMigratedUser.mockResolvedValueOnce(false);
schoolService.getSchoolById.mockResolvedValueOnce(school);

return {
user,
schoolId,
school,
};
};

it('should check all permissions', async () => {
const { user, schoolId } = setup();

await uc.closeMigration(user.id, schoolId);

expect(authorizationService.checkAllPermissions).toHaveBeenCalledWith(user, [Permission.IMPORT_USER_MIGRATE]);
});

it('should reset migration for user school', async () => {
const { user, schoolId, school } = setup();

await uc.closeMigration(user.id, schoolId);

expect(userImportService.resetMigrationForUsersSchool).toHaveBeenCalledWith(user, school);
});
});
});
});
Loading

0 comments on commit cac1e80

Please sign in to comment.