Skip to content

Commit

Permalink
Merge branch 'BC-6871-board-refactor' of https://github.com/hpi-schul…
Browse files Browse the repository at this point in the history
  • Loading branch information
virgilchiriac committed Jun 13, 2024
2 parents 3f0fe3c + e5f7ae7 commit 6ed2c2d
Show file tree
Hide file tree
Showing 17 changed files with 224 additions and 98 deletions.
150 changes: 150 additions & 0 deletions apps/server/src/modules/board/service/board-node.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { Test, TestingModule } from '@nestjs/testing';
import { setupEntities } from '@shared/testing';
import { Card, ColumnBoard } from '../domain';
import { BoardNodeRepo } from '../repo';
import { columnBoardFactory, richTextElementFactory } from '../testing';
import { BoardNodeService } from './board-node.service';
import { BoardNodeDeleteHooksService, ContentElementUpdateService } from './internal';

describe(BoardNodeService.name, () => {
let module: TestingModule;
let service: BoardNodeService;

let boardNodeRepo: DeepMocked<BoardNodeRepo>;
let contentElementUpdateService: DeepMocked<ContentElementUpdateService>;

Check failure on line 15 in apps/server/src/modules/board/service/board-node.service.spec.ts

View workflow job for this annotation

GitHub Actions / nest_lint

'contentElementUpdateService' is assigned a value but never used
let boardNodeDeleteHooksService: DeepMocked<BoardNodeDeleteHooksService>;

Check failure on line 16 in apps/server/src/modules/board/service/board-node.service.spec.ts

View workflow job for this annotation

GitHub Actions / nest_lint

'boardNodeDeleteHooksService' is assigned a value but never used

beforeAll(async () => {
module = await Test.createTestingModule({
providers: [
BoardNodeService,
{
provide: BoardNodeRepo,
useValue: createMock<BoardNodeRepo>(),
},
{
provide: ContentElementUpdateService,
useValue: createMock<ContentElementUpdateService>(),
},
{
provide: BoardNodeDeleteHooksService,
useValue: createMock<BoardNodeDeleteHooksService>(),
},
],
}).compile();

service = module.get(BoardNodeService);
boardNodeRepo = module.get(BoardNodeRepo);
contentElementUpdateService = module.get(ContentElementUpdateService);
boardNodeDeleteHooksService = module.get(BoardNodeDeleteHooksService);

await setupEntities();
});

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

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

describe('findById', () => {
const setup = () => {
const boardNode = columnBoardFactory.build();
boardNodeRepo.findById.mockResolvedValueOnce(boardNode);

return { boardNode };
};

it('should use the repo', async () => {
const { boardNode } = setup();

await service.findById(boardNode.id, 2);

expect(boardNodeRepo.findById).toHaveBeenCalledWith(boardNode.id, 2);
});

it('should return the repo result', async () => {
const { boardNode } = setup();

const result = await service.findById(boardNode.id, 2);

expect(result).toBe(boardNode);
});
});

describe('findByClassAndId', () => {
const setup = () => {
const boardNode = columnBoardFactory.build();
boardNodeRepo.findById.mockResolvedValueOnce(boardNode);

return { boardNode };
};

it('should use the repo', async () => {
const { boardNode } = setup();

await service.findByClassAndId(ColumnBoard, boardNode.id);

expect(boardNodeRepo.findById).toHaveBeenCalledWith(boardNode.id, undefined);
});

it('should return the repo result', async () => {
const { boardNode } = setup();

const result = await service.findByClassAndId(ColumnBoard, boardNode.id);

expect(result).toBe(boardNode);
});

describe('when class doesnt match', () => {
it('should throw error', async () => {
const { boardNode } = setup();

await expect(service.findByClassAndId(Card, boardNode.id)).rejects.toThrowError();
});
});
});

describe('findContentElementById', () => {
const setup = () => {
const element = richTextElementFactory.build();
boardNodeRepo.findById.mockResolvedValueOnce(element);

return { element };
};

it('should use the repo', async () => {
const { element } = setup();

await service.findContentElementById(element.id);

expect(boardNodeRepo.findById).toHaveBeenCalledWith(element.id, undefined);
});

it('should return the repo result', async () => {
const { element } = setup();

const result = await service.findContentElementById(element.id);

expect(result).toBe(element);
});

describe('when node is not a content element', () => {
const setupNoneElement = () => {
const boardNode = columnBoardFactory.build();
boardNodeRepo.findById.mockResolvedValueOnce(boardNode);

return { boardNode };
};

it('should throw error', async () => {
const { boardNode } = setupNoneElement();

await expect(service.findContentElementById(boardNode.id)).rejects.toThrowError();
});
});
});
});
4 changes: 0 additions & 4 deletions apps/server/src/modules/board/service/board-node.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,6 @@ export class BoardNodeService {
const boardNodes = await this.boardNodeRepo.findByIds(ids, depth);
const filteredNodes = boardNodes.filter((node) => node instanceof Constructor);

// if (filteredNodes.length !== ids.length) {
// throw new NotFoundException(`There is no '${Constructor.name}' with these ids`);
// }

return filteredNodes as T[];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ describe('Collaborative Text Editor Controller (API)', () => {
const basePath = Configuration.get('ETHERPAD__PAD_URI') as string;
const expectedPath = `${basePath}/${editorId}`;

const cookieExpiresMilliseconds = Number(Configuration.get('ETHERPAD_COOKIE_EXPIRES_SECONDS')) * 1000;
const cookieExpiresMilliseconds = Number(Configuration.get('ETHERPAD__COOKIE_EXPIRES_SECONDS')) * 1000;
// Remove the last 8 characters from the string to prevent conflict between time of test and code execution
const sessionCookieExpiryDate = new Date(Date.now() + cookieExpiresMilliseconds).toUTCString().slice(0, -8);

Expand Down Expand Up @@ -202,7 +202,7 @@ describe('Collaborative Text Editor Controller (API)', () => {
const basePath = Configuration.get('ETHERPAD__PAD_URI') as string;
const expectedPath = `${basePath}/${editorId}`;

const cookieExpiresMilliseconds = Number(Configuration.get('ETHERPAD_COOKIE_EXPIRES_SECONDS')) * 1000;
const cookieExpiresMilliseconds = Number(Configuration.get('ETHERPAD__COOKIE_EXPIRES_SECONDS')) * 1000;
// Remove the last 8 characters from the string to prevent conflict between time of test and code execution
const sessionCookieExpiryDate = new Date(Date.now() + cookieExpiresMilliseconds).toUTCString().slice(0, -8);

Expand Down Expand Up @@ -273,7 +273,7 @@ describe('Collaborative Text Editor Controller (API)', () => {
const basePath = Configuration.get('ETHERPAD__PAD_URI') as string;
const expectedPath = `${basePath}/${editorId}`;

const cookieExpiresMilliseconds = Number(Configuration.get('ETHERPAD_COOKIE_EXPIRES_SECONDS')) * 1000;
const cookieExpiresMilliseconds = Number(Configuration.get('ETHERPAD__COOKIE_EXPIRES_SECONDS')) * 1000;
// Remove the last 8 characters from the string to prevent conflict between time of test and code execution
const sessionCookieExpiryDate = new Date(Date.now() + cookieExpiresMilliseconds).toUTCString().slice(0, -8);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export interface CollaborativeTextEditorConfig {
ETHERPAD_COOKIE_EXPIRES_SECONDS: number;
ETHERPAD_COOKIE_RELEASE_THRESHOLD: number;
ETHERPAD__COOKIE_EXPIRES_SECONDS: number;
ETHERPAD__COOKIE_RELEASE_THRESHOLD: number;
ETHERPAD__PAD_URI: string;
}
4 changes: 2 additions & 2 deletions apps/server/src/modules/collaborative-text-editor/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import { Configuration } from '@hpi-schul-cloud/commons/lib';
import { EtherpadClientConfig } from '@src/infra/etherpad-client';

export const etherpadClientConfig: EtherpadClientConfig = {
apiKey: Configuration.has('ETHERPAD_API_KEY') ? (Configuration.get('ETHERPAD_API_KEY') as string) : undefined,
basePath: Configuration.has('ETHERPAD_URI') ? (Configuration.get('ETHERPAD_URI') as string) : undefined,
apiKey: Configuration.has('ETHERPAD__API_KEY') ? (Configuration.get('ETHERPAD__API_KEY') as string) : undefined,
basePath: Configuration.has('ETHERPAD__URI') ? (Configuration.get('ETHERPAD__URI') as string) : undefined,
};
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class CollaborativeTextEditorService {
params: GetCollaborativeTextEditorForParentParams
): Promise<CollaborativeTextEditor> {
const sessionExpiryDate = this.buildSessionExpiryDate();
const durationThreshold = Number(this.configService.get('ETHERPAD_COOKIE_RELEASE_THRESHOLD'));
const durationThreshold = Number(this.configService.get('ETHERPAD__COOKIE_RELEASE_THRESHOLD'));
const { parentId } = params;

const groupId = await this.collaborativeTextEditorAdapter.getOrCreateGroupId(parentId);
Expand Down Expand Up @@ -62,7 +62,7 @@ export class CollaborativeTextEditorService {
}

private buildSessionExpiryDate(): Date {
const cookieExpiresMilliseconds = Number(this.configService.get('ETHERPAD_COOKIE_EXPIRES_SECONDS')) * 1000;
const cookieExpiresMilliseconds = Number(this.configService.get('ETHERPAD__COOKIE_EXPIRES_SECONDS')) * 1000;
const sessionCookieExpiryDate = new Date(Date.now() + cookieExpiresMilliseconds);

return sessionCookieExpiryDate;
Expand Down
18 changes: 9 additions & 9 deletions apps/server/src/modules/server/admin-api.server.module.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { Configuration } from '@hpi-schul-cloud/commons';
import { MikroOrmModule } from '@mikro-orm/nestjs';
import { DynamicModule, Module } from '@nestjs/common';
import { DeletionApiModule } from '@modules/deletion/deletion-api.module';
import { FileEntity } from '@modules/files/entity';
import { LegacySchoolAdminApiModule } from '@modules/legacy-school/legacy-school-admin.api-module';
import { UserAdminApiModule } from '@modules/user/user-admin-api.module';
import { DynamicModule, Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { CqrsModule } from '@nestjs/cqrs';
import { ALL_ENTITIES } from '@shared/domain/entity';
import { DB_PASSWORD, DB_URL, DB_USERNAME, createConfigModuleOptions } from '@src/config';
import { LoggerModule } from '@src/core/logger';
import { MongoDatabaseModuleOptions, MongoMemoryDatabaseModule } from '@src/infra/database';
import { RabbitMQWrapperModule, RabbitMQWrapperTestModule } from '@src/infra/rabbitmq';
import { CqrsModule } from '@nestjs/cqrs';
import { DeletionApiModule } from '@modules/deletion/deletion-api.module';
import { LegacySchoolAdminApiModule } from '@modules/legacy-school/legacy-school-admin.api-module';
import { UserAdminApiModule } from '@modules/user/user-admin-api.module';
import { EtherpadClientModule } from '@src/infra/etherpad-client';
import { Configuration } from '@hpi-schul-cloud/commons';
import { RabbitMQWrapperModule, RabbitMQWrapperTestModule } from '@src/infra/rabbitmq';
import { serverConfig } from './server.config';
import { defaultMikroOrmOptions } from './server.module';

Expand All @@ -22,8 +22,8 @@ const serverModules = [
LegacySchoolAdminApiModule,
UserAdminApiModule,
EtherpadClientModule.register({
apiKey: Configuration.has('ETHERPAD_API_KEY') ? (Configuration.get('ETHERPAD_API_KEY') as string) : undefined,
basePath: Configuration.has('ETHERPAD_URI') ? (Configuration.get('ETHERPAD_URI') as string) : undefined,
apiKey: Configuration.has('ETHERPAD__API_KEY') ? (Configuration.get('ETHERPAD__API_KEY') as string) : undefined,
basePath: Configuration.has('ETHERPAD__URI') ? (Configuration.get('ETHERPAD__URI') as string) : undefined,
}),
];

Expand Down
4 changes: 2 additions & 2 deletions apps/server/src/modules/server/server.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ const config: ServerConfig = {
FEATURE_NEXBOARD_COPY_ENABLED: Configuration.get('FEATURE_NEXBOARD_COPY_ENABLED') as boolean,
FEATURE_ETHERPAD_ENABLED: Configuration.get('FEATURE_ETHERPAD_ENABLED') as boolean,
ETHERPAD__PAD_URI: Configuration.get('ETHERPAD__PAD_URI') as string,
ETHERPAD_COOKIE_EXPIRES_SECONDS: Configuration.get('ETHERPAD_COOKIE_EXPIRES_SECONDS') as number,
ETHERPAD_COOKIE_RELEASE_THRESHOLD: Configuration.get('ETHERPAD_COOKIE_RELEASE_THRESHOLD') as number,
ETHERPAD__COOKIE_EXPIRES_SECONDS: Configuration.get('ETHERPAD__COOKIE_EXPIRES_SECONDS') as number,
ETHERPAD__COOKIE_RELEASE_THRESHOLD: Configuration.get('ETHERPAD__COOKIE_RELEASE_THRESHOLD') as number,
I18N__AVAILABLE_LANGUAGES: (Configuration.get('I18N__AVAILABLE_LANGUAGES') as string).split(',') as LanguageType[],
I18N__DEFAULT_LANGUAGE: Configuration.get('I18N__DEFAULT_LANGUAGE') as unknown as LanguageType,
I18N__FALLBACK_LANGUAGE: Configuration.get('I18N__FALLBACK_LANGUAGE') as unknown as LanguageType,
Expand Down
60 changes: 22 additions & 38 deletions config/default.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -783,57 +783,41 @@
"default": true,
"description": "Etherpad feature enabled"
},
"ETHERPAD_API_KEY": {
"default": "",
"type": "string",
"description": "The etherpad api key for sending requests."
},
"ETHERPAD_API_PATH": {
"type": "string",
"default": "/api/1",
"description": "The etherpad api path."
},
"ETHERPAD_URI": {
"type": "string",
"default": "https://dbildungscloud.de/etherpad/api/1",
"description": "The etherpad api version uri."
},
"ETHERPAD_OLD_PAD_URI": {
"type": "string",
"default": "https://etherpad.dbildungscloud.de/p",
"description": "The etherpad api version uri."
},
"ETHERPAD": {
"type": "object",
"description": "Etherpad settings",
"required": ["PAD_URI"],
"properties": {
"URI": {
"type": "string",
"description": "The etherpad api version uri."
},
"PAD_URI": {
"type": "string",
"format": "uri",
"pattern": ".*(?<!/)$",
"description": "The etherpad pad uri"
},
"OLD_PAD_URI": {
"type": "string",
"description": "The etherpad api version uri."
},
"API_KEY": {
"type": "string",
"description": "The etherpad api key for sending requests."
},
"COOKIE_EXPIRES_SECONDS": {
"type": "integer",
"default": 7200,
"description": "Number of seconds after an etherpad cookie expires."
},
"COOKIE_RELEASE_THRESHOLD": {
"type": "integer",
"default": 7200,
"description": "If Session Valid time is smaller than this, a new session is created on request."
}
},
"default": {
"PAD_URI": "https://dbildungscloud.de/etherpad/p"
}
},
"ETHERPAD_OLD_PAD_DOMAIN": {
"type": "string",
"default": "etherpad.dbildungscloud.de",
"description": "The old etherpad domain."
},
"ETHERPAD_COOKIE_EXPIRES_SECONDS": {
"type": "integer",
"default": 28800,
"description": "Number of seconds after an etherpad cookie expires."
},
"ETHERPAD_COOKIE_RELEASE_THRESHOLD": {
"type": "integer",
"default": 7200,
"description": "If Session Valid time is smaller than this, a new session is created on request."
},
"NEXTCLOUD_BASE_URL": {
"type": "string",
"default": "http://nextcloud.localhost:9090",
Expand Down
4 changes: 2 additions & 2 deletions config/development.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@
"API_URL": "http://localhost:8888/v1/",
"TOKEN_ENDPOINT": "http://localhost:8888/realms/SANIS/protocol/openid-connect/token"
},
"ETHERPAD_URI": "http://localhost:9001/api/1/",
"ETHERPAD": {
"PAD_URI": "http://localhost:9001/p"
"PAD_URI": "http://localhost:9001/p",
"URI": "http://localhost:9001/api/1.2.14"
},
"PROVISIONING_SCHULCONNEX_LIZENZ_INFO_URL": "http://localhost:8888/v1/lizenzinfo",
"BOARD_COLLABORATION_URI": "ws://localhost:4450"
Expand Down
6 changes: 3 additions & 3 deletions config/test.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@
"IS_ENABLED_BY_DEFAULT": true,
"IS_VISIBLE": true
},
"ETHERPAD_URI": "http://localhost:9001/api/1/",
"ETHERPAD_API_KEY": "381d67e6347d235ac9446",
"ETHERPAD": {
"PAD_URI": "http://localhost:9001/p"
"URI": "http://localhost:9001/api/1/",
"PAD_URI": "http://localhost:9001/p",
"API_KEY": "381d67e6347d235ac9446"
}
}
Loading

0 comments on commit 6ed2c2d

Please sign in to comment.