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-1319 ctl showing tool usage #4543

Merged
merged 25 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f6de63f
N21-1319 externaltool metadata
mrikallab Nov 10, 2023
f1e1044
N21-1319 schoolexternaltool metadata
mrikallab Nov 10, 2023
0abb730
N21-1319 clean up
mrikallab Nov 10, 2023
a683866
N21-1319 add ExternalToolMetadataService
mrikallab Nov 13, 2023
9824bdc
N21-1319 add SchoolExternalToolMetadataService
mrikallab Nov 13, 2023
4475b87
N21-1319 loggable
mrikallab Nov 14, 2023
da62982
N21-1319 unit tests
mrikallab Nov 14, 2023
06954aa
N21-1319 fix unit tests
mrikallab Nov 14, 2023
ac9886a
N21-1319 fix lint
mrikallab Nov 14, 2023
7b597f3
Merge branch 'main' into N21-1319-ctl-showing-tool-usage
mrikallab Nov 14, 2023
280f3c9
N21-1319 review changes
mrikallab Nov 15, 2023
44327fd
N21-1319 clean up
mrikallab Nov 16, 2023
8a6be9a
N21-1319 clean barrelfile
mrikallab Nov 16, 2023
ecdb027
Merge branch 'main' into N21-1319-ctl-showing-tool-usage
mrikallab Nov 16, 2023
6554267
N21-1319 clean up
mrikallab Nov 16, 2023
c7c8067
N21-1319 clean up
mrikallab Nov 16, 2023
68869cd
N21-1319 clean up
mrikallab Nov 16, 2023
5e1fb2c
N21-1319 Review Changes2
mrikallab Nov 16, 2023
9d1f3b6
N21-1319 Review Changes2
mrikallab Nov 16, 2023
d63cb92
N21-1319 service changes
mrikallab Nov 16, 2023
338b9ff
Merge branch 'main' into N21-1319-ctl-showing-tool-usage
mrikallab Nov 16, 2023
f25c3fb
N21-1319 changes
mrikallab Nov 17, 2023
9e29367
N21-1319 adjust seed data
mrikallab Nov 20, 2023
dab99dd
Merge branch 'main' into N21-1319-ctl-showing-tool-usage
mrikallab Nov 20, 2023
eb9cf54
Merge branch 'main' into N21-1319-ctl-showing-tool-usage
mrikallab Nov 20, 2023
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
@@ -0,0 +1,9 @@
import { ToolContextType } from '../enum';
import { ContextExternalToolType } from '../../context-external-tool/entity';

export class ToolContextMapper {
static contextMapping: Record<ToolContextType, ContextExternalToolType> = {
[ToolContextType.COURSE]: ContextExternalToolType.COURSE,
[ToolContextType.BOARD_ELEMENT]: ContextExternalToolType.BOARD_ELEMENT,
};
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { Loaded } from '@mikro-orm/core';
import { EntityManager, ObjectId } from '@mikro-orm/mongodb';
import { ServerTestModule } from '@modules/server';
import { HttpStatus, INestApplication } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { Permission } from '@shared/domain';
import { Permission, SchoolEntity } from '@shared/domain';
import {
cleanupCollections,
contextExternalToolEntityFactory,
externalToolEntityFactory,
externalToolFactory,
schoolExternalToolEntityFactory,
schoolFactory,
TestApiClient,
UserAndAccountTestFactory,
} from '@shared/testing';
import { ServerTestModule } from '@modules/server';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { Response } from 'supertest';
Expand All @@ -20,8 +23,16 @@ import {
CustomParameterTypeParams,
ToolConfigType,
} from '../../../common/enum';
import { ContextExternalToolEntity, ContextExternalToolType } from '../../../context-external-tool/entity';
import { SchoolExternalToolEntity } from '../../../school-external-tool/entity';
import { ExternalToolMetadata } from '../../domain';
import { ExternalToolEntity } from '../../entity';
import { ExternalToolCreateParams, ExternalToolResponse, ExternalToolSearchListResponse } from '../dto';
import {
ExternalToolCreateParams,
ExternalToolResponse,
ExternalToolSearchListResponse,
ExternalToolMetadataResponse,
} from '../dto';

describe('ToolController (API)', () => {
let app: INestApplication;
Expand Down Expand Up @@ -617,4 +628,82 @@ describe('ToolController (API)', () => {
});
});
});

