diff --git a/apps/server/src/apps/server.app.ts b/apps/server/src/apps/server.app.ts index c3cbeb8a921..81a35f6bfa6 100644 --- a/apps/server/src/apps/server.app.ts +++ b/apps/server/src/apps/server.app.ts @@ -8,6 +8,7 @@ import { enableOpenApiDocs } from '@shared/controller/swagger'; import { Mail, MailService } from '@shared/infra/mail'; import { LegacyLogger, Logger } from '@src/core/logger'; import { AccountService } from '@src/modules/account/services/account.service'; +import { TeamService } from '@src/modules/teams/service/team.service'; import { AccountValidationService } from '@src/modules/account/services/account.validation.service'; import { AccountUc } from '@src/modules/account/uc/account.uc'; import { CollaborativeStorageUc } from '@src/modules/collaborative-storage/uc/collaborative-storage.uc'; @@ -76,6 +77,8 @@ async function bootstrap() { feathersExpress.services['nest-account-uc'] = nestApp.get(AccountUc); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment feathersExpress.services['nest-collaborative-storage-uc'] = nestApp.get(CollaborativeStorageUc); + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access + feathersExpress.services['nest-team-service'] = nestApp.get(TeamService); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment feathersExpress.services['nest-orm'] = orm; diff --git a/apps/server/src/modules/server/server.module.ts b/apps/server/src/modules/server/server.module.ts index 1f9c607c4af..ad338bae642 100644 --- a/apps/server/src/modules/server/server.module.ts +++ b/apps/server/src/modules/server/server.module.ts @@ -35,6 +35,7 @@ import { VideoConferenceApiModule } from '@src/modules/video-conference/video-co import connectRedis from 'connect-redis'; import session from 'express-session'; import { RedisClient } from 'redis'; +import { TeamsApiModule } from '@src/modules/teams/teams-api.module'; import { ServerController } from './controller/server.controller'; import { serverConfig } from './server.config'; @@ -72,6 +73,7 @@ const serverModules = [ UserLoginMigrationApiModule, BoardApiModule, GroupApiModule, + TeamsApiModule, ]; export const defaultMikroOrmOptions: MikroOrmModuleSyncOptions = { diff --git a/apps/server/src/modules/teams/service/team.service.ts b/apps/server/src/modules/teams/service/team.service.ts index 347b604c13d..364d6b73e57 100644 --- a/apps/server/src/modules/teams/service/team.service.ts +++ b/apps/server/src/modules/teams/service/team.service.ts @@ -15,16 +15,12 @@ export class TeamService { public async deleteUserDataFromTeams(userId: EntityId): Promise { const teams = await this.teamsRepo.findByUserId(userId); - const updatedTeams: TeamEntity[] = teams.map((team: TeamEntity) => { - return { - ...team, - userIds: team.userIds.filter((u) => u.userId.id !== userId), - teamUsers: team.userIds.filter((u) => u.userId.id !== userId), - }; + teams.forEach((team) => { + team.userIds = team.userIds.filter((u) => u.userId.id !== userId); }); - await this.teamsRepo.save(updatedTeams); + await this.teamsRepo.save(teams); - return updatedTeams.length; + return teams.length; } } diff --git a/apps/server/src/modules/teams/teams-api.module.ts b/apps/server/src/modules/teams/teams-api.module.ts new file mode 100644 index 00000000000..5fc620fe76a --- /dev/null +++ b/apps/server/src/modules/teams/teams-api.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { TeamsModule } from '@src/modules/teams/teams.module'; + +@Module({ + imports: [TeamsModule], + providers: [], + controllers: [], + exports: [], +}) +export class TeamsApiModule {} diff --git a/src/services/sync/strategies/TSP/SchoolChange.js b/src/services/sync/strategies/TSP/SchoolChange.js index 58e1fc4929d..15fa4c2dc69 100644 --- a/src/services/sync/strategies/TSP/SchoolChange.js +++ b/src/services/sync/strategies/TSP/SchoolChange.js @@ -25,11 +25,11 @@ const invalidateUser = async (app, user) => { const deleteUser = (app, user) => { const userService = app.service('usersModel'); const accountService = app.service('nest-account-service'); - const teamsService = app.service('/teams'); + const teamService = app.service('nest-team-service'); return Promise.all([ userService.remove({ _id: user._id }), accountService.deleteByUserId(user._id.toString()), - teamsService.updateMany({ 'userIds.userId': { $in: [user._id] } }, { $pull: { userIds: { userId: user._id } } }) + teamService.deleteUserDataFromTeams(user._id.toString()), ]); }; @@ -84,7 +84,7 @@ const switchSchool = async (app, currentUser, createUserMethod) => { await deleteUser(app, currentUser); return newUser; } catch (err) { - logError(`Something went wrong during switching school for user: ${err}`); + logError(`Something went wrong during switching school for user (${currentUser.sourceOptions.tspUid})`, err); return null; } }; diff --git a/test/services/sync/strategies/TSP/SchoolChange.integration.test.js b/test/services/sync/strategies/TSP/SchoolChange.integration.test.js new file mode 100644 index 00000000000..d587b4a3119 --- /dev/null +++ b/test/services/sync/strategies/TSP/SchoolChange.integration.test.js @@ -0,0 +1,58 @@ +const { expect } = require('chai'); + +const appPromise = require('../../../../../src/app'); +const { setupNestServices, closeNestServices } = require('../../../../utils/setup.nest.services'); + +const testObjects = require('../../../helpers/testObjects')(appPromise()); + +const { deleteUser } = require('../../../../../src/services/sync/strategies/TSP/SchoolChange'); + +const userRepo = require('../../../../../src/components/user/repo/user.repo'); +const { NotFound } = require('../../../../../src/errors'); + +describe('SchooolChange API integration tests', () => { + let app; + let server; + let nestServices; + + let nestAccountService; + let teamService; + + before(async () => { + app = await appPromise(); + server = app.listen(0); + nestServices = await setupNestServices(app); + nestAccountService = app.service('nest-account-service'); + teamService = app.service('teams'); + }); + + after(async () => { + await server.close(); + await closeNestServices(nestServices); + }); + + afterEach(async () => { + await testObjects.cleanup(); + }); + + describe('deleteUser', () => { + it('should delete user, users account and delete user from teams', async () => { + const team = await testObjects.createTestTeamWithOwner({ roles: 'teacher' }); + const credentials = { username: team.user.email, password: `${Date.now()}` }; + await testObjects.createTestAccount(credentials, 'local', team.user); + + await deleteUser(app, team.user); + + await expect(userRepo.getUser(team.user._id)).to.be.rejectedWith(NotFound); + const deletedAccount = await nestAccountService.findByUserId(team.user._id); + expect(deletedAccount).to.be.equal(null); + const deletedUserTeams = await teamService.find({ + query: { + $limit: false, + userIds: { $elemMatch: { userId: team.user._id } }, + }, + }); + expect(deletedUserTeams.total).to.be.equal(0); + }); + }); +}); diff --git a/test/utils/setup.nest.services.js b/test/utils/setup.nest.services.js index 715ee3ad1ea..4de3bce181f 100644 --- a/test/utils/setup.nest.services.js +++ b/test/utils/setup.nest.services.js @@ -13,6 +13,8 @@ const { } = require('../../dist/apps/server/modules/account/services/account.validation.service'); const { DB_PASSWORD, DB_URL, DB_USERNAME } = require('../../dist/apps/server/config/database.config'); const { ALL_ENTITIES } = require('../../dist/apps/server/shared/domain/entity/all-entities'); +const { TeamService } = require('../../dist/apps/server/modules/teams/service/team.service'); +const { TeamsApiModule } = require('../../dist/apps/server/modules/teams/teams-api.module'); const setupNestServices = async (app) => { const module = await Test.createTestingModule({ @@ -28,6 +30,7 @@ const setupNestServices = async (app) => { }), ConfigModule.forRoot({ ignoreEnvFile: true, ignoreEnvVars: true, isGlobal: true }), AccountApiModule, + TeamsApiModule, ], }).compile(); const nestApp = await module.createNestApplication().init(); @@ -35,10 +38,12 @@ const setupNestServices = async (app) => { const accountUc = nestApp.get(AccountUc); const accountService = nestApp.get(AccountService); const accountValidationService = nestApp.get(AccountValidationService); + const teamService = nestApp.get(TeamService); app.services['nest-account-uc'] = accountUc; app.services['nest-account-service'] = accountService; app.services['nest-account-validation-service'] = accountValidationService; + app.services['nest-team-service'] = teamService; app.services['nest-orm'] = orm; return { nestApp, orm, accountUc, accountService };