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-1976 add media source to license logic #5016

Merged
merged 9 commits into from
May 22, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ describe('Media Board (API)', () => {
const { studentAccount, studentUser } = UserAndAccountTestFactory.buildStudent();

const externalTool = externalToolEntityFactory.build();
const licensedUnusedExternalTool = externalToolEntityFactory.build({ medium: { mediumId: 'mediumId' } });
const licensedUnusedExternalTool = externalToolEntityFactory.withMedium().build();
const unusedExternalTool = externalToolEntityFactory.build({ medium: { mediumId: 'notLicensedByUser' } });
const schoolExternalTool = schoolExternalToolEntityFactory.build({
tool: externalTool,
Expand Down Expand Up @@ -532,6 +532,7 @@ describe('Media Board (API)', () => {
const userLicense: MediaUserLicenseEntity = mediaUserLicenseEntityFactory.build({
user: studentUser,
mediumId: 'mediumId',
mediaSourceId: 'mediaSourceId',
});

await em.persistAndFlush([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ export class MediaAvailableLineUc {
const mediaUserLicenses: MediaUserLicense[] = await this.userLicenseService.getMediaUserLicensesForUser(userId);

matchedTools = matchedTools.filter((tool: [ExternalTool, SchoolExternalTool]): boolean => {
const externalToolMediumId = tool[0]?.medium?.mediumId;
if (externalToolMediumId) {
return this.mediaUserLicenseService.hasLicenseForExternalTool(externalToolMediumId, mediaUserLicenses);
const externalToolMedium = tool[0]?.medium;
if (externalToolMedium) {
return this.mediaUserLicenseService.hasLicenseForExternalTool(externalToolMedium, mediaUserLicenses);
}
return true;
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,18 @@ export class SanisResponseMapper {
}

public static mapToExternalLicenses(licenseInfos: SchulconnexLizenzInfoResponse[]): ExternalLicenseDto[] {
const externalLicenseDtos: ExternalLicenseDto[] = licenseInfos.map(
(license: SchulconnexLizenzInfoResponse) =>
new ExternalLicenseDto({
mediumId: license.target.uid,
mediaSourceId: license.target.partOf,
})
);
const externalLicenseDtos: ExternalLicenseDto[] = licenseInfos.map((license: SchulconnexLizenzInfoResponse) => {
if (license.target.partOf === '') {
license.target.partOf = undefined;
}

const externalLicenseDto: ExternalLicenseDto = new ExternalLicenseDto({
mediumId: license.target.uid,
mediaSourceId: license.target.partOf,
});

return externalLicenseDto;
});

return externalLicenseDtos;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@ export class ExternalToolMediumParams {
@IsNotEmpty()
@ApiPropertyOptional({ type: String, description: 'Publisher of the medium' })
publisher?: string;

@IsString()
@IsOptional()
@IsNotEmpty()
@ApiPropertyOptional({ type: String, description: 'The id of the media source' })
mediaSourceId?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ export class ExternalToolMediumResponse {
@ApiPropertyOptional({ type: String, description: 'Publisher of the medium' })
publisher?: string;

@ApiPropertyOptional({ type: String, description: 'The id of the media source' })
mediaSourceId?: string;

constructor(props: ExternalToolMediumResponse) {
this.mediumId = props.mediumId;
this.publisher = props.publisher;
this.mediaSourceId = props.mediaSourceId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@ export interface ExternalToolMediumProps {
mediumId: string;

publisher?: string;

mediaSourceId?: string;
}

export class ExternalToolMedium {
mediumId: string;

publisher?: string;

mediaSourceId?: string;

constructor(props: ExternalToolMediumProps) {
this.mediumId = props.mediumId;
this.publisher = props.publisher;
this.mediaSourceId = props.mediaSourceId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ export class ExternalToolMediumEntity {
@Property({ nullable: true })
publisher?: string;

@Property({ nullable: true })
mediaSourceId?: string;

constructor(props: ExternalToolMediumEntity) {
this.mediumId = props.mediumId;
this.publisher = props.publisher;
this.mediaSourceId = props.mediaSourceId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export class ExternalToolEntityFactory extends BaseFactory<ExternalToolEntity, E
...medium,
mediumId: 'mediumId',
publisher: 'publisher',
mediaSourceId: 'mediaSourceId',
}),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class ExternalToolFactory extends DoBaseFactory<ExternalTool, ExternalToolProps>
medium: {
mediumId: 'mediumId',
publisher: 'publisher',
mediaSourceId: 'mediaSourceId',
...externalToolMedium,
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -505,8 +505,8 @@ describe('ToolLaunchUc', () => {
const setup = () => {
const user: User = userFactory.build();
const mediaUserLicense: MediaUserLicense = mediaUserLicenseFactory.build();
const externalTool: ExternalTool = externalToolFactory.build({
medium: { mediumId: mediaUserLicense.mediumId },
const externalTool: ExternalTool = externalToolFactory.withMedium().build({
medium: { mediumId: mediaUserLicense.mediumId, mediaSourceId: mediaUserLicense.mediaSourceId },
IgorCapCoder marked this conversation as resolved.
Show resolved Hide resolved
});
const schoolExternalToolId = new ObjectId().toHexString();
const schoolExternalTool: SchoolExternalTool = schoolExternalToolFactory.build({ id: schoolExternalToolId });
Expand Down Expand Up @@ -543,6 +543,7 @@ describe('ToolLaunchUc', () => {

return {
user,
externalTool,
schoolExternalTool,
contextExternalTool,
toolLaunchData,
Expand All @@ -552,11 +553,11 @@ describe('ToolLaunchUc', () => {
};

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

await uc.getSchoolExternalToolLaunchRequest(user.id, contextExternalTool);

expect(mediaUserLicenseService.hasLicenseForExternalTool).toHaveBeenCalledWith(mediaUserLicense.mediumId, [
expect(mediaUserLicenseService.hasLicenseForExternalTool).toHaveBeenCalledWith(externalTool.medium, [
mediaUserLicense,
]);
});
Expand Down
4 changes: 2 additions & 2 deletions apps/server/src/modules/tool/tool-launch/uc/tool-launch.uc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ export class ToolLaunchUc {
const mediaUserLicenses: MediaUserLicense[] = await this.userLicenseService.getMediaUserLicensesForUser(userId);

if (
externalTool.medium?.mediumId &&
!this.mediaUserLicenseService.hasLicenseForExternalTool(externalTool.medium.mediumId, mediaUserLicenses)
externalTool.medium &&
!this.mediaUserLicenseService.hasLicenseForExternalTool(externalTool.medium, mediaUserLicenses)
) {
throw new MissingMediaLicenseLoggableException(externalTool.medium, userId, contextExternalTool);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ExternalToolMedium } from '@modules/tool/external-tool/domain';
import { MediaUserLicense, mediaUserLicenseFactory } from '@modules/user-license';
import { MediaUserLicenseService } from '@modules/user-license/service/media-user-license.service';
import { Test, TestingModule } from '@nestjs/testing';
Expand Down Expand Up @@ -25,60 +26,94 @@ describe(MediaUserLicenseService.name, () => {
describe('hasLicenseForExternalTool', () => {
describe('when user has license', () => {
const setup = () => {
const mediumId = 'mediumId';
const mediaUserLicenses: MediaUserLicense[] = mediaUserLicenseFactory.buildList(2);
mediaUserLicenses[0].mediumId = 'mediumId';
const toolMedium: ExternalToolMedium = {
mediumId: 'mediumId',
mediaSourceId: 'mediaSourceId',
};
const medium = mediaUserLicenseFactory.build({
mediumId: toolMedium.mediumId,
mediaSourceId: toolMedium.mediaSourceId,
});
const unusedMedium = mediaUserLicenseFactory.build();
const mediaUserLicenses: MediaUserLicense[] = [medium, unusedMedium];

return {
toolMedium,
mediaUserLicenses,
};
};

it('should return true', () => {
const { toolMedium, mediaUserLicenses } = setup();

const result = service.hasLicenseForExternalTool(toolMedium, mediaUserLicenses);

expect(result).toEqual(true);
});
});

describe('when user has license without sourceId', () => {
const setup = () => {
const toolMedium: ExternalToolMedium = {
mediumId: 'mediumId',
};
const medium = mediaUserLicenseFactory.build({
mediumId: toolMedium.mediumId,
mediaSourceId: undefined,
});
const unusedMedium = mediaUserLicenseFactory.build();
const mediaUserLicenses: MediaUserLicense[] = [medium, unusedMedium];

return {
mediumId,
toolMedium,
mediaUserLicenses,
};
};

it('should return true', () => {
const { mediumId, mediaUserLicenses } = setup();
const { toolMedium, mediaUserLicenses } = setup();

const result = service.hasLicenseForExternalTool(mediumId, mediaUserLicenses);
const result = service.hasLicenseForExternalTool(toolMedium, mediaUserLicenses);

expect(result).toEqual(true);
});
});

describe('when user has not the correct license', () => {
const setup = () => {
const mediumId = 'mediumId';
const medium: ExternalToolMedium = { mediumId: 'mediumId' };
const mediaUserLicenses: MediaUserLicense[] = mediaUserLicenseFactory.buildList(2);

return {
mediumId,
medium,
mediaUserLicenses,
};
};

it('should return false', () => {
const { mediumId, mediaUserLicenses } = setup();
const { medium, mediaUserLicenses } = setup();

const result = service.hasLicenseForExternalTool(mediumId, mediaUserLicenses);
const result = service.hasLicenseForExternalTool(medium, mediaUserLicenses);

expect(result).toEqual(false);
});
});

describe('when user has no licenses', () => {
const setup = () => {
const mediumId = 'mediumId';
const medium: ExternalToolMedium = { mediumId: 'mediumId' };
const mediaUserLicenses: MediaUserLicense[] = [];

return {
mediumId,
medium,
mediaUserLicenses,
};
};

it('should return false', () => {
const { mediumId, mediaUserLicenses } = setup();
const { medium, mediaUserLicenses } = setup();

const result = service.hasLicenseForExternalTool(mediumId, mediaUserLicenses);
const result = service.hasLicenseForExternalTool(medium, mediaUserLicenses);

expect(result).toEqual(false);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { ExternalToolMedium } from '@modules/tool/external-tool/domain';
import { MediaUserLicense } from '@modules/user-license';
import { Injectable } from '@nestjs/common';

@Injectable()
export class MediaUserLicenseService {
public hasLicenseForExternalTool(externalToolMediumId: string, mediaUserLicenses: MediaUserLicense[]): boolean {
return mediaUserLicenses.some((license: MediaUserLicense) => license.mediumId === externalToolMediumId);
public hasLicenseForExternalTool(
externalToolMedium: ExternalToolMedium,
mediaUserLicenses: MediaUserLicense[]
): boolean {
return mediaUserLicenses.some(
(license: MediaUserLicense) =>
license.mediumId === externalToolMedium.mediumId && license.mediaSourceId === externalToolMedium.mediaSourceId
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export class ExternalToolRepoMapper {
return new ExternalToolMedium({
mediumId: entity.mediumId,
publisher: entity.publisher,
mediaSourceId: entity.mediaSourceId,
});
}

Expand Down Expand Up @@ -137,6 +138,7 @@ export class ExternalToolRepoMapper {
return new ExternalToolMediumEntity({
mediumId: medium.mediumId,
publisher: medium.publisher,
mediaSourceId: medium.mediaSourceId,
});
}

Expand Down
Loading