describe('[GET] tools/external-tools/:externalToolId/metadata', () => {
describe('when user is not authenticated', () => {
const setup = () => {
const toolId: string = new ObjectId().toHexString();

return { toolId };
};

it('should return unauthorized', async () => {
const { toolId } = setup();

const response: Response = await testApiClient.get(`${toolId}/metadata`);

expect(response.statusCode).toEqual(HttpStatus.UNAUTHORIZED);
});
});

describe('when externalToolId is given ', () => {
const setup = async () => {
const toolId: string = new ObjectId().toHexString();
const externalToolEntity: ExternalToolEntity = externalToolEntityFactory.buildWithId(undefined, toolId);

const school: SchoolEntity = schoolFactory.buildWithId();
const schoolExternalToolEntitys: SchoolExternalToolEntity[] = schoolExternalToolEntityFactory.buildList(2, {
tool: externalToolEntity,
school,
});

const courseTools: ContextExternalToolEntity[] = contextExternalToolEntityFactory.buildList(3, {
schoolTool: schoolExternalToolEntitys[0],
contextType: ContextExternalToolType.COURSE,
});

const boardTools: ContextExternalToolEntity[] = contextExternalToolEntityFactory.buildList(2, {
schoolTool: schoolExternalToolEntitys[1],
contextType: ContextExternalToolType.BOARD_ELEMENT,
contextId: new ObjectId().toHexString(),
});

const externalToolMetadata: ExternalToolMetadata = new ExternalToolMetadata({
schoolExternalToolCount: 2,
contextExternalToolCountPerContext: { course: 3, boardElement: 2 },
});

const { adminUser, adminAccount } = UserAndAccountTestFactory.buildAdmin({}, [Permission.TOOL_ADMIN]);
await em.persistAndFlush([
adminAccount,
adminUser,
school,
externalToolEntity,
...schoolExternalToolEntitys,
...courseTools,
...boardTools,
]);
em.clear();

const loggedInClient: TestApiClient = await testApiClient.login(adminAccount);

return { loggedInClient, toolId, externalToolEntity, externalToolMetadata };
};

it('should return the metadata of externalTool', async () => {
const { loggedInClient, externalToolEntity } = await setup();

const response: Response = await loggedInClient.get(`${externalToolEntity.id}/metadata`);

expect(response.statusCode).toEqual(HttpStatus.OK);
expect(response.body).toEqual<ExternalToolMetadataResponse>({
schoolExternalToolCount: 2,
contextExternalToolCountPerContext: {
course: 3,
boardElement: 2,
},
});
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ApiProperty } from '@nestjs/swagger';
import { ContextExternalToolType } from '../../../../context-external-tool/entity';

export class ExternalToolMetadataResponse {
@ApiProperty()
schoolExternalToolCount: number;

@ApiProperty({
type: 'object',
properties: Object.fromEntries(
Object.values(ContextExternalToolType).map((key: ContextExternalToolType) => [key, { type: 'number' }])
),
})
contextExternalToolCountPerContext: Record<ContextExternalToolType, number>;

constructor(externalToolMetadataResponse: ExternalToolMetadataResponse) {
this.schoolExternalToolCount = externalToolMetadataResponse.schoolExternalToolCount;
this.contextExternalToolCountPerContext = externalToolMetadataResponse.contextExternalToolCountPerContext;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './context-external-tool-configuration-template.response';
export * from './context-external-tool-configuration-template-list.response';
export * from './school-external-tool-configuration-template.response';
export * from './school-external-tool-configuration-template-list.response';
export * from './external-tool-metadata.response';
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ import { LegacyLogger } from '@src/core/logger';
import { Authenticate, CurrentUser, ICurrentUser } from '@modules/authentication';
import { Response } from 'express';
import { ExternalToolSearchQuery } from '../../common/interface';
import { ExternalTool } from '../domain';
import { ExternalTool, ExternalToolMetadata } from '../domain';
import { ExternalToolLogo } from '../domain/external-tool-logo';
import { ExternalToolRequestMapper, ExternalToolResponseMapper } from '../mapper';

import { ExternalToolRequestMapper, ExternalToolResponseMapper, ExternalToolMetadataMapper } from '../mapper';
import { ExternalToolLogoService } from '../service';
import { ExternalToolCreate, ExternalToolUc, ExternalToolUpdate } from '../uc';
import {
Expand All @@ -30,6 +31,7 @@ import {
ExternalToolSearchParams,
ExternalToolUpdateParams,
SortExternalToolParams,
ExternalToolMetadataResponse,
} from './dto';

@ApiTags('Tool')
Expand Down Expand Up @@ -165,4 +167,26 @@ export class ToolController {
res.setHeader('Cache-Control', 'must-revalidate');
res.send(externalToolLogo.logo);
}

@Get('/:externalToolId/metadata')
@ApiOperation({ summary: 'Gets the metadata of an external tool.' })
@ApiOkResponse({
description: 'Metadata of external tool fetched successfully.',
mrikallab marked this conversation as resolved.
Show resolved Hide resolved
type: ExternalToolMetadataResponse,
})
@ApiUnauthorizedResponse({ description: 'User is not logged in.' })
async getMetaDataForExternalTool(
@CurrentUser() currentUser: ICurrentUser,
@Param() params: ExternalToolIdParams
): Promise<ExternalToolMetadataResponse> {
const externalToolMetadata: ExternalToolMetadata = await this.externalToolUc.getMetadataForExternalTool(
currentUser.userId,
params.externalToolId
);

const mapped: ExternalToolMetadataResponse =
ExternalToolMetadataMapper.mapToExternalToolMetadataResponse(externalToolMetadata);

return mapped;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export class ExternalToolMetadata {
schoolExternalToolCount: number;

contextExternalToolCountPerContext: Record<string, number>;

constructor(externalToolMetadata: ExternalToolMetadata) {
this.schoolExternalToolCount = externalToolMetadata.schoolExternalToolCount;
this.contextExternalToolCountPerContext = externalToolMetadata.contextExternalToolCountPerContext;
}
}
1 change: 1 addition & 0 deletions apps/server/src/modules/tool/external-tool/domain/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './external-tool.do';
export * from './config';
export * from './external-tool-metadata';
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { OauthProviderServiceModule } from '@infra/oauth-provider';
import { EncryptionModule } from '@infra/encryption';
import { ExternalToolRepo } from '@shared/repo';
import { ToolConfigModule } from '../tool-config.module';
import { ExternalToolMetadataMapper } from './mapper';
import { ToolContextMapper } from '../common/mapper/tool-context.mapper';
import {
ExternalToolConfigurationService,
ExternalToolLogoService,
Expand All @@ -13,6 +15,7 @@ import {
ExternalToolServiceMapper,
ExternalToolValidationService,
ExternalToolVersionIncrementService,
ExternalToolMetadataService,
} from './service';
import { CommonToolModule } from '../common';

Expand All @@ -27,13 +30,17 @@ import { CommonToolModule } from '../common';
ExternalToolConfigurationService,
ExternalToolLogoService,
ExternalToolRepo,
ExternalToolMetadataService,
ExternalToolMetadataMapper,
ToolContextMapper,
],
exports: [
ExternalToolService,
ExternalToolValidationService,
ExternalToolVersionIncrementService,
ExternalToolConfigurationService,
ExternalToolLogoService,
ExternalToolMetadataService,
],
})
export class ExternalToolModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ExternalToolMetadataResponse } from '../controller/dto';
import { ExternalToolMetadata } from '../domain';

export class ExternalToolMetadataMapper {
static mapToExternalToolMetadataResponse(externalToolMetadata: ExternalToolMetadata): ExternalToolMetadataResponse {
const externalToolMetadataResponse: ExternalToolMetadataResponse = new ExternalToolMetadataResponse({
schoolExternalToolCount: externalToolMetadata.schoolExternalToolCount,
contextExternalToolCountPerContext: externalToolMetadata.contextExternalToolCountPerContext,
});

return externalToolMetadataResponse;
}
}
1 change: 1 addition & 0 deletions apps/server/src/modules/tool/external-tool/mapper/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './external-tool-request.mapper';
export * from './external-tool-response.mapper';
export * from './external-tool-metadata.mapper';
Loading
Loading