Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

N21-2285 Media Activations Extension #5433

Merged
merged 31 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
0e5f439
update media school license repo and service and scope
sdinkov Jan 15, 2025
afa3431
Merge branch 'main' into N21-2285-update-media-activations-extension-1
sdinkov Jan 15, 2025
65b00df
update do / repo/ mapper / index / test factories for media school li…
sdinkov Jan 16, 2025
34c8086
Merge branch 'main' into N21-2285-update-media-activations-extension-1
sdinkov Jan 16, 2025
2f8d773
update modules and configs
sdinkov Jan 17, 2025
d55e029
update media school license repo
sdinkov Jan 17, 2025
bbb0021
update media available line ucc
sdinkov Jan 17, 2025
5d6564c
update tool config
sdinkov Jan 17, 2025
163dc29
Merge branch 'main' into N21-2285-update-media-activations-extension-1
sdinkov Jan 20, 2025
109e409
update tool config status service
sdinkov Jan 20, 2025
dc59382
Merge branch 'main' into N21-2285-update-media-activations-extension-1
sdinkov Jan 20, 2025
64d5296
update bode copy test
sdinkov Jan 20, 2025
f8ddc40
remove unused import
sdinkov Jan 20, 2025
53fe355
update imports
sdinkov Jan 21, 2025
519b96a
update tool test
sdinkov Jan 21, 2025
ccdbe33
Merge branch 'main' into N21-2285-update-media-activations-extension-1
sdinkov Jan 21, 2025
78ee58d
Merge branch 'main' into N21-2285-update-media-activations-extension-1
sdinkov Jan 21, 2025
a4fc1cc
fix merge - wrong import in tc
sdinkov Jan 21, 2025
4ee5752
update getMediaAvailableLine to make more readable
sdinkov Jan 22, 2025
c7bc630
Merge branch 'main' into N21-2285-update-media-activations-extension-1
sdinkov Jan 22, 2025
525e53b
update review changes
sdinkov Jan 22, 2025
f02f48b
update var name
sdinkov Jan 22, 2025
429081f
update formatting
sdinkov Jan 22, 2025
012634b
Merge branch 'main' into N21-2285-update-media-activations-extension-1
sdinkov Jan 22, 2025
94540f6
Merge branch 'N21-2285-update-media-activations-extension-1' of https…
sdinkov Jan 22, 2025
457b3c8
update method name and var names
sdinkov Jan 22, 2025
d39ed4d
rename private methods
sdinkov Jan 23, 2025
1228649
Merge branch 'main' into N21-2285-update-media-activations-extension-1
sdinkov Jan 23, 2025
70d1a7d
Merge branch 'main' into N21-2285-update-media-activations-extension-1
sdinkov Jan 23, 2025
5929a7a
Merge branch 'main' into N21-2285-update-media-activations-extension-1
sdinkov Jan 23, 2025
521e015
fix scope import
sdinkov Jan 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ describe(VidisSyncService.name, () => {
expect.objectContaining<DeepPartial<MediaSchoolLicenseProps>>({
type: SchoolLicenseType.MEDIA_LICENSE,
mediumId: `${item.offerId as number}`,
school,
schoolId: school.id,
mediaSource,
})
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class VidisSyncService {
const license: MediaSchoolLicense = new MediaSchoolLicense({
id: new ObjectId().toHexString(),
type: SchoolLicenseType.MEDIA_LICENSE,
school,
schoolId: school.id,
mediaSource,
mediumId,
});
Expand Down
4 changes: 3 additions & 1 deletion apps/server/src/modules/board/media-board-api.module.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { AuthorizationModule } from '@modules/authorization';
import { SchoolLicenseModule } from '@modules/school-license';
import { UserLicenseModule } from '@modules/user-license';
import { forwardRef, Module } from '@nestjs/common';
import { LoggerModule } from '@src/core/logger';
import { ToolModule } from '../tool';
import { BoardModule } from './board.module';
import { MediaBoardController, MediaElementController, MediaLineController } from './controller';
import { MediaBoardModule } from './media-board.module';
import { MediaAvailableLineUc, MediaBoardUc, MediaElementUc, MediaLineUc } from './uc';
import { BoardNodePermissionService } from './service';
import { MediaAvailableLineUc, MediaBoardUc, MediaElementUc, MediaLineUc } from './uc';

@Module({
imports: [
Expand All @@ -17,6 +18,7 @@ import { BoardNodePermissionService } from './service';
MediaBoardModule,
ToolModule,
UserLicenseModule,
SchoolLicenseModule,
],
controllers: [MediaBoardController, MediaLineController, MediaElementController],
providers: [BoardNodePermissionService, MediaBoardUc, MediaLineUc, MediaElementUc, MediaAvailableLineUc],
Expand Down
1 change: 1 addition & 0 deletions apps/server/src/modules/board/media-board.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface MediaBoardConfig {
FEATURE_MEDIA_SHELF_ENABLED: boolean;
FEATURE_SCHULCONNEX_MEDIA_LICENSE_ENABLED: boolean;
FEATURE_VIDIS_MEDIA_ACTIVATIONS_ENABLED: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ describe(BoardNodeCopyService.name, () => {
CTL_TOOLS__PREFERRED_TOOLS_LIMIT: 10,
FEATURE_PREFERRED_CTL_TOOLS_ENABLED: false,
PUBLIC_BACKEND_URL: '',
FEATURE_VIDIS_MEDIA_ACTIVATIONS_ENABLED: false,
FEATURE_SCHULCONNEX_MEDIA_LICENSE_ENABLED: false,
};
let contextExternalToolService: DeepMocked<ContextExternalToolService>;
let copyHelperService: DeepMocked<CopyHelperService>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { ObjectId } from '@mikro-orm/mongodb';
import { Action, AuthorizationService } from '@modules/authorization';
import { MediaSchoolLicense, MediaSchoolLicenseService } from '@modules/school-license';
import { mediaSchoolLicenseFactory } from '@modules/school-license/testing';
import { ExternalTool } from '@modules/tool/external-tool/domain';
import { externalToolFactory } from '@modules/tool/external-tool/testing';
import { SchoolExternalTool } from '@modules/tool/school-external-tool/domain';
Expand All @@ -26,14 +28,13 @@ import {
MediaAvailableLineService,
MediaBoardService,
} from '../../service';
import { MediaAvailableLineUc } from './media-available-line.uc';

import {
mediaAvailableLineElementFactory,
mediaAvailableLineFactory,
mediaBoardFactory,
mediaExternalToolElementFactory,
} from '../../testing';
import { MediaAvailableLineUc } from './media-available-line.uc';

describe(MediaAvailableLineUc.name, () => {
let module: TestingModule;
Expand All @@ -46,6 +47,7 @@ describe(MediaAvailableLineUc.name, () => {
let configService: DeepMocked<ConfigService<MediaBoardConfig, true>>;
let mediaBoardService: DeepMocked<MediaBoardService>;
let mediaUserLicenseService: DeepMocked<MediaUserLicenseService>;
let mediaSchoolLicenseService: DeepMocked<MediaSchoolLicenseService>;

beforeAll(async () => {
await setupEntities();
Expand Down Expand Up @@ -81,6 +83,10 @@ describe(MediaAvailableLineUc.name, () => {
provide: MediaUserLicenseService,
useValue: createMock<MediaUserLicenseService>(),
},
{
provide: MediaSchoolLicenseService,
useValue: createMock<MediaSchoolLicenseService>(),
},
],
}).compile();

Expand All @@ -92,22 +98,26 @@ describe(MediaAvailableLineUc.name, () => {
configService = module.get(ConfigService);
mediaBoardService = module.get(MediaBoardService);
mediaUserLicenseService = module.get(MediaUserLicenseService);
mediaSchoolLicenseService = module.get(MediaSchoolLicenseService);
});

afterAll(async () => {
await module.close();
});

afterEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
});

describe('getMediaAvailableLine', () => {
describe('when the user request the available line', () => {
const setup = () => {
configService.get.mockReturnValueOnce(true);
configService.get.mockReturnValueOnce(false);

const config: Partial<MediaBoardConfig> = {
FEATURE_MEDIA_SHELF_ENABLED: true,
FEATURE_SCHULCONNEX_MEDIA_LICENSE_ENABLED: false,
FEATURE_VIDIS_MEDIA_ACTIVATIONS_ENABLED: false,
};
configService.get.mockImplementation((key: keyof MediaBoardConfig) => config[key]);
const user: User = userFactory.build();
authorizationService.getUserWithPermissions.mockResolvedValueOnce(user);

Expand Down Expand Up @@ -234,10 +244,16 @@ describe(MediaAvailableLineUc.name, () => {
});
});

describe('when licensing feature flag is enabled', () => {
describe('when licensing feature flag FEATURE_SCHULCONNEX_MEDIA_LICENSE_ENABLED is enabled', () => {
const config: Partial<MediaBoardConfig> = {
FEATURE_MEDIA_SHELF_ENABLED: true,
FEATURE_SCHULCONNEX_MEDIA_LICENSE_ENABLED: true,
FEATURE_VIDIS_MEDIA_ACTIVATIONS_ENABLED: false,
};

describe('when tool has no mediumId', () => {
const setup = () => {
configService.get.mockReturnValue(true);
configService.get.mockImplementation((key: keyof MediaBoardConfig) => config[key]);

const user: User = userFactory.build();
const mediaBoard: MediaBoard = mediaBoardFactory.build();
Expand Down Expand Up @@ -416,6 +432,193 @@ describe(MediaAvailableLineUc.name, () => {
});
});

describe('when licensing feature flag FEATURE_VIDIS_MEDIA_ACTIVATIONS_ENABLED is enabled', () => {
const config: Partial<MediaBoardConfig> = {
FEATURE_MEDIA_SHELF_ENABLED: true,
FEATURE_SCHULCONNEX_MEDIA_LICENSE_ENABLED: false,
FEATURE_VIDIS_MEDIA_ACTIVATIONS_ENABLED: true,
};

describe('when tool has no mediumId', () => {
const setup = () => {
configService.get.mockImplementation((key: keyof MediaBoardConfig) => config[key]);

const user: User = userFactory.build();
const mediaBoard: MediaBoard = mediaBoardFactory.build();
const mediaAvailableLineElement: MediaAvailableLineElement = mediaAvailableLineElementFactory.build();
const mediaAvailableLine: MediaAvailableLine = mediaAvailableLineFactory
.withElement(mediaAvailableLineElement)
.build();
const externalTool1: ExternalTool = externalToolFactory.build();
const externalTool2: ExternalTool = externalToolFactory.build();
const schoolExternalTool1: SchoolExternalTool = schoolExternalToolFactory.build({ toolId: externalTool1.id });
const schoolExternalTool2: SchoolExternalTool = schoolExternalToolFactory.build({ toolId: externalTool2.id });

mediaSchoolLicenseService.findMediaSchoolLicensesBySchoolId.mockResolvedValue([]);

boardNodeService.findByClassAndId.mockResolvedValueOnce(mediaBoard);
mediaAvailableLineService.getUnusedAvailableSchoolExternalTools.mockResolvedValueOnce([
schoolExternalTool1,
schoolExternalTool2,
]);
mediaAvailableLineService.getAvailableExternalToolsForSchool.mockResolvedValueOnce([
externalTool1,
externalTool2,
]);
mediaAvailableLineService.matchTools.mockReturnValueOnce([
[externalTool1, schoolExternalTool1],
[externalTool2, schoolExternalTool2],
]);
mediaAvailableLineService.createMediaAvailableLine.mockReturnValueOnce(mediaAvailableLine);

return {
user,
mediaBoard,
mediaAvailableLineElement,
};
};

it('should not check license', async () => {
const { user, mediaBoard } = setup();

await uc.getMediaAvailableLine(user.id, mediaBoard.id);

expect(mediaSchoolLicenseService.hasLicenseForExternalTool).not.toHaveBeenCalled();
});

it('should return media line', async () => {
const { user, mediaBoard, mediaAvailableLineElement } = setup();

const line: MediaAvailableLine = await uc.getMediaAvailableLine(user.id, mediaBoard.id);

expect(line).toEqual<MediaAvailableLine>({
collapsed: mediaBoard.collapsed,
backgroundColor: mediaBoard.backgroundColor,
elements: [
{
schoolExternalToolId: mediaAvailableLineElement.schoolExternalToolId,
name: mediaAvailableLineElement.name,
description: mediaAvailableLineElement.description,
logoUrl: mediaAvailableLineElement.logoUrl,
},
],
});
});
});

describe('when license exist', () => {
const setup = () => {
configService.get.mockReturnValue(true);

const user: User = userFactory.build();
const mediaBoard: MediaBoard = mediaBoardFactory.build();
const mediaAvailableLineElement: MediaAvailableLineElement = mediaAvailableLineElementFactory.build();
const mediaAvailableLine: MediaAvailableLine = mediaAvailableLineFactory
.withElement(mediaAvailableLineElement)
.build();
const externalTool1: ExternalTool = externalToolFactory.build({ medium: { mediumId: 'mediumId' } });
const externalTool2: ExternalTool = externalToolFactory.build();
const schoolExternalTool1: SchoolExternalTool = schoolExternalToolFactory.build({ toolId: externalTool1.id });
const schoolExternalTool2: SchoolExternalTool = schoolExternalToolFactory.build({ toolId: externalTool2.id });

const mediaSchoolLicense: MediaSchoolLicense = mediaSchoolLicenseFactory.build({ mediumId: 'mediumId' });

mediaSchoolLicenseService.findMediaSchoolLicensesBySchoolId.mockResolvedValue([mediaSchoolLicense]);
mediaSchoolLicenseService.hasLicenseForExternalTool.mockReturnValue(true);

boardNodeService.findByClassAndId.mockResolvedValueOnce(mediaBoard);

mediaAvailableLineService.getUnusedAvailableSchoolExternalTools.mockResolvedValueOnce([
schoolExternalTool1,
schoolExternalTool2,
]);
mediaAvailableLineService.getAvailableExternalToolsForSchool.mockResolvedValueOnce([
externalTool1,
externalTool2,
]);
mediaAvailableLineService.matchTools.mockReturnValueOnce([
[externalTool1, schoolExternalTool1],
[externalTool2, schoolExternalTool2],
]);
mediaAvailableLineService.createMediaAvailableLine.mockReturnValueOnce(mediaAvailableLine);

return {
user,
mediaBoard,
mediaAvailableLineElement,
};
};

it('should check license', async () => {
const { user, mediaBoard } = setup();

await uc.getMediaAvailableLine(user.id, mediaBoard.id);

expect(mediaSchoolLicenseService.hasLicenseForExternalTool).toHaveBeenCalled();
});

it('should return the available line', async () => {
const { user, mediaBoard, mediaAvailableLineElement } = setup();

const line: MediaAvailableLine = await uc.getMediaAvailableLine(user.id, mediaBoard.id);

expect(line).toEqual<MediaAvailableLine>({
collapsed: mediaBoard.collapsed,
backgroundColor: mediaBoard.backgroundColor,
elements: [
{
schoolExternalToolId: mediaAvailableLineElement.schoolExternalToolId,
name: mediaAvailableLineElement.name,
description: mediaAvailableLineElement.description,
logoUrl: mediaAvailableLineElement.logoUrl,
},
],
});
});
});

describe('when license does not exist', () => {
const setup = () => {
configService.get.mockReturnValue(true);

const user: User = userFactory.build();
const mediaBoard: MediaBoard = mediaBoardFactory.build();
const mediaAvailableLine: MediaAvailableLine = mediaAvailableLineFactory.build();
const externalTool1: ExternalTool = externalToolFactory.build({ medium: { mediumId: 'mediumId' } });
const schoolExternalTool1: SchoolExternalTool = schoolExternalToolFactory.build({ toolId: externalTool1.id });

const mediaSchoolLicense: MediaSchoolLicense = mediaSchoolLicenseFactory.build();

mediaSchoolLicenseService.findMediaSchoolLicensesBySchoolId.mockResolvedValue([mediaSchoolLicense]);
mediaSchoolLicenseService.hasLicenseForExternalTool.mockReturnValue(false);

boardNodeService.findByClassAndId.mockResolvedValueOnce(mediaBoard);

mediaAvailableLineService.getUnusedAvailableSchoolExternalTools.mockResolvedValueOnce([schoolExternalTool1]);
mediaAvailableLineService.getAvailableExternalToolsForSchool.mockResolvedValueOnce([externalTool1]);
mediaAvailableLineService.matchTools.mockReturnValueOnce([[externalTool1, schoolExternalTool1]]);
mediaAvailableLineService.createMediaAvailableLine.mockReturnValueOnce(mediaAvailableLine);

return {
user,
mediaBoard,
};
};

it('should show empty avalable line', async () => {
const { user, mediaBoard } = setup();

const line: MediaAvailableLine = await uc.getMediaAvailableLine(user.id, mediaBoard.id);

expect(line).toEqual<MediaAvailableLine>({
collapsed: mediaBoard.collapsed,
backgroundColor: mediaBoard.backgroundColor,
elements: [],
});
});
});
});

describe('when the feature is disabled', () => {
const setup = () => {
configService.get.mockReturnValue(false);
Expand Down
Loading
Loading