From 61050ac46c58fbd68a3a2d49534ee1ba9d94c93b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20=C3=96hlerking?= Date: Fri, 28 Jun 2024 10:27:12 +0200 Subject: [PATCH 1/6] fix school external tools --- .../mikro-orm/Migration20240627134214.ts | 38 ++ .../schulconnex-tool-provisioning.service.ts | 1 + .../tool-configuration-status.service.spec.ts | 2 +- .../tool-configuration-status.service.ts | 2 +- .../mapper/external-tool-datasheet.mapper.ts | 2 +- .../external-tool-configuration.service.ts | 2 +- .../api-test/tool-school.api.spec.ts | 29 +- .../controller/dto/index.ts | 2 +- ...ol-external-tool-configuration.response.ts | 6 +- .../dto/school-external-tool.response.ts | 10 +- .../controller/tool-school.controller.ts | 27 +- .../tool/school-external-tool/domain/index.ts | 1 + ...hool-external-tool-configuration-status.ts | 4 +- .../domain/school-external-tool.do.ts | 14 +- ...l-tool-configuration-status.entity.spec.ts | 38 -- ...ternal-tool-configuration-status.entity.ts | 15 - .../school-external-tool.entity.spec.ts | 103 ----- .../entity/school-external-tool.entity.ts | 11 +- .../tool/school-external-tool/mapper/index.ts | 1 - ...chool-external-tool-request.mapper.spec.ts | 15 +- .../school-external-tool-request.mapper.ts | 21 +- .../school-external-tool-response.mapper.ts | 29 +- ...ol-external-tool-status-response.mapper.ts | 14 - .../school-external-tool.service.spec.ts | 403 +++++++----------- .../service/school-external-tool.service.ts | 65 ++- .../school-external-tool/testing/index.ts | 1 - ...ool-configuration-status-entity.factory.ts | 10 - ...l-configuration-status-response.factory.ts | 2 +- ...ernal-tool-configuration-status.factory.ts | 4 +- .../school-external-tool-entity.factory.ts | 3 +- .../testing/school-external-tool.factory.ts | 1 + .../uc/dto/school-external-tool.types.ts | 4 - .../uc/school-external-tool.uc.ts | 8 +- .../src/modules/tool/tool-api.module.ts | 3 - .../tool-launch.controller.api.spec.ts | 9 +- .../school-external-tool.repo.spec.ts | 14 +- .../school-external-tool.repo.ts | 4 +- .../school-external-tool.scope.ts | 8 +- backup/setup/migrations.json | 33 +- 39 files changed, 346 insertions(+), 613 deletions(-) create mode 100644 apps/server/src/migrations/mikro-orm/Migration20240627134214.ts rename apps/server/src/modules/tool/school-external-tool/{controller => }/domain/school-external-tool-configuration-status.ts (70%) delete mode 100644 apps/server/src/modules/tool/school-external-tool/entity/school-external-tool-configuration-status.entity.spec.ts delete mode 100644 apps/server/src/modules/tool/school-external-tool/entity/school-external-tool-configuration-status.entity.ts delete mode 100644 apps/server/src/modules/tool/school-external-tool/entity/school-external-tool.entity.spec.ts delete mode 100644 apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-status-response.mapper.ts delete mode 100644 apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-configuration-status-entity.factory.ts diff --git a/apps/server/src/migrations/mikro-orm/Migration20240627134214.ts b/apps/server/src/migrations/mikro-orm/Migration20240627134214.ts new file mode 100644 index 00000000000..95372879c47 --- /dev/null +++ b/apps/server/src/migrations/mikro-orm/Migration20240627134214.ts @@ -0,0 +1,38 @@ +import { Migration } from '@mikro-orm/migrations-mongodb'; + +export class Migration20240627134214 extends Migration { + async up(): Promise { + await this.driver.aggregate('school-external-tools', [ + { $set: { isDeactivated: { $ifNull: ['$status.isDeactivated', false] } } }, + { $unset: 'status' }, + { $out: 'school-external-tools' }, + ]); + + console.info(`'status.isDeactivated' has moved to 'isDeactivated' for all school-external-tools`); + } + + async down(): Promise { + await this.driver.nativeUpdate( + 'school-external-tools', + { isDeactivated: true }, + { + $set: { + status: { + isOutdatedOnScopeSchool: false, + isDeactivated: true, + }, + }, + } + ); + + await this.driver.nativeUpdate( + 'school-external-tools', + {}, + { + $unset: { isDeactivated: '' }, + } + ); + + console.info(`All school-external-tools were reverted to using 'status'`); + } +} diff --git a/apps/server/src/modules/provisioning/strategy/oidc/service/schulconnex-tool-provisioning.service.ts b/apps/server/src/modules/provisioning/strategy/oidc/service/schulconnex-tool-provisioning.service.ts index 75505abe65f..c24eea36374 100644 --- a/apps/server/src/modules/provisioning/strategy/oidc/service/schulconnex-tool-provisioning.service.ts +++ b/apps/server/src/modules/provisioning/strategy/oidc/service/schulconnex-tool-provisioning.service.ts @@ -72,6 +72,7 @@ export class SchulconnexToolProvisioningService { id: new ObjectId().toHexString(), toolId: externalTool.id, schoolId, + isDeactivated: false, parameters: [], }); diff --git a/apps/server/src/modules/tool/context-external-tool/service/tool-configuration-status.service.spec.ts b/apps/server/src/modules/tool/context-external-tool/service/tool-configuration-status.service.spec.ts index 1dc112369d3..587d9731b6f 100644 --- a/apps/server/src/modules/tool/context-external-tool/service/tool-configuration-status.service.spec.ts +++ b/apps/server/src/modules/tool/context-external-tool/service/tool-configuration-status.service.spec.ts @@ -443,7 +443,7 @@ describe(ToolConfigurationStatusService.name, () => { const externalTool = externalToolFactory.buildWithId(); const schoolExternalTool = schoolExternalToolFactory.buildWithId({ toolId: externalTool.id, - status: { isDeactivated: true }, + isDeactivated: true, }); const contextExternalTool = contextExternalToolFactory .withSchoolExternalToolRef(schoolExternalTool.id) diff --git a/apps/server/src/modules/tool/context-external-tool/service/tool-configuration-status.service.ts b/apps/server/src/modules/tool/context-external-tool/service/tool-configuration-status.service.ts index b5464fbac89..e1387d59dc5 100644 --- a/apps/server/src/modules/tool/context-external-tool/service/tool-configuration-status.service.ts +++ b/apps/server/src/modules/tool/context-external-tool/service/tool-configuration-status.service.ts @@ -72,7 +72,7 @@ export class ToolConfigurationStatusService { } private isToolDeactivated(externalTool: ExternalTool, schoolExternalTool: SchoolExternalTool): boolean { - return !!(externalTool.isDeactivated || (schoolExternalTool.status && schoolExternalTool.status.isDeactivated)); + return externalTool.isDeactivated || schoolExternalTool.isDeactivated; } private async isToolLicensed(externalTool: ExternalTool, userId: EntityId): Promise { diff --git a/apps/server/src/modules/tool/external-tool/mapper/external-tool-datasheet.mapper.ts b/apps/server/src/modules/tool/external-tool/mapper/external-tool-datasheet.mapper.ts index 4a336ff604e..d35e86b8d82 100644 --- a/apps/server/src/modules/tool/external-tool/mapper/external-tool-datasheet.mapper.ts +++ b/apps/server/src/modules/tool/external-tool/mapper/external-tool-datasheet.mapper.ts @@ -61,7 +61,7 @@ export class ExternalToolDatasheetMapper { return 'Das Tool ist instanzweit deaktiviert'; } - if (schoolExternalTool?.status?.isDeactivated) { + if (schoolExternalTool?.isDeactivated) { return 'Das Tool ist deaktiviert'; } diff --git a/apps/server/src/modules/tool/external-tool/service/external-tool-configuration.service.ts b/apps/server/src/modules/tool/external-tool/service/external-tool-configuration.service.ts index e46ad499f8c..f41dcace98e 100644 --- a/apps/server/src/modules/tool/external-tool/service/external-tool-configuration.service.ts +++ b/apps/server/src/modules/tool/external-tool/service/external-tool-configuration.service.ts @@ -38,7 +38,7 @@ export class ExternalToolConfigurationService { const availableTools: ContextExternalToolTemplateInfo[] = unusedTools .filter((toolRef): toolRef is ContextExternalToolTemplateInfo => !toolRef.externalTool.isHidden) .filter((toolRef) => !toolRef.externalTool.isDeactivated) - .filter((toolRef) => !toolRef.schoolExternalTool.status?.isDeactivated); + .filter((toolRef) => !toolRef.schoolExternalTool.isDeactivated); return availableTools; } diff --git a/apps/server/src/modules/tool/school-external-tool/controller/api-test/tool-school.api.spec.ts b/apps/server/src/modules/tool/school-external-tool/controller/api-test/tool-school.api.spec.ts index 1b62a7128fc..b75027fbb60 100644 --- a/apps/server/src/modules/tool/school-external-tool/controller/api-test/tool-school.api.spec.ts +++ b/apps/server/src/modules/tool/school-external-tool/controller/api-test/tool-school.api.spec.ts @@ -130,8 +130,9 @@ describe('ToolSchoolController (API)', () => { const response = await loggedInClient.post().send(postParams); expect(response.statusCode).toEqual(HttpStatus.CREATED); - expect(response.body).toEqual({ + expect(response.body).toEqual({ id: expect.any(String), + isDeactivated: postParams.isDeactivated, name: externalToolEntity.name, schoolId: postParams.schoolId, toolId: postParams.toolId, @@ -231,6 +232,7 @@ describe('ToolSchoolController (API)', () => { const externalToolEntity: ExternalToolEntity = externalToolEntityFactory.buildWithId({ parameters: [], + isDeactivated: true, }); const schoolExternalToolEntity: SchoolExternalToolEntity = schoolExternalToolEntityFactory.buildWithId({ @@ -284,16 +286,18 @@ describe('ToolSchoolController (API)', () => { expect(response.statusCode).toEqual(HttpStatus.OK); expect(response.body).toEqual( - expect.objectContaining({ + expect.objectContaining({ data: [ { id: schoolExternalToolEntity.id, name: externalToolEntity.name, schoolId: school.id, toolId: externalToolEntity.id, - status: schoolExternalToolConfigurationStatusFactory.build({ + isDeactivated: false, + status: { isOutdatedOnScopeSchool: true, - }), + isGloballyDeactivated: true, + }, parameters: [ { name: schoolExternalToolEntity.schoolParameters[0].name, @@ -322,6 +326,7 @@ describe('ToolSchoolController (API)', () => { const externalToolEntity: ExternalToolEntity = externalToolEntityFactory.buildWithId({ parameters: [], + isDeactivated: true, }); const schoolExternalToolEntity: SchoolExternalToolEntity = schoolExternalToolEntityFactory.buildWithId({ @@ -331,12 +336,14 @@ describe('ToolSchoolController (API)', () => { const schoolExternalToolResponse: SchoolExternalToolResponse = new SchoolExternalToolResponse({ id: schoolExternalToolEntity.id, - name: '', + name: externalToolEntity.name, schoolId: school.id, toolId: externalToolEntity.id, - status: schoolExternalToolConfigurationStatusFactory.build({ - isOutdatedOnScopeSchool: false, - }), + isDeactivated: false, + status: { + isOutdatedOnScopeSchool: true, + isGloballyDeactivated: true, + }, parameters: [ { name: schoolExternalToolEntity.schoolParameters[0].name, @@ -459,9 +466,11 @@ describe('ToolSchoolController (API)', () => { name: externalToolEntity.name, schoolId: postParamsUpdate.schoolId, toolId: postParamsUpdate.toolId, - status: schoolExternalToolConfigurationStatusFactory.build({ + isDeactivated: false, + status: { isOutdatedOnScopeSchool: false, - }), + isGloballyDeactivated: false, + }, parameters: [ { name: updatedParamEntry.name, diff --git a/apps/server/src/modules/tool/school-external-tool/controller/dto/index.ts b/apps/server/src/modules/tool/school-external-tool/controller/dto/index.ts index 3631b6989b4..b3e0ba2d6ed 100644 --- a/apps/server/src/modules/tool/school-external-tool/controller/dto/index.ts +++ b/apps/server/src/modules/tool/school-external-tool/controller/dto/index.ts @@ -6,4 +6,4 @@ export * from './school-external-tool-post.params'; export * from './school-external-tool-search.params'; export * from './school-external-tool-search-list.response'; export * from './school-external-tool-metadata.response'; -export * from '../domain/school-external-tool-configuration-status'; +export { SchoolExternalToolConfigurationStatusResponse } from './school-external-tool-configuration.response'; diff --git a/apps/server/src/modules/tool/school-external-tool/controller/dto/school-external-tool-configuration.response.ts b/apps/server/src/modules/tool/school-external-tool/controller/dto/school-external-tool-configuration.response.ts index 36d500ba88e..2807b060c22 100644 --- a/apps/server/src/modules/tool/school-external-tool/controller/dto/school-external-tool-configuration.response.ts +++ b/apps/server/src/modules/tool/school-external-tool/controller/dto/school-external-tool-configuration.response.ts @@ -10,12 +10,12 @@ export class SchoolExternalToolConfigurationStatusResponse { @ApiProperty({ type: Boolean, - description: 'Is the tool deactivated, because of school administrator?', + description: 'Is the tool deactivated, because of instance administrator?', }) - isDeactivated: boolean; + isGloballyDeactivated: boolean; constructor(props: SchoolExternalToolConfigurationStatusResponse) { this.isOutdatedOnScopeSchool = props.isOutdatedOnScopeSchool; - this.isDeactivated = props.isDeactivated; + this.isGloballyDeactivated = props.isGloballyDeactivated; } } diff --git a/apps/server/src/modules/tool/school-external-tool/controller/dto/school-external-tool.response.ts b/apps/server/src/modules/tool/school-external-tool/controller/dto/school-external-tool.response.ts index 2ca015c5538..76e4affd524 100644 --- a/apps/server/src/modules/tool/school-external-tool/controller/dto/school-external-tool.response.ts +++ b/apps/server/src/modules/tool/school-external-tool/controller/dto/school-external-tool.response.ts @@ -1,4 +1,4 @@ -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { ApiProperty } from '@nestjs/swagger'; import { CustomParameterEntryResponse } from './custom-parameter-entry.response'; import { SchoolExternalToolConfigurationStatusResponse } from './school-external-tool-configuration.response'; @@ -15,22 +15,22 @@ export class SchoolExternalToolResponse { @ApiProperty() schoolId: string; + @ApiProperty() + isDeactivated: boolean; + @ApiProperty({ type: [CustomParameterEntryResponse] }) parameters: CustomParameterEntryResponse[]; @ApiProperty({ type: SchoolExternalToolConfigurationStatusResponse }) status: SchoolExternalToolConfigurationStatusResponse; - @ApiPropertyOptional() - logoUrl?: string; - constructor(response: SchoolExternalToolResponse) { this.id = response.id; this.name = response.name; this.toolId = response.toolId; this.schoolId = response.schoolId; + this.isDeactivated = response.isDeactivated; this.parameters = response.parameters; this.status = response.status; - this.logoUrl = response.logoUrl; } } diff --git a/apps/server/src/modules/tool/school-external-tool/controller/tool-school.controller.ts b/apps/server/src/modules/tool/school-external-tool/controller/tool-school.controller.ts index 44b1754ea9a..abfff864d11 100644 --- a/apps/server/src/modules/tool/school-external-tool/controller/tool-school.controller.ts +++ b/apps/server/src/modules/tool/school-external-tool/controller/tool-school.controller.ts @@ -15,14 +15,13 @@ import { import { ValidationError } from '@shared/common'; import { LegacyLogger } from '@src/core/logger'; import { ExternalToolSearchListResponse } from '../../external-tool/controller/dto'; -import { SchoolExternalTool, SchoolExternalToolMetadata } from '../domain'; +import { SchoolExternalTool, SchoolExternalToolMetadata, SchoolExternalToolProps } from '../domain'; import { SchoolExternalToolMetadataMapper, SchoolExternalToolRequestMapper, SchoolExternalToolResponseMapper, } from '../mapper'; import { SchoolExternalToolUc } from '../uc'; -import { SchoolExternalToolDto } from '../uc/dto/school-external-tool.types'; import { SchoolExternalToolIdParams, SchoolExternalToolMetadataResponse, @@ -36,12 +35,7 @@ import { @Authenticate('jwt') @Controller('tools/school-external-tools') export class ToolSchoolController { - constructor( - private readonly schoolExternalToolUc: SchoolExternalToolUc, - private readonly responseMapper: SchoolExternalToolResponseMapper, - private readonly requestMapper: SchoolExternalToolRequestMapper, - private readonly logger: LegacyLogger - ) {} + constructor(private readonly schoolExternalToolUc: SchoolExternalToolUc, private readonly logger: LegacyLogger) {} @Get() @ApiFoundResponse({ description: 'SchoolExternalTools has been found.', type: ExternalToolSearchListResponse }) @@ -55,7 +49,8 @@ export class ToolSchoolController { const found: SchoolExternalTool[] = await this.schoolExternalToolUc.findSchoolExternalTools(currentUser.userId, { schoolId: schoolExternalToolParams.schoolId, }); - const response: SchoolExternalToolSearchListResponse = this.responseMapper.mapToSearchListResponse(found); + const response: SchoolExternalToolSearchListResponse = + SchoolExternalToolResponseMapper.mapToSearchListResponse(found); return response; } @@ -71,7 +66,8 @@ export class ToolSchoolController { currentUser.userId, params.schoolExternalToolId ); - const mapped: SchoolExternalToolResponse = this.responseMapper.mapToSchoolExternalToolResponse(schoolExternalTool); + const mapped: SchoolExternalToolResponse = + SchoolExternalToolResponseMapper.mapToSchoolExternalToolResponse(schoolExternalTool); return mapped; } @@ -86,14 +82,16 @@ export class ToolSchoolController { @Param() params: SchoolExternalToolIdParams, @Body() body: SchoolExternalToolPostParams ): Promise { - const schoolExternalToolDto: SchoolExternalToolDto = this.requestMapper.mapSchoolExternalToolRequest(body); + const schoolExternalToolDto: SchoolExternalToolProps = + SchoolExternalToolRequestMapper.mapSchoolExternalToolRequest(body); const updated: SchoolExternalTool = await this.schoolExternalToolUc.updateSchoolExternalTool( currentUser.userId, params.schoolExternalToolId, schoolExternalToolDto ); - const mapped: SchoolExternalToolResponse = this.responseMapper.mapToSchoolExternalToolResponse(updated); + const mapped: SchoolExternalToolResponse = + SchoolExternalToolResponseMapper.mapToSchoolExternalToolResponse(updated); this.logger.debug(`SchoolExternalTool with id ${mapped.id} was updated by user with id ${currentUser.userId}`); return mapped; } @@ -127,7 +125,8 @@ export class ToolSchoolController { @CurrentUser() currentUser: ICurrentUser, @Body() body: SchoolExternalToolPostParams ): Promise { - const schoolExternalToolDto: SchoolExternalToolDto = this.requestMapper.mapSchoolExternalToolRequest(body); + const schoolExternalToolDto: SchoolExternalToolProps = + SchoolExternalToolRequestMapper.mapSchoolExternalToolRequest(body); const createdSchoolExternalToolDO: SchoolExternalTool = await this.schoolExternalToolUc.createSchoolExternalTool( currentUser.userId, @@ -135,7 +134,7 @@ export class ToolSchoolController { ); const response: SchoolExternalToolResponse = - this.responseMapper.mapToSchoolExternalToolResponse(createdSchoolExternalToolDO); + SchoolExternalToolResponseMapper.mapToSchoolExternalToolResponse(createdSchoolExternalToolDO); this.logger.debug(`SchoolExternalTool with id ${response.id} was created by user with id ${currentUser.userId}`); diff --git a/apps/server/src/modules/tool/school-external-tool/domain/index.ts b/apps/server/src/modules/tool/school-external-tool/domain/index.ts index c0716afd84b..2a85b86634b 100644 --- a/apps/server/src/modules/tool/school-external-tool/domain/index.ts +++ b/apps/server/src/modules/tool/school-external-tool/domain/index.ts @@ -1,3 +1,4 @@ export * from './school-external-tool.do'; export * from './school-external-tool.ref'; export * from './school-external-tool-metadata'; +export { SchoolExternalToolConfigurationStatus } from './school-external-tool-configuration-status'; diff --git a/apps/server/src/modules/tool/school-external-tool/controller/domain/school-external-tool-configuration-status.ts b/apps/server/src/modules/tool/school-external-tool/domain/school-external-tool-configuration-status.ts similarity index 70% rename from apps/server/src/modules/tool/school-external-tool/controller/domain/school-external-tool-configuration-status.ts rename to apps/server/src/modules/tool/school-external-tool/domain/school-external-tool-configuration-status.ts index b8dcfcd13d3..104dbed6197 100644 --- a/apps/server/src/modules/tool/school-external-tool/controller/domain/school-external-tool-configuration-status.ts +++ b/apps/server/src/modules/tool/school-external-tool/domain/school-external-tool-configuration-status.ts @@ -1,10 +1,10 @@ export class SchoolExternalToolConfigurationStatus { isOutdatedOnScopeSchool: boolean; - isDeactivated: boolean; + isGloballyDeactivated: boolean; constructor(props: SchoolExternalToolConfigurationStatus) { this.isOutdatedOnScopeSchool = props.isOutdatedOnScopeSchool; - this.isDeactivated = props.isDeactivated; + this.isGloballyDeactivated = props.isGloballyDeactivated; } } diff --git a/apps/server/src/modules/tool/school-external-tool/domain/school-external-tool.do.ts b/apps/server/src/modules/tool/school-external-tool/domain/school-external-tool.do.ts index bad765ea17f..4d8ed9b8a9f 100644 --- a/apps/server/src/modules/tool/school-external-tool/domain/school-external-tool.do.ts +++ b/apps/server/src/modules/tool/school-external-tool/domain/school-external-tool.do.ts @@ -1,6 +1,6 @@ import { AuthorizableObject, DomainObject } from '@shared/domain/domain-object'; import { CustomParameterEntry } from '../../common/domain'; -import { SchoolExternalToolConfigurationStatus } from '../controller/dto'; +import { SchoolExternalToolConfigurationStatus } from './school-external-tool-configuration-status'; export interface SchoolExternalToolProps extends AuthorizableObject { id: string; @@ -13,6 +13,8 @@ export interface SchoolExternalToolProps extends AuthorizableObject { parameters: CustomParameterEntry[]; + isDeactivated: boolean; + status?: SchoolExternalToolConfigurationStatus; } @@ -37,11 +39,15 @@ export class SchoolExternalTool extends DomainObject { return this.props.parameters; } - get status(): SchoolExternalToolConfigurationStatus | undefined { - return this.props.status; + get isDeactivated(): boolean { + return this.props.isDeactivated; + } + + get status(): SchoolExternalToolConfigurationStatus { + return this.props.status ?? { isOutdatedOnScopeSchool: false, isGloballyDeactivated: false }; } - set status(value: SchoolExternalToolConfigurationStatus | undefined) { + set status(value: SchoolExternalToolConfigurationStatus) { this.props.status = value; } } diff --git a/apps/server/src/modules/tool/school-external-tool/entity/school-external-tool-configuration-status.entity.spec.ts b/apps/server/src/modules/tool/school-external-tool/entity/school-external-tool-configuration-status.entity.spec.ts deleted file mode 100644 index 87a3985ac31..00000000000 --- a/apps/server/src/modules/tool/school-external-tool/entity/school-external-tool-configuration-status.entity.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { setupEntities } from '@shared/testing'; -import { schoolExternalToolConfigurationStatusEntityFactory } from '../testing/school-external-tool-configuration-status-entity.factory'; -import { SchoolExternalToolConfigurationStatusEntity } from './school-external-tool-configuration-status.entity'; - -describe('SchoolExternalToolConfigurationStatusEntity', () => { - beforeAll(async () => { - await setupEntities(); - }); - - describe('constructor', () => { - it('should throw an error by empty constructor', () => { - // @ts-expect-error: Test case - const test = () => new SchoolExternalToolConfigurationStatusEntity(); - expect(test).toThrow(); - }); - - it('should create a school external tool configuration status by passing required properties', () => { - const schoolExternalToolConfigurationStatusEntity: SchoolExternalToolConfigurationStatusEntity = - schoolExternalToolConfigurationStatusEntityFactory.build(); - expect( - schoolExternalToolConfigurationStatusEntity instanceof SchoolExternalToolConfigurationStatusEntity - ).toEqual(false); - }); - - it('should set school external tool status', () => { - const schoolExternalToolConfigurationStatusEntity: SchoolExternalToolConfigurationStatusEntity = - new SchoolExternalToolConfigurationStatusEntity({ - isDeactivated: true, - isOutdatedOnScopeSchool: false, - }); - - expect(schoolExternalToolConfigurationStatusEntity).toEqual({ - isDeactivated: true, - isOutdatedOnScopeSchool: false, - }); - }); - }); -}); diff --git a/apps/server/src/modules/tool/school-external-tool/entity/school-external-tool-configuration-status.entity.ts b/apps/server/src/modules/tool/school-external-tool/entity/school-external-tool-configuration-status.entity.ts deleted file mode 100644 index ea071f996e1..00000000000 --- a/apps/server/src/modules/tool/school-external-tool/entity/school-external-tool-configuration-status.entity.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Embeddable, Property } from '@mikro-orm/core'; - -@Embeddable() -export class SchoolExternalToolConfigurationStatusEntity { - @Property() - isOutdatedOnScopeSchool: boolean; - - @Property() - isDeactivated: boolean; - - constructor(props: SchoolExternalToolConfigurationStatusEntity) { - this.isOutdatedOnScopeSchool = props.isOutdatedOnScopeSchool; - this.isDeactivated = props.isDeactivated; - } -} diff --git a/apps/server/src/modules/tool/school-external-tool/entity/school-external-tool.entity.spec.ts b/apps/server/src/modules/tool/school-external-tool/entity/school-external-tool.entity.spec.ts deleted file mode 100644 index d1f03b47d80..00000000000 --- a/apps/server/src/modules/tool/school-external-tool/entity/school-external-tool.entity.spec.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { schoolEntityFactory, setupEntities } from '@shared/testing'; -import { CustomParameterLocation, CustomParameterScope, CustomParameterType, ToolConfigType } from '../../common/enum'; -import { CustomParameterEntity, ExternalToolConfigEntity, ExternalToolEntity } from '../../external-tool/entity'; -import { - basicToolConfigFactory, - customParameterEntityFactory, - externalToolEntityFactory, -} from '../../external-tool/testing'; -import { schoolExternalToolConfigurationStatusEntityFactory, schoolExternalToolEntityFactory } from '../testing'; -import { SchoolExternalToolEntity } from './school-external-tool.entity'; - -describe('SchoolExternalToolEntity', () => { - beforeAll(async () => { - await setupEntities(); - }); - - describe('constructor', () => { - it('should throw an error by empty constructor', () => { - // @ts-expect-error: Test case - const test = () => new SchoolExternalToolEntity(); - expect(test).toThrow(); - }); - - it('should create an external school Tool by passing required properties', () => { - const schoolExternalToolEntity: SchoolExternalToolEntity = schoolExternalToolEntityFactory.buildWithId(); - expect(schoolExternalToolEntity instanceof SchoolExternalToolEntity).toEqual(true); - }); - - it('should set schoolParameters to empty when is undefined', () => { - const externalToolConfigEntity: ExternalToolConfigEntity = basicToolConfigFactory.buildWithId({ - type: ToolConfigType.OAUTH2, - baseUrl: 'mockBaseUrl', - }); - const customParameter: CustomParameterEntity = customParameterEntityFactory.build({ - name: 'parameterName', - displayName: 'User Friendly Name', - default: 'mock', - location: CustomParameterLocation.PATH, - scope: CustomParameterScope.SCHOOL, - type: CustomParameterType.STRING, - regex: 'mockRegex', - regexComment: 'mockComment', - isOptional: false, - isProtected: false, - }); - const externalToolEntity: ExternalToolEntity = externalToolEntityFactory.buildWithId({ - name: 'toolName', - url: 'mockUrl', - logoUrl: 'mockLogoUrl', - config: externalToolConfigEntity, - parameters: [customParameter], - isHidden: true, - openNewTab: true, - isDeactivated: false, - }); - const schoolExternalToolEntity: SchoolExternalToolEntity = schoolExternalToolEntityFactory.buildWithId({ - tool: externalToolEntity, - school: schoolEntityFactory.buildWithId(), - schoolParameters: [], - status: schoolExternalToolConfigurationStatusEntityFactory.build(), - }); - - expect(schoolExternalToolEntity.schoolParameters).toEqual([]); - }); - - it('should set school external tool configuration status', () => { - const externalToolConfigEntity: ExternalToolConfigEntity = basicToolConfigFactory.buildWithId({ - type: ToolConfigType.OAUTH2, - baseUrl: 'mockBaseUrl', - }); - const customParameter: CustomParameterEntity = customParameterEntityFactory.build({ - name: 'parameterName', - displayName: 'User Friendly Name', - default: 'mock', - location: CustomParameterLocation.PATH, - scope: CustomParameterScope.SCHOOL, - type: CustomParameterType.STRING, - regex: 'mockRegex', - regexComment: 'mockComment', - isOptional: false, - isProtected: false, - }); - const externalToolEntity: ExternalToolEntity = externalToolEntityFactory.buildWithId({ - name: 'toolName', - url: 'mockUrl', - logoUrl: 'mockLogoUrl', - config: externalToolConfigEntity, - parameters: [customParameter], - isHidden: true, - openNewTab: true, - isDeactivated: false, - }); - const schoolExternalToolEntity: SchoolExternalToolEntity = schoolExternalToolEntityFactory.buildWithId({ - tool: externalToolEntity, - school: schoolEntityFactory.buildWithId(), - schoolParameters: [], - status: schoolExternalToolConfigurationStatusEntityFactory.build(), - }); - - expect(schoolExternalToolEntity.status).toEqual({ isDeactivated: false, isOutdatedOnScopeSchool: false }); - }); - }); -}); diff --git a/apps/server/src/modules/tool/school-external-tool/entity/school-external-tool.entity.ts b/apps/server/src/modules/tool/school-external-tool/entity/school-external-tool.entity.ts index cd798abfccd..a43539d371b 100644 --- a/apps/server/src/modules/tool/school-external-tool/entity/school-external-tool.entity.ts +++ b/apps/server/src/modules/tool/school-external-tool/entity/school-external-tool.entity.ts @@ -1,10 +1,9 @@ -import { Embedded, Entity, ManyToOne } from '@mikro-orm/core'; +import { Embedded, Entity, ManyToOne, Property } from '@mikro-orm/core'; import { BaseEntityWithTimestamps } from '@shared/domain/entity/base.entity'; import { SchoolEntity } from '@shared/domain/entity/school.entity'; import { EntityId } from '@shared/domain/types'; import { CustomParameterEntryEntity } from '../../common/entity'; import { ExternalToolEntity } from '../../external-tool/entity'; -import { SchoolExternalToolConfigurationStatusEntity } from './school-external-tool-configuration-status.entity'; export interface SchoolExternalToolEntityProps { id?: EntityId; @@ -15,7 +14,7 @@ export interface SchoolExternalToolEntityProps { schoolParameters?: CustomParameterEntryEntity[]; - status?: SchoolExternalToolConfigurationStatusEntity; + isDeactivated: boolean; } @Entity({ tableName: 'school-external-tools' }) @@ -29,8 +28,8 @@ export class SchoolExternalToolEntity extends BaseEntityWithTimestamps { @Embedded(() => CustomParameterEntryEntity, { array: true }) schoolParameters: CustomParameterEntryEntity[]; - @Embedded(() => SchoolExternalToolConfigurationStatusEntity, { object: true, nullable: true }) - status?: SchoolExternalToolConfigurationStatusEntity; + @Property() + isDeactivated: boolean; constructor(props: SchoolExternalToolEntityProps) { super(); @@ -40,6 +39,6 @@ export class SchoolExternalToolEntity extends BaseEntityWithTimestamps { this.tool = props.tool; this.school = props.school; this.schoolParameters = props.schoolParameters ?? []; - this.status = props.status; + this.isDeactivated = props.isDeactivated; } } diff --git a/apps/server/src/modules/tool/school-external-tool/mapper/index.ts b/apps/server/src/modules/tool/school-external-tool/mapper/index.ts index 4b663b7b50b..48cd0b13a20 100644 --- a/apps/server/src/modules/tool/school-external-tool/mapper/index.ts +++ b/apps/server/src/modules/tool/school-external-tool/mapper/index.ts @@ -1,4 +1,3 @@ export * from './school-external-tool-request.mapper'; export * from './school-external-tool-response.mapper'; export * from './school-external-tool-metadata.mapper'; -export * from './school-external-tool-status-response.mapper'; diff --git a/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-request.mapper.spec.ts b/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-request.mapper.spec.ts index 9fe3f7f1d33..fd6a02c09d2 100644 --- a/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-request.mapper.spec.ts +++ b/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-request.mapper.spec.ts @@ -1,6 +1,5 @@ import { CustomParameterEntryParam, SchoolExternalToolPostParams } from '../controller/dto'; -import { schoolExternalToolConfigurationStatusFactory } from '../testing'; -import { SchoolExternalToolDto } from '../uc/dto/school-external-tool.types'; +import { SchoolExternalToolProps } from '../domain'; import { SchoolExternalToolRequestMapper } from './school-external-tool-request.mapper'; describe('SchoolExternalToolRequestMapper', () => { @@ -29,14 +28,14 @@ describe('SchoolExternalToolRequestMapper', () => { it('should return an schoolExternalTool', () => { const { param, params } = setup(); - const schoolExternalToolDto: SchoolExternalToolDto = mapper.mapSchoolExternalToolRequest(params); + const schoolExternalToolDto: SchoolExternalToolProps = mapper.mapSchoolExternalToolRequest(params); - expect(schoolExternalToolDto).toEqual({ + expect(schoolExternalToolDto).toEqual({ id: expect.any(String), toolId: params.toolId, parameters: [{ name: param.name, value: param.value }], schoolId: params.schoolId, - status: schoolExternalToolConfigurationStatusFactory.build({ isDeactivated: true }), + isDeactivated: true, }); }); }); @@ -58,14 +57,14 @@ describe('SchoolExternalToolRequestMapper', () => { it('should return an schoolExternalTool without parameter', () => { const { params } = setup(); - const schoolExternalToolDto: SchoolExternalToolDto = mapper.mapSchoolExternalToolRequest(params); + const schoolExternalToolDto: SchoolExternalToolProps = mapper.mapSchoolExternalToolRequest(params); - expect(schoolExternalToolDto).toEqual({ + expect(schoolExternalToolDto).toEqual({ id: expect.any(String), toolId: params.toolId, parameters: [], schoolId: params.schoolId, - status: schoolExternalToolConfigurationStatusFactory.build(), + isDeactivated: false, }); }); }); diff --git a/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-request.mapper.ts b/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-request.mapper.ts index 6e05bc21ed2..b0061ac44ae 100644 --- a/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-request.mapper.ts +++ b/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-request.mapper.ts @@ -1,29 +1,20 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { Injectable } from '@nestjs/common'; import { CustomParameterEntry } from '../../common/domain'; -import { - CustomParameterEntryParam, - SchoolExternalToolConfigurationStatus, - SchoolExternalToolPostParams, -} from '../controller/dto'; -import { SchoolExternalToolDto } from '../uc/dto/school-external-tool.types'; +import { CustomParameterEntryParam, SchoolExternalToolPostParams } from '../controller/dto'; +import { SchoolExternalToolProps } from '../domain'; -@Injectable() export class SchoolExternalToolRequestMapper { - mapSchoolExternalToolRequest(request: SchoolExternalToolPostParams): SchoolExternalToolDto { + public static mapSchoolExternalToolRequest(request: SchoolExternalToolPostParams): SchoolExternalToolProps { return { id: new ObjectId().toHexString(), toolId: request.toolId, schoolId: request.schoolId, - parameters: this.mapRequestToCustomParameterEntryDO(request.parameters ?? []), - status: new SchoolExternalToolConfigurationStatus({ - isOutdatedOnScopeSchool: false, - isDeactivated: request.isDeactivated, - }), + parameters: SchoolExternalToolRequestMapper.mapRequestToCustomParameterEntryDO(request.parameters ?? []), + isDeactivated: request.isDeactivated, }; } - private mapRequestToCustomParameterEntryDO( + private static mapRequestToCustomParameterEntryDO( customParameterParams: CustomParameterEntryParam[] ): CustomParameterEntry[] { return customParameterParams.map((customParameterParam: CustomParameterEntryParam) => { diff --git a/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-response.mapper.ts b/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-response.mapper.ts index 71de9168de5..50e75ecd37d 100644 --- a/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-response.mapper.ts +++ b/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-response.mapper.ts @@ -1,36 +1,39 @@ -import { Injectable } from '@nestjs/common'; import { CustomParameterEntry } from '../../common/domain'; import { CustomParameterEntryResponse, + SchoolExternalToolConfigurationStatusResponse, SchoolExternalToolResponse, SchoolExternalToolSearchListResponse, } from '../controller/dto'; import { SchoolExternalTool } from '../domain'; -import { SchoolToolConfigurationStatusResponseMapper } from './school-external-tool-status-response.mapper'; -@Injectable() export class SchoolExternalToolResponseMapper { - mapToSearchListResponse(externalTools: SchoolExternalTool[]): SchoolExternalToolSearchListResponse { + static mapToSearchListResponse(externalTools: SchoolExternalTool[]): SchoolExternalToolSearchListResponse { const responses: SchoolExternalToolResponse[] = externalTools.map((toolDO: SchoolExternalTool) => this.mapToSchoolExternalToolResponse(toolDO) ); + return new SchoolExternalToolSearchListResponse(responses); } - mapToSchoolExternalToolResponse(schoolExternalTool: SchoolExternalTool): SchoolExternalToolResponse { - return { - id: schoolExternalTool.id ?? '', + static mapToSchoolExternalToolResponse(schoolExternalTool: SchoolExternalTool): SchoolExternalToolResponse { + const response: SchoolExternalToolResponse = new SchoolExternalToolResponse({ + id: schoolExternalTool.id, name: schoolExternalTool.name ?? '', toolId: schoolExternalTool.toolId, schoolId: schoolExternalTool.schoolId, - parameters: this.mapToCustomParameterEntryResponse(schoolExternalTool.parameters), - status: SchoolToolConfigurationStatusResponseMapper.mapToResponse( - schoolExternalTool.status ?? { isOutdatedOnScopeSchool: false, isDeactivated: false } - ), - }; + isDeactivated: schoolExternalTool.isDeactivated, + parameters: SchoolExternalToolResponseMapper.mapToCustomParameterEntryResponse(schoolExternalTool.parameters), + status: new SchoolExternalToolConfigurationStatusResponse({ + isOutdatedOnScopeSchool: schoolExternalTool.status.isOutdatedOnScopeSchool, + isGloballyDeactivated: schoolExternalTool.status.isGloballyDeactivated, + }), + }); + + return response; } - private mapToCustomParameterEntryResponse(entries: CustomParameterEntry[]): CustomParameterEntryResponse[] { + private static mapToCustomParameterEntryResponse(entries: CustomParameterEntry[]): CustomParameterEntryResponse[] { return entries.map( (entry: CustomParameterEntry): CustomParameterEntry => new CustomParameterEntryResponse({ diff --git a/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-status-response.mapper.ts b/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-status-response.mapper.ts deleted file mode 100644 index 001efe071c0..00000000000 --- a/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-status-response.mapper.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { SchoolExternalToolConfigurationStatus } from '../controller/dto'; -import { SchoolExternalToolConfigurationStatusResponse } from '../controller/dto/school-external-tool-configuration.response'; - -export class SchoolToolConfigurationStatusResponseMapper { - static mapToResponse(status: SchoolExternalToolConfigurationStatus): SchoolExternalToolConfigurationStatusResponse { - const configurationStatus: SchoolExternalToolConfigurationStatusResponse = - new SchoolExternalToolConfigurationStatusResponse({ - isOutdatedOnScopeSchool: status.isOutdatedOnScopeSchool, - isDeactivated: status.isDeactivated, - }); - - return configurationStatus; - } -} diff --git a/apps/server/src/modules/tool/school-external-tool/service/school-external-tool.service.spec.ts b/apps/server/src/modules/tool/school-external-tool/service/school-external-tool.service.spec.ts index f0e8f89640f..9f3e50b6b9a 100644 --- a/apps/server/src/modules/tool/school-external-tool/service/school-external-tool.service.spec.ts +++ b/apps/server/src/modules/tool/school-external-tool/service/school-external-tool.service.spec.ts @@ -1,14 +1,14 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; -import { ApiValidationError } from '@shared/common'; +import { ValidationError } from '@shared/common'; import { SchoolExternalToolRepo } from '@shared/repo'; +import { CommonToolValidationService } from '../../common/service'; import { ExternalToolService } from '../../external-tool'; -import { ExternalTool } from '../../external-tool/domain'; +import { type ExternalTool } from '../../external-tool/domain'; import { externalToolFactory } from '../../external-tool/testing'; -import { SchoolExternalTool } from '../domain'; -import { schoolExternalToolConfigurationStatusFactory, schoolExternalToolFactory } from '../testing'; +import { SchoolExternalTool, SchoolExternalToolConfigurationStatus } from '../domain'; +import { schoolExternalToolFactory } from '../testing'; import { SchoolExternalToolQuery } from '../uc/dto/school-external-tool.types'; -import { SchoolExternalToolValidationService } from './school-external-tool-validation.service'; import { SchoolExternalToolService } from './school-external-tool.service'; describe(SchoolExternalToolService.name, () => { @@ -17,7 +17,7 @@ describe(SchoolExternalToolService.name, () => { let schoolExternalToolRepo: DeepMocked; let externalToolService: DeepMocked; - let schoolExternalToolValidationService: DeepMocked; + let commonToolValidationService: DeepMocked; beforeAll(async () => { module = await Test.createTestingModule({ @@ -32,8 +32,8 @@ describe(SchoolExternalToolService.name, () => { useValue: createMock(), }, { - provide: SchoolExternalToolValidationService, - useValue: createMock(), + provide: CommonToolValidationService, + useValue: createMock(), }, ], }).compile(); @@ -41,293 +41,178 @@ describe(SchoolExternalToolService.name, () => { service = module.get(SchoolExternalToolService); schoolExternalToolRepo = module.get(SchoolExternalToolRepo); externalToolService = module.get(ExternalToolService); - schoolExternalToolValidationService = module.get(SchoolExternalToolValidationService); + commonToolValidationService = module.get(CommonToolValidationService); }); describe('findSchoolExternalTools', () => { describe('when called with query', () => { - describe('findSchoolExternalTools', () => { - describe('when called with query', () => { - const setup = () => { - const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build(); - const schoolExternalToolQuery: SchoolExternalToolQuery = { - schoolId: schoolExternalTool.schoolId, - toolId: schoolExternalTool.toolId, - isDeactivated: !!schoolExternalTool.status?.isDeactivated, - }; - - schoolExternalToolRepo.find.mockResolvedValueOnce([schoolExternalTool]); - - return { - schoolExternalTool, - schoolExternalToolId: schoolExternalTool.id, - schoolExternalToolQuery, - }; - }; - - it('should call repo with query', async () => { - const { schoolExternalTool, schoolExternalToolQuery } = setup(); - - await service.findSchoolExternalTools(schoolExternalToolQuery); - - expect(schoolExternalToolRepo.find).toHaveBeenCalledWith<[Required]>({ - schoolId: schoolExternalTool.schoolId, - toolId: schoolExternalTool.toolId, - isDeactivated: !!schoolExternalTool.status?.isDeactivated, - }); - }); - - it('should return schoolExternalTool array', async () => { - const { schoolExternalToolQuery } = setup(); - - const result: SchoolExternalTool[] = await service.findSchoolExternalTools(schoolExternalToolQuery); - - expect(Array.isArray(result)).toBe(true); - }); + const setup = () => { + const externalTool: ExternalTool = externalToolFactory.build(); + const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build({ + name: undefined, + status: undefined, }); - }); - describe('enrichDataFromExternalTool', () => { - describe('when schoolExternalTool is given', () => { - const setup = () => { - const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build(); - const externalTool: ExternalTool = externalToolFactory.buildWithId(); + const schoolExternalToolQuery: SchoolExternalToolQuery = { + schoolId: schoolExternalTool.schoolId, + toolId: schoolExternalTool.toolId, + isDeactivated: schoolExternalTool.isDeactivated, + }; - schoolExternalToolRepo.find.mockResolvedValue([schoolExternalTool]); - externalToolService.findById.mockResolvedValue(externalTool); + schoolExternalToolRepo.find.mockResolvedValueOnce([schoolExternalTool]); + externalToolService.findById.mockResolvedValueOnce(externalTool); + commonToolValidationService.validateParameters.mockReturnValueOnce([new ValidationError('')]); - return { - schoolExternalTool, - }; - }; + return { + externalTool, + schoolExternalTool, + schoolExternalToolQuery, + }; + }; - it('should call the externalToolService', async () => { - const { schoolExternalTool } = setup(); + it('should call repo with query', async () => { + const { schoolExternalTool, schoolExternalToolQuery } = setup(); - await service.findSchoolExternalTools(schoolExternalTool); + await service.findSchoolExternalTools(schoolExternalToolQuery); - expect(externalToolService.findById).toHaveBeenCalledWith(schoolExternalTool.toolId); - }); + expect(schoolExternalToolRepo.find).toHaveBeenCalledWith<[Required]>({ + schoolId: schoolExternalTool.schoolId, + toolId: schoolExternalTool.toolId, + isDeactivated: schoolExternalTool.isDeactivated, }); + }); - describe('when determine status', () => { - describe('when validation goes through', () => { - const setup = () => { - const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build(); - const externalTool: ExternalTool = externalToolFactory.buildWithId(); - - schoolExternalToolRepo.find.mockResolvedValue([schoolExternalTool]); - externalToolService.findById.mockResolvedValue(externalTool); - schoolExternalToolValidationService.validate.mockResolvedValue(); - - return { - schoolExternalTool, - }; - }; - - it('should return latest tool status', async () => { - const { schoolExternalTool } = setup(); - - const schoolExternalToolDOs: SchoolExternalTool[] = await service.findSchoolExternalTools( - schoolExternalTool - ); - - expect(schoolExternalToolValidationService.validate).toHaveBeenCalledWith(schoolExternalTool); - expect(schoolExternalToolDOs[0].status).toEqual( - schoolExternalToolConfigurationStatusFactory.build({ - isOutdatedOnScopeSchool: false, - }) - ); - }); - - it('should return non deactivated tool status', async () => { - const { schoolExternalTool } = setup(); - - const schoolExternalToolDOs: SchoolExternalTool[] = await service.findSchoolExternalTools( - schoolExternalTool - ); - - expect(schoolExternalToolValidationService.validate).toHaveBeenCalledWith(schoolExternalTool); - expect(schoolExternalToolDOs[0].status).toEqual( - schoolExternalToolConfigurationStatusFactory.build({ - isDeactivated: false, - }) - ); - }); - }); - - describe('when validation throws error', () => { - const setup = () => { - const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build(); - const externalTool: ExternalTool = externalToolFactory.buildWithId(); - - schoolExternalToolRepo.find.mockResolvedValue([schoolExternalTool]); - externalToolService.findById.mockResolvedValue(externalTool); - schoolExternalToolValidationService.validate.mockRejectedValue(ApiValidationError); - - return { - schoolExternalTool, - }; - }; - - it('should return outdated tool status', async () => { - const { schoolExternalTool } = setup(); - - const schoolExternalToolDOs: SchoolExternalTool[] = await service.findSchoolExternalTools( - schoolExternalTool - ); - - expect(schoolExternalToolValidationService.validate).toHaveBeenCalledWith(schoolExternalTool); - expect(schoolExternalToolDOs[0].status).toEqual( - schoolExternalToolConfigurationStatusFactory.build({ - isOutdatedOnScopeSchool: true, - }) - ); - }); - }); - - describe('when schoolExternalTool is deactivated', () => { - const setup = () => { - const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build({ - status: schoolExternalToolConfigurationStatusFactory.build({ isDeactivated: true }), - }); - const externalTool: ExternalTool = externalToolFactory.buildWithId(); - - schoolExternalToolRepo.find.mockResolvedValue([schoolExternalTool]); - externalToolService.findById.mockResolvedValue(externalTool); - schoolExternalToolValidationService.validate.mockRejectedValue(Promise.resolve()); - - return { - schoolExternalTool, - }; - }; - - it('should return deactivated tool status true', async () => { - const { schoolExternalTool } = setup(); - - const schoolExternalToolDOs: SchoolExternalTool[] = await service.findSchoolExternalTools( - schoolExternalTool - ); - - expect(schoolExternalToolDOs[0].status).toEqual( - schoolExternalToolConfigurationStatusFactory.build({ - isDeactivated: true, - isOutdatedOnScopeSchool: true, - }) - ); - }); - }); - - describe('when externalTool is deactivated', () => { - const setup = () => { - const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build(); - const externalTool: ExternalTool = externalToolFactory.buildWithId({ isDeactivated: true }); - - schoolExternalToolRepo.find.mockResolvedValue([schoolExternalTool]); - externalToolService.findById.mockResolvedValue(externalTool); - schoolExternalToolValidationService.validate.mockRejectedValue(Promise.resolve()); - - return { - schoolExternalTool, - }; - }; - - it('should return deactivated tool status true', async () => { - const { schoolExternalTool } = setup(); - - const schoolExternalToolDOs: SchoolExternalTool[] = await service.findSchoolExternalTools( - schoolExternalTool - ); - - expect(schoolExternalToolDOs[0].status).toEqual( - schoolExternalToolConfigurationStatusFactory.build({ - isDeactivated: true, - isOutdatedOnScopeSchool: true, - }) - ); - }); - }); - }); + it('should return schoolExternalTool array with enriched data', async () => { + const { schoolExternalToolQuery, schoolExternalTool, externalTool } = setup(); + + const result: SchoolExternalTool[] = await service.findSchoolExternalTools(schoolExternalToolQuery); + + expect(result).toEqual([ + new SchoolExternalTool({ + ...schoolExternalTool.getProps(), + name: externalTool.name, + status: new SchoolExternalToolConfigurationStatus({ + isGloballyDeactivated: externalTool.isDeactivated, + isOutdatedOnScopeSchool: true, + }), + }), + ]); }); + }); + }); - describe('deleteSchoolExternalToolById', () => { - describe('when schoolExternalToolId is given', () => { - const setup = () => { - const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build(); - const externalTool: ExternalTool = externalToolFactory.buildWithId(); + describe('deleteSchoolExternalToolById', () => { + describe('when schoolExternalToolId is given', () => { + const setup = () => { + const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build(); + const externalTool: ExternalTool = externalToolFactory.buildWithId(); - schoolExternalToolRepo.find.mockResolvedValue([schoolExternalTool]); - externalToolService.findById.mockResolvedValue(externalTool); + schoolExternalToolRepo.find.mockResolvedValue([schoolExternalTool]); + externalToolService.findById.mockResolvedValue(externalTool); - return { - schoolExternalToolId: schoolExternalTool.id, - }; - }; + return { + schoolExternalToolId: schoolExternalTool.id, + }; + }; - it('should call the schoolExternalToolRepo', () => { - const { schoolExternalToolId } = setup(); + it('should call the schoolExternalToolRepo', () => { + const { schoolExternalToolId } = setup(); - service.deleteSchoolExternalToolById(schoolExternalToolId); + service.deleteSchoolExternalToolById(schoolExternalToolId); - expect(schoolExternalToolRepo.deleteById).toHaveBeenCalledWith(schoolExternalToolId); - }); - }); + expect(schoolExternalToolRepo.deleteById).toHaveBeenCalledWith(schoolExternalToolId); }); + }); + }); - describe('findById', () => { - describe('when schoolExternalToolId is given', () => { - const setup = () => { - const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build(); - const externalTool: ExternalTool = externalToolFactory.buildWithId(); + describe('findById', () => { + describe('when schoolExternalToolId is given', () => { + const setup = () => { + const externalTool: ExternalTool = externalToolFactory.build(); + const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build({ + name: undefined, + status: undefined, + }); - schoolExternalToolRepo.find.mockResolvedValue([schoolExternalTool]); - externalToolService.findById.mockResolvedValue(externalTool); + schoolExternalToolRepo.findById.mockResolvedValue(schoolExternalTool); + externalToolService.findById.mockResolvedValue(externalTool); + commonToolValidationService.validateParameters.mockReturnValueOnce([new ValidationError('')]); - return { - schoolExternalToolId: schoolExternalTool.id, - }; - }; + return { + schoolExternalTool, + externalTool, + }; + }; - it('should call schoolExternalToolRepo.findById', async () => { - const { schoolExternalToolId } = setup(); + it('should call schoolExternalToolRepo.findById', async () => { + const { schoolExternalTool } = setup(); - await service.findById(schoolExternalToolId); + await service.findById(schoolExternalTool.id); - expect(schoolExternalToolRepo.findById).toHaveBeenCalledWith(schoolExternalToolId); - }); - }); + expect(schoolExternalToolRepo.findById).toHaveBeenCalledWith(schoolExternalTool.id); }); - describe('saveSchoolExternalTool', () => { - describe('when schoolExternalTool is given', () => { - const setup = () => { - const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build(); - const externalTool: ExternalTool = externalToolFactory.buildWithId(); - - schoolExternalToolRepo.find.mockResolvedValue([schoolExternalTool]); - externalToolService.findById.mockResolvedValue(externalTool); + it('should return the schoolExternalTool with enriched data', async () => { + const { schoolExternalTool, externalTool } = setup(); + + const result = await service.findById(schoolExternalTool.id); + + expect(result).toEqual( + new SchoolExternalTool({ + ...schoolExternalTool.getProps(), + name: externalTool.name, + status: new SchoolExternalToolConfigurationStatus({ + isGloballyDeactivated: externalTool.isDeactivated, + isOutdatedOnScopeSchool: true, + }), + }) + ); + }); + }); + }); - return { - schoolExternalTool, - }; - }; + describe('saveSchoolExternalTool', () => { + describe('when schoolExternalTool is given', () => { + const setup = () => { + const externalTool: ExternalTool = externalToolFactory.build(); + const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build({ + name: undefined, + status: undefined, + }); - it('should call schoolExternalToolRepo.save', async () => { - const { schoolExternalTool } = setup(); + schoolExternalToolRepo.save.mockResolvedValue(schoolExternalTool); + externalToolService.findById.mockResolvedValue(externalTool); + commonToolValidationService.validateParameters.mockReturnValueOnce([new ValidationError('')]); - await service.saveSchoolExternalTool(schoolExternalTool); + return { + schoolExternalTool, + externalTool, + }; + }; - expect(schoolExternalToolRepo.save).toHaveBeenCalledWith(schoolExternalTool); - }); + it('should call schoolExternalToolRepo.save', async () => { + const { schoolExternalTool } = setup(); - it('should enrich data from externalTool', async () => { - const { schoolExternalTool } = setup(); + await service.saveSchoolExternalTool(schoolExternalTool); - await service.saveSchoolExternalTool(schoolExternalTool); + expect(schoolExternalToolRepo.save).toHaveBeenCalledWith(schoolExternalTool); + }); - expect(externalToolService.findById).toHaveBeenCalledWith(schoolExternalTool.toolId); - }); - }); + it('should return the schoolExternalTool with enriched data', async () => { + const { schoolExternalTool, externalTool } = setup(); + + const result = await service.saveSchoolExternalTool(schoolExternalTool); + + expect(result).toEqual( + new SchoolExternalTool({ + ...schoolExternalTool.getProps(), + name: externalTool.name, + status: new SchoolExternalToolConfigurationStatus({ + isGloballyDeactivated: externalTool.isDeactivated, + isOutdatedOnScopeSchool: true, + }), + }) + ); }); }); }); diff --git a/apps/server/src/modules/tool/school-external-tool/service/school-external-tool.service.ts b/apps/server/src/modules/tool/school-external-tool/service/school-external-tool.service.ts index 0a05ceb5685..978f0aa4ee5 100644 --- a/apps/server/src/modules/tool/school-external-tool/service/school-external-tool.service.ts +++ b/apps/server/src/modules/tool/school-external-tool/service/school-external-tool.service.ts @@ -1,23 +1,25 @@ import { Injectable } from '@nestjs/common'; +import { ValidationError } from '@shared/common'; import { EntityId } from '@shared/domain/types'; import { SchoolExternalToolRepo } from '@shared/repo'; +import { CommonToolValidationService } from '../../common/service'; import { ExternalTool } from '../../external-tool/domain'; import { ExternalToolService } from '../../external-tool/service'; -import { SchoolExternalToolConfigurationStatus } from '../controller/dto'; -import { SchoolExternalTool } from '../domain'; +import { SchoolExternalTool, SchoolExternalToolConfigurationStatus } from '../domain'; import { SchoolExternalToolQuery } from '../uc/dto/school-external-tool.types'; -import { SchoolExternalToolValidationService } from './school-external-tool-validation.service'; @Injectable() export class SchoolExternalToolService { constructor( private readonly schoolExternalToolRepo: SchoolExternalToolRepo, private readonly externalToolService: ExternalToolService, - private readonly schoolExternalToolValidationService: SchoolExternalToolValidationService + private readonly commonToolValidationService: CommonToolValidationService ) {} public async findById(schoolExternalToolId: EntityId): Promise { - const schoolExternalTool: SchoolExternalTool = await this.schoolExternalToolRepo.findById(schoolExternalToolId); + let schoolExternalTool: SchoolExternalTool = await this.schoolExternalToolRepo.findById(schoolExternalToolId); + + schoolExternalTool = await this.enrichWithDataFromExternalTool(schoolExternalTool); return schoolExternalTool; } @@ -36,45 +38,45 @@ export class SchoolExternalToolService { private async enrichWithDataFromExternalTools(tools: SchoolExternalTool[]): Promise { const enrichedTools: SchoolExternalTool[] = await Promise.all( - tools.map(async (tool: SchoolExternalTool): Promise => this.enrichDataFromExternalTool(tool)) + tools.map( + async (tool: SchoolExternalTool): Promise => this.enrichWithDataFromExternalTool(tool) + ) ); return enrichedTools; } - private async enrichDataFromExternalTool(tool: SchoolExternalTool): Promise { + private async enrichWithDataFromExternalTool(tool: SchoolExternalTool): Promise { const externalTool: ExternalTool = await this.externalToolService.findById(tool.toolId); - const status: SchoolExternalToolConfigurationStatus = await this.determineSchoolToolStatus(tool, externalTool); + const status: SchoolExternalToolConfigurationStatus = this.determineSchoolToolStatus(tool, externalTool); + const schoolExternalTool: SchoolExternalTool = new SchoolExternalTool({ - id: tool.id, - toolId: tool.toolId, - schoolId: tool.schoolId, - parameters: tool.parameters, - status, + ...tool.getProps(), name: externalTool.name, + status, }); return schoolExternalTool; } - private async determineSchoolToolStatus( + private determineSchoolToolStatus( tool: SchoolExternalTool, externalTool: ExternalTool - ): Promise { - const status: SchoolExternalToolConfigurationStatus = new SchoolExternalToolConfigurationStatus({ - isOutdatedOnScopeSchool: true, - isDeactivated: this.isToolDeactivated(externalTool, tool), - }); + ): SchoolExternalToolConfigurationStatus { + let isOutdatedOnScopeSchool = false; - try { - await this.schoolExternalToolValidationService.validate(tool); + const errors: ValidationError[] = this.commonToolValidationService.validateParameters(externalTool, tool); - status.isOutdatedOnScopeSchool = false; - - return status; - } catch (err) { - return status; + if (errors.length) { + isOutdatedOnScopeSchool = true; } + + const status: SchoolExternalToolConfigurationStatus = new SchoolExternalToolConfigurationStatus({ + isOutdatedOnScopeSchool, + isGloballyDeactivated: externalTool.isDeactivated, + }); + + return status; } public deleteSchoolExternalToolById(schoolExternalToolId: EntityId): void { @@ -83,16 +85,9 @@ export class SchoolExternalToolService { public async saveSchoolExternalTool(schoolExternalTool: SchoolExternalTool): Promise { let createdSchoolExternalTool: SchoolExternalTool = await this.schoolExternalToolRepo.save(schoolExternalTool); - createdSchoolExternalTool = await this.enrichDataFromExternalTool(createdSchoolExternalTool); - - return createdSchoolExternalTool; - } - private isToolDeactivated(externalTool: ExternalTool, schoolExternalTool: SchoolExternalTool) { - if (externalTool.isDeactivated || schoolExternalTool.status?.isDeactivated) { - return true; - } + createdSchoolExternalTool = await this.enrichWithDataFromExternalTool(createdSchoolExternalTool); - return false; + return createdSchoolExternalTool; } } diff --git a/apps/server/src/modules/tool/school-external-tool/testing/index.ts b/apps/server/src/modules/tool/school-external-tool/testing/index.ts index 2c15f549607..55b1de1dbfa 100644 --- a/apps/server/src/modules/tool/school-external-tool/testing/index.ts +++ b/apps/server/src/modules/tool/school-external-tool/testing/index.ts @@ -2,4 +2,3 @@ export { schoolExternalToolEntityFactory } from './school-external-tool-entity.f export { schoolExternalToolFactory } from './school-external-tool.factory'; export { schoolExternalToolConfigurationStatusFactory } from './school-external-tool-configuration-status.factory'; export { schoolExternalToolConfigurationStatusResponseFactory } from './school-external-tool-configuration-status-response.factory'; -export { schoolExternalToolConfigurationStatusEntityFactory } from './school-external-tool-configuration-status-entity.factory'; diff --git a/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-configuration-status-entity.factory.ts b/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-configuration-status-entity.factory.ts deleted file mode 100644 index 73b02ad773d..00000000000 --- a/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-configuration-status-entity.factory.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Factory } from 'fishery'; -import { SchoolExternalToolConfigurationStatusEntity } from '../entity/school-external-tool-configuration-status.entity'; - -export const schoolExternalToolConfigurationStatusEntityFactory = - Factory.define(() => { - return { - isOutdatedOnScopeSchool: false, - isDeactivated: false, - }; - }); diff --git a/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-configuration-status-response.factory.ts b/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-configuration-status-response.factory.ts index a381fadc03b..0890f40227d 100644 --- a/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-configuration-status-response.factory.ts +++ b/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-configuration-status-response.factory.ts @@ -5,6 +5,6 @@ export const schoolExternalToolConfigurationStatusResponseFactory = Factory.define(() => { return { isOutdatedOnScopeSchool: false, - isDeactivated: false, + isGloballyDeactivated: false, }; }); diff --git a/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-configuration-status.factory.ts b/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-configuration-status.factory.ts index 11b38da4bbd..f925bea5a45 100644 --- a/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-configuration-status.factory.ts +++ b/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-configuration-status.factory.ts @@ -1,11 +1,11 @@ import { Factory } from 'fishery'; -import { SchoolExternalToolConfigurationStatus } from '../controller/dto'; +import { SchoolExternalToolConfigurationStatus } from '../domain'; export const schoolExternalToolConfigurationStatusFactory = Factory.define( () => { return { isOutdatedOnScopeSchool: false, - isDeactivated: false, + isGloballyDeactivated: false, }; } ); diff --git a/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-entity.factory.ts b/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-entity.factory.ts index a90ceafd0ba..383aabbb407 100644 --- a/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-entity.factory.ts +++ b/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool-entity.factory.ts @@ -2,7 +2,6 @@ import { externalToolEntityFactory } from '@modules/tool/external-tool/testing'; import { SchoolExternalToolEntity, SchoolExternalToolEntityProps } from '@modules/tool/school-external-tool/entity'; import { BaseFactory } from '@shared/testing/factory/base.factory'; import { schoolEntityFactory } from '@shared/testing/factory/school-entity.factory'; -import { schoolExternalToolConfigurationStatusEntityFactory } from './school-external-tool-configuration-status-entity.factory'; export const schoolExternalToolEntityFactory = BaseFactory.define< SchoolExternalToolEntity, @@ -12,6 +11,6 @@ export const schoolExternalToolEntityFactory = BaseFactory.define< tool: externalToolEntityFactory.buildWithId(), school: schoolEntityFactory.buildWithId(), schoolParameters: [{ name: 'schoolMockParameter', value: 'mockValue' }], - status: schoolExternalToolConfigurationStatusEntityFactory.build(), + isDeactivated: false, }; }); diff --git a/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool.factory.ts b/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool.factory.ts index a7af0be4b53..3d979b90331 100644 --- a/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool.factory.ts +++ b/apps/server/src/modules/tool/school-external-tool/testing/school-external-tool.factory.ts @@ -26,6 +26,7 @@ export const schoolExternalToolFactory = SchoolExternalToolFactory.define(School }), ], toolId: 'toolId', + isDeactivated: false, status: schoolExternalToolConfigurationStatusFactory.build(), }; }); diff --git a/apps/server/src/modules/tool/school-external-tool/uc/dto/school-external-tool.types.ts b/apps/server/src/modules/tool/school-external-tool/uc/dto/school-external-tool.types.ts index 48ba154dab0..c66f31feb57 100644 --- a/apps/server/src/modules/tool/school-external-tool/uc/dto/school-external-tool.types.ts +++ b/apps/server/src/modules/tool/school-external-tool/uc/dto/school-external-tool.types.ts @@ -1,7 +1,3 @@ -import { SchoolExternalToolProps } from '../../domain'; - -export type SchoolExternalToolDto = SchoolExternalToolProps; - export type SchoolExternalToolQueryInput = { schoolId?: string; toolId?: string; diff --git a/apps/server/src/modules/tool/school-external-tool/uc/school-external-tool.uc.ts b/apps/server/src/modules/tool/school-external-tool/uc/school-external-tool.uc.ts index d8d4c95405c..c7861f82823 100644 --- a/apps/server/src/modules/tool/school-external-tool/uc/school-external-tool.uc.ts +++ b/apps/server/src/modules/tool/school-external-tool/uc/school-external-tool.uc.ts @@ -6,9 +6,9 @@ import { EntityId } from '@shared/domain/types'; import { School, SchoolService } from '@src/modules/school'; import { CommonToolMetadataService } from '../../common/service/common-tool-metadata.service'; import { ContextExternalToolService } from '../../context-external-tool/service'; -import { SchoolExternalTool, SchoolExternalToolMetadata } from '../domain'; +import { SchoolExternalTool, SchoolExternalToolMetadata, SchoolExternalToolProps } from '../domain'; import { SchoolExternalToolService, SchoolExternalToolValidationService } from '../service'; -import { SchoolExternalToolDto, SchoolExternalToolQueryInput } from './dto/school-external-tool.types'; +import { SchoolExternalToolQueryInput } from './dto/school-external-tool.types'; @Injectable() export class SchoolExternalToolUc { @@ -38,7 +38,7 @@ export class SchoolExternalToolUc { async createSchoolExternalTool( userId: EntityId, - schoolExternalToolDto: SchoolExternalToolDto + schoolExternalToolDto: SchoolExternalToolProps ): Promise { const schoolExternalTool = new SchoolExternalTool({ ...schoolExternalToolDto }); @@ -96,7 +96,7 @@ export class SchoolExternalToolUc { async updateSchoolExternalTool( userId: EntityId, schoolExternalToolId: string, - schoolExternalToolDto: SchoolExternalToolDto + schoolExternalToolDto: SchoolExternalToolProps ): Promise { const schoolExternalTool = new SchoolExternalTool({ ...schoolExternalToolDto }); diff --git a/apps/server/src/modules/tool/tool-api.module.ts b/apps/server/src/modules/tool/tool-api.module.ts index 067f062e7f3..783c82ac3da 100644 --- a/apps/server/src/modules/tool/tool-api.module.ts +++ b/apps/server/src/modules/tool/tool-api.module.ts @@ -18,7 +18,6 @@ import { ExternalToolRequestMapper, ExternalToolResponseMapper } from './externa import { ExternalToolConfigurationService } from './external-tool/service'; import { ExternalToolConfigurationUc, ExternalToolUc } from './external-tool/uc'; import { ToolSchoolController } from './school-external-tool/controller'; -import { SchoolExternalToolRequestMapper, SchoolExternalToolResponseMapper } from './school-external-tool/mapper'; import { SchoolExternalToolUc } from './school-external-tool/uc'; import { ToolConfigModule } from './tool-config.module'; import { ToolLaunchController } from './tool-launch/controller/tool-launch.controller'; @@ -55,8 +54,6 @@ import { ToolModule } from './tool.module'; ExternalToolRequestMapper, ExternalToolResponseMapper, SchoolExternalToolUc, - SchoolExternalToolResponseMapper, - SchoolExternalToolRequestMapper, ContextExternalToolUc, ToolLaunchUc, ToolReferenceUc, diff --git a/apps/server/src/modules/tool/tool-launch/controller/api-test/tool-launch.controller.api.spec.ts b/apps/server/src/modules/tool/tool-launch/controller/api-test/tool-launch.controller.api.spec.ts index f0e3aec8e24..f85cfcd69a3 100644 --- a/apps/server/src/modules/tool/tool-launch/controller/api-test/tool-launch.controller.api.spec.ts +++ b/apps/server/src/modules/tool/tool-launch/controller/api-test/tool-launch.controller.api.spec.ts @@ -25,10 +25,7 @@ import { externalToolEntityFactory, } from '../../../external-tool/testing'; import { SchoolExternalToolEntity } from '../../../school-external-tool/entity'; -import { - schoolExternalToolConfigurationStatusEntityFactory, - schoolExternalToolEntityFactory, -} from '../../../school-external-tool/testing'; +import { schoolExternalToolEntityFactory } from '../../../school-external-tool/testing'; import { LaunchRequestMethod } from '../../types'; import { ContextExternalToolBodyParams, ContextExternalToolLaunchParams, ToolLaunchRequestResponse } from '../dto'; @@ -242,9 +239,7 @@ describe('ToolLaunchController (API)', () => { const schoolExternalToolEntity: SchoolExternalToolEntity = schoolExternalToolEntityFactory.buildWithId({ tool: externalToolEntity, school, - status: schoolExternalToolConfigurationStatusEntityFactory.build({ - isDeactivated: true, - }), + isDeactivated: true, }); const contextExternalToolEntity: ContextExternalToolEntity = contextExternalToolEntityFactory.buildWithId({ schoolTool: schoolExternalToolEntity, diff --git a/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.repo.spec.ts b/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.repo.spec.ts index 85954491420..7502ecfdce5 100644 --- a/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.repo.spec.ts +++ b/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.repo.spec.ts @@ -6,11 +6,7 @@ import { ExternalToolEntity } from '@modules/tool/external-tool/entity'; import { externalToolEntityFactory } from '@modules/tool/external-tool/testing'; import { SchoolExternalTool } from '@modules/tool/school-external-tool/domain'; import { SchoolExternalToolEntity } from '@modules/tool/school-external-tool/entity'; -import { - schoolExternalToolConfigurationStatusEntityFactory, - schoolExternalToolEntityFactory, - schoolExternalToolFactory, -} from '@modules/tool/school-external-tool/testing'; +import { schoolExternalToolEntityFactory, schoolExternalToolFactory } from '@modules/tool/school-external-tool/testing'; import { SchoolExternalToolQuery } from '@modules/tool/school-external-tool/uc/dto/school-external-tool.types'; import { Test, TestingModule } from '@nestjs/testing'; import { type SchoolEntity } from '@shared/domain/entity'; @@ -55,15 +51,13 @@ describe(SchoolExternalToolRepo.name, () => { const schoolExternalTool1: SchoolExternalToolEntity = schoolExternalToolEntityFactory.buildWithId({ tool: externalToolEntity, school, - status: schoolExternalToolConfigurationStatusEntityFactory.build({ isDeactivated: false }), - }); - const schoolExternalTool2: SchoolExternalToolEntity = schoolExternalToolEntityFactory.buildWithId({ - status: undefined, + isDeactivated: false, }); + const schoolExternalTool2: SchoolExternalToolEntity = schoolExternalToolEntityFactory.buildWithId(); const schoolExternalTool3: SchoolExternalToolEntity = schoolExternalToolEntityFactory.buildWithId({ tool: externalToolEntity, school, - status: schoolExternalToolConfigurationStatusEntityFactory.build({ isDeactivated: true }), + isDeactivated: true, }); return { externalToolEntity, school, schoolExternalTool1, schoolExternalTool2, schoolExternalTool3 }; diff --git a/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.repo.ts b/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.repo.ts index 39f9ce92c82..42aa69db1ca 100644 --- a/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.repo.ts +++ b/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.repo.ts @@ -104,7 +104,7 @@ export class SchoolExternalToolRepo { toolId: entity.tool.id, schoolId: entity.school.id, parameters: ExternalToolRepoMapper.mapCustomParameterEntryEntitiesToDOs(entity.schoolParameters), - status: entity.status, + isDeactivated: entity.isDeactivated, }); } @@ -114,7 +114,7 @@ export class SchoolExternalToolRepo { school: this.em.getReference(SchoolEntity, entityDO.schoolId), tool: this.em.getReference(ExternalToolEntity, entityDO.toolId), schoolParameters: ExternalToolRepoMapper.mapCustomParameterEntryDOsToEntities(entityDO.parameters), - status: entityDO.status, + isDeactivated: entityDO.isDeactivated, }; } } diff --git a/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.scope.ts b/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.scope.ts index 1e5d120d674..1ab1dc0d8b5 100644 --- a/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.scope.ts +++ b/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.scope.ts @@ -1,4 +1,4 @@ -import { SchoolExternalToolEntity } from '@modules/tool/school-external-tool/entity'; +import type { SchoolExternalToolEntity } from '@modules/tool/school-external-tool/entity'; import { EntityId } from '@shared/domain/types'; import { Scope } from '@shared/repo/scope'; @@ -18,10 +18,8 @@ export class SchoolExternalToolScope extends Scope { } byIsDeactivated(isDeactivated?: boolean): this { - if (isDeactivated) { - this.addQuery({ status: { isDeactivated } }); - } else if (isDeactivated === false) { - this.addQuery({ $or: [{ status: { isDeactivated } }, { status: undefined }] }); + if (isDeactivated !== undefined) { + this.addQuery({ isDeactivated }); } return this; } diff --git a/backup/setup/migrations.json b/backup/setup/migrations.json index be63aa0fe27..24a98d9b857 100644 --- a/backup/setup/migrations.json +++ b/backup/setup/migrations.json @@ -107,6 +107,15 @@ "$date": "2024-05-17T14:00:42.414Z" } }, + { + "_id": { + "$oid": "6655e94f06722f2a434c135f" + }, + "name": "Migration20240528140356", + "created_at": { + "$date": "2024-05-28T14:25:19.577Z" + } + }, { "_id": { "$oid": "6656f4835290f6d36be31830" @@ -116,6 +125,15 @@ "$date": "2024-05-29T09:25:23.454Z" } }, + { + "_id": { + "$oid": "6668485aadfd9c4d7be91ca3" + }, + "name": "Migration20240611081033", + "created_at": { + "$date": "2024-06-11T12:51:38.379Z" + } + }, { "_id": { "$oid": "66684c3db14698848e23c0c2" @@ -154,20 +172,11 @@ }, { "_id": { - "$oid": "6655e94f06722f2a434c135f" + "$oid": "667e611e207a39b02c306406" }, - "name": "Migration20240528140356", + "name": "Migration20240627134214", "created_at": { - "$date": "2024-05-28T14:25:19.577Z" - } - }, - { - "_id": { - "$oid": "6668485aadfd9c4d7be91ca3" - }, - "name": "Migration20240611081033", - "created_at": { - "$date": "2024-06-11T12:51:38.379Z" + "$date": "2024-06-28T07:07:10.278Z" } } ] From 3e0995d4edcc9a0ab31f5848530653b1f6695c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20=C3=96hlerking?= Date: Fri, 28 Jun 2024 14:33:02 +0200 Subject: [PATCH 2/6] fix tests --- .../schulconnex-tool-provisioning.service.spec.ts | 9 +++++---- .../service/external-tool-configuration.service.spec.ts | 8 +++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/server/src/modules/provisioning/strategy/oidc/service/schulconnex-tool-provisioning.service.spec.ts b/apps/server/src/modules/provisioning/strategy/oidc/service/schulconnex-tool-provisioning.service.spec.ts index 9601b32ab9a..ed3a05aa0c1 100644 --- a/apps/server/src/modules/provisioning/strategy/oidc/service/schulconnex-tool-provisioning.service.spec.ts +++ b/apps/server/src/modules/provisioning/strategy/oidc/service/schulconnex-tool-provisioning.service.spec.ts @@ -147,14 +147,15 @@ describe(SchulconnexToolProvisioningService.name, () => { await service.provisionSchoolExternalTools(userId, schoolId, systemId); - expect(schoolExternalToolService.saveSchoolExternalTool).toHaveBeenCalledWith({ - props: { + expect(schoolExternalToolService.saveSchoolExternalTool).toHaveBeenCalledWith<[SchoolExternalTool]>( + new SchoolExternalTool({ id: expect.any(String), toolId: externalTool.id, + isDeactivated: false, schoolId, parameters: [], - }, - }); + }) + ); }); }); diff --git a/apps/server/src/modules/tool/external-tool/service/external-tool-configuration.service.spec.ts b/apps/server/src/modules/tool/external-tool/service/external-tool-configuration.service.spec.ts index 54b5149f57a..4afa83fe301 100644 --- a/apps/server/src/modules/tool/external-tool/service/external-tool-configuration.service.spec.ts +++ b/apps/server/src/modules/tool/external-tool/service/external-tool-configuration.service.spec.ts @@ -129,12 +129,12 @@ describe('ExternalToolConfigurationService', () => { availableSchoolExternalTools.forEach((tool): void => { if (tool.id === 'deactivatedToolId') { tool.status = schoolExternalToolConfigurationStatusFactory.build({ - isDeactivated: true, + isGloballyDeactivated: true, isOutdatedOnScopeSchool: false, }); } tool.status = schoolExternalToolConfigurationStatusFactory.build({ - isDeactivated: false, + isGloballyDeactivated: false, isOutdatedOnScopeSchool: false, }); }); @@ -175,9 +175,7 @@ describe('ExternalToolConfigurationService', () => { ); expect( - result.every( - (toolInfo: ContextExternalToolTemplateInfo) => !toolInfo.schoolExternalTool.status?.isDeactivated - ) + result.every((toolInfo: ContextExternalToolTemplateInfo) => !toolInfo.schoolExternalTool.isDeactivated) ).toBe(true); }); }); From b52dbb91f926365d6ae41eac55aa5a4f56616aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20=C3=96hlerking?= Date: Fri, 28 Jun 2024 15:20:42 +0200 Subject: [PATCH 3/6] fix tests --- .../service/external-tool.service.spec.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/apps/server/src/modules/tool/external-tool/service/external-tool.service.spec.ts b/apps/server/src/modules/tool/external-tool/service/external-tool.service.spec.ts index b43a67a37b2..abc6ec6ab07 100644 --- a/apps/server/src/modules/tool/external-tool/service/external-tool.service.spec.ts +++ b/apps/server/src/modules/tool/external-tool/service/external-tool.service.spec.ts @@ -10,6 +10,7 @@ import { ContextExternalToolRepo, ExternalToolRepo, SchoolExternalToolRepo } fro import { LegacyLogger } from '@src/core/logger'; import { ExternalToolSearchQuery } from '../../common/interface'; import { SchoolExternalTool } from '../../school-external-tool/domain'; +import { schoolExternalToolFactory } from '../../school-external-tool/testing'; import { ExternalTool, Lti11ToolConfig, Oauth2ToolConfig } from '../domain'; import { externalToolFactory, lti11ToolConfigFactory, oauth2ToolConfigFactory } from '../testing'; import { ExternalToolServiceMapper } from './external-tool-service.mapper'; @@ -375,16 +376,13 @@ describe(ExternalToolService.name, () => { const setup = () => { createTools(); - const schoolExternalTool: SchoolExternalTool = new SchoolExternalTool({ - id: 'schoolTool1', - toolId: 'tool1', - schoolId: 'school1', - parameters: [], - }); + const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build(); schoolToolRepo.findByExternalToolId.mockResolvedValue([schoolExternalTool]); - return { schoolExternalTool }; + return { + schoolExternalTool, + }; }; describe('when tool id is set', () => { From 1c2e6de3bb7606fbf53d97ad8f47342d3132b4ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20=C3=96hlerking?= Date: Fri, 28 Jun 2024 15:35:36 +0200 Subject: [PATCH 4/6] fix tests --- .../mapper/external-tool-datasheet.mapper.spec.ts | 4 ++-- .../mapper/school-external-tool-request.mapper.spec.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/server/src/modules/tool/external-tool/mapper/external-tool-datasheet.mapper.spec.ts b/apps/server/src/modules/tool/external-tool/mapper/external-tool-datasheet.mapper.spec.ts index 26bc472710c..3cc59845750 100644 --- a/apps/server/src/modules/tool/external-tool/mapper/external-tool-datasheet.mapper.spec.ts +++ b/apps/server/src/modules/tool/external-tool/mapper/external-tool-datasheet.mapper.spec.ts @@ -37,7 +37,7 @@ describe(ExternalToolDatasheetMapper.name, () => { restrictToContexts: [ToolContextType.COURSE, ToolContextType.BOARD_ELEMENT], }); const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build({ - status: { isDeactivated: true }, + isDeactivated: true, }); const expectDatasheet: ExternalToolDatasheetTemplateData = externalToolDatasheetTemplateDataFactory .withOptionalProperties() @@ -68,7 +68,7 @@ describe(ExternalToolDatasheetMapper.name, () => { const school: School = schoolFactory.build(); const externalTool = externalToolFactory.build(); const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build({ - status: { isDeactivated: true }, + isDeactivated: true, }); const expectDatasheet: ExternalToolDatasheetTemplateData = externalToolDatasheetTemplateDataFactory.build({ instance: 'dBildungscloud', diff --git a/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-request.mapper.spec.ts b/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-request.mapper.spec.ts index fd6a02c09d2..abab0048a6e 100644 --- a/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-request.mapper.spec.ts +++ b/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-request.mapper.spec.ts @@ -3,8 +3,6 @@ import { SchoolExternalToolProps } from '../domain'; import { SchoolExternalToolRequestMapper } from './school-external-tool-request.mapper'; describe('SchoolExternalToolRequestMapper', () => { - const mapper: SchoolExternalToolRequestMapper = new SchoolExternalToolRequestMapper(); - describe('mapSchoolExternalToolRequest', () => { describe('when SchoolExternalToolPostParams is given', () => { const setup = () => { @@ -28,7 +26,8 @@ describe('SchoolExternalToolRequestMapper', () => { it('should return an schoolExternalTool', () => { const { param, params } = setup(); - const schoolExternalToolDto: SchoolExternalToolProps = mapper.mapSchoolExternalToolRequest(params); + const schoolExternalToolDto: SchoolExternalToolProps = + SchoolExternalToolRequestMapper.mapSchoolExternalToolRequest(params); expect(schoolExternalToolDto).toEqual({ id: expect.any(String), @@ -57,7 +56,8 @@ describe('SchoolExternalToolRequestMapper', () => { it('should return an schoolExternalTool without parameter', () => { const { params } = setup(); - const schoolExternalToolDto: SchoolExternalToolProps = mapper.mapSchoolExternalToolRequest(params); + const schoolExternalToolDto: SchoolExternalToolProps = + SchoolExternalToolRequestMapper.mapSchoolExternalToolRequest(params); expect(schoolExternalToolDto).toEqual({ id: expect.any(String), From 6c12fc8580948f19a938eae4b64c3a9d2f9f6aa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20=C3=96hlerking?= Date: Fri, 28 Jun 2024 15:56:28 +0200 Subject: [PATCH 5/6] fix tests --- ...hool-external-tool-response.mapper.spec.ts | 116 ------------------ .../school-external-tool.scope.spec.ts | 7 +- 2 files changed, 5 insertions(+), 118 deletions(-) delete mode 100644 apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-response.mapper.spec.ts diff --git a/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-response.mapper.spec.ts b/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-response.mapper.spec.ts deleted file mode 100644 index a3dae02d9ba..00000000000 --- a/apps/server/src/modules/tool/school-external-tool/mapper/school-external-tool-response.mapper.spec.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { SchoolExternalToolResponse, SchoolExternalToolSearchListResponse } from '../controller/dto'; -import { SchoolExternalTool } from '../domain'; -import { - schoolExternalToolConfigurationStatusFactory, - schoolExternalToolConfigurationStatusResponseFactory, - schoolExternalToolFactory, -} from '../testing'; -import { SchoolExternalToolResponseMapper } from './school-external-tool-response.mapper'; - -describe('SchoolExternalToolResponseMapper', () => { - let mapper: SchoolExternalToolResponseMapper; - - beforeAll(() => { - mapper = new SchoolExternalToolResponseMapper(); - }); - - describe('mapToSearchListResponse', () => { - it('should return a schoolExternalToolResponse', () => { - const response: SchoolExternalToolSearchListResponse = mapper.mapToSearchListResponse([]); - - expect(response).toBeInstanceOf(SchoolExternalToolSearchListResponse); - }); - - describe('when parameter are given', () => { - const setup = () => { - const do1: SchoolExternalTool = schoolExternalToolFactory.buildWithId(); - const do2: SchoolExternalTool = schoolExternalToolFactory.buildWithId(); - do2.status = undefined; - - const dos: SchoolExternalTool[] = [do1, do2]; - - return { - dos, - do1, - do2, - }; - }; - - it('should map domain objects correctly', () => { - const { dos, do1, do2 } = setup(); - - const response: SchoolExternalToolSearchListResponse = mapper.mapToSearchListResponse(dos); - - expect(response.data).toEqual( - expect.objectContaining([ - { - id: do1.id, - name: do1.name as string, - schoolId: do1.schoolId, - toolId: do1.toolId, - parameters: [ - { - name: do1.parameters[0].name, - value: do1.parameters[0].value, - }, - ], - status: schoolExternalToolConfigurationStatusResponseFactory.build({ - isOutdatedOnScopeSchool: false, - isDeactivated: false, - }), - }, - { - id: do2.id, - name: do2.name as string, - schoolId: do2.schoolId, - toolId: do2.toolId, - parameters: [ - { - name: do2.parameters[0].name, - value: do2.parameters[0].value, - }, - ], - status: schoolExternalToolConfigurationStatusFactory.build({ - isOutdatedOnScopeSchool: false, - isDeactivated: false, - }), - }, - ]) - ); - }); - }); - - describe('when optional parameter are missing', () => { - const setup = () => { - const do1: SchoolExternalTool = schoolExternalToolFactory.build({ id: undefined }); - do1.name = undefined; - do1.status = undefined; - - const do2: SchoolExternalTool = schoolExternalToolFactory.buildWithId(); - - const dos: SchoolExternalTool[] = [do1, do2]; - - return { - dos, - }; - }; - - it('should set defaults', () => { - const { dos } = setup(); - - const response: SchoolExternalToolSearchListResponse = mapper.mapToSearchListResponse(dos); - - expect(response.data[0]).toEqual( - expect.objectContaining({ - id: '', - name: '', - status: schoolExternalToolConfigurationStatusResponseFactory.build({ - isOutdatedOnScopeSchool: false, - isDeactivated: false, - }), - }) - ); - }); - }); - }); -}); diff --git a/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.scope.spec.ts b/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.scope.spec.ts index 42efc0de412..558d8b68ba3 100644 --- a/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.scope.spec.ts +++ b/apps/server/src/shared/repo/schoolexternaltool/school-external-tool.scope.spec.ts @@ -51,6 +51,7 @@ describe('SchoolExternalToolScope', () => { describe('when isDeactivated parameter is undefined', () => { it('should return scope without added status to query', () => { scope.byIsDeactivated(undefined); + expect(scope.query).toEqual({}); }); }); @@ -58,14 +59,16 @@ describe('SchoolExternalToolScope', () => { describe('when isDeactivated parameter is false', () => { it('should return scope with added status to query', () => { scope.byIsDeactivated(false); - expect(scope.query).toEqual({ $or: [{ status: { isDeactivated: false } }, { status: undefined }] }); + + expect(scope.query).toEqual({ isDeactivated: false }); }); }); describe('when isDeactivated parameter is true', () => { it('should return scope with added status to query', () => { scope.byIsDeactivated(true); - expect(scope.query).toEqual({ status: { isDeactivated: true } }); + + expect(scope.query).toEqual({ isDeactivated: true }); }); }); }); From 594224e9d15c580f8e6fe7ff769509d34bcb1d59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20=C3=96hlerking?= Date: Wed, 3 Jul 2024 09:14:14 +0200 Subject: [PATCH 6/6] fix migration.json --- backup/setup/migrations.json | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/backup/setup/migrations.json b/backup/setup/migrations.json index 24a98d9b857..dbba0355eee 100644 --- a/backup/setup/migrations.json +++ b/backup/setup/migrations.json @@ -107,15 +107,6 @@ "$date": "2024-05-17T14:00:42.414Z" } }, - { - "_id": { - "$oid": "6655e94f06722f2a434c135f" - }, - "name": "Migration20240528140356", - "created_at": { - "$date": "2024-05-28T14:25:19.577Z" - } - }, { "_id": { "$oid": "6656f4835290f6d36be31830" @@ -125,15 +116,6 @@ "$date": "2024-05-29T09:25:23.454Z" } }, - { - "_id": { - "$oid": "6668485aadfd9c4d7be91ca3" - }, - "name": "Migration20240611081033", - "created_at": { - "$date": "2024-06-11T12:51:38.379Z" - } - }, { "_id": { "$oid": "66684c3db14698848e23c0c2" @@ -170,6 +152,24 @@ "$date": "2024-06-12T12:26:01.665Z" } }, + { + "_id": { + "$oid": "6655e94f06722f2a434c135f" + }, + "name": "Migration20240528140356", + "created_at": { + "$date": "2024-05-28T14:25:19.577Z" + } + }, + { + "_id": { + "$oid": "6668485aadfd9c4d7be91ca3" + }, + "name": "Migration20240611081033", + "created_at": { + "$date": "2024-06-11T12:51:38.379Z" + } + }, { "_id": { "$oid": "667e611e207a39b02c306406"