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

BC-7008 - element socket actions #5006

Merged
merged 30 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6725e71
WIP: implementation of elementActions
hoeppner-dataport May 14, 2024
201ab93
add moveElement action
hoeppner-dataport May 14, 2024
deafacd
chore: remove unneeded code
hoeppner-dataport May 14, 2024
c4f47d5
fix websocket validation
Metauriel May 14, 2024
b639188
chore: fix merge conflict in test
Metauriel May 14, 2024
8470106
chore: add mapping for contentElements
hoeppner-dataport May 15, 2024
d56dc8c
add missing moveCard parameters
muratmerdoglu-dp May 15, 2024
bf37817
fix: drag And drop of columns
hoeppner-dataport May 16, 2024
4b6b483
Merge branch 'BC-7008-element-socket-actions' of github.com:hpi-schul…
hoeppner-dataport May 16, 2024
7735797
chore: extending move card message with additional parameters
hoeppner-dataport May 17, 2024
1af43dd
Merge branch 'main' of github.com:hpi-schul-cloud/schulcloud-server i…
hoeppner-dataport May 17, 2024
4c67cc3
chore: reduce code duplication
hoeppner-dataport May 17, 2024
9a0efc7
chore: add missing test
hoeppner-dataport May 17, 2024
9633df5
Merge branch 'main' of github.com:hpi-schul-cloud/schulcloud-server i…
hoeppner-dataport May 17, 2024
028352b
Merge branch 'main' of github.com:hpi-schul-cloud/schulcloud-server i…
hoeppner-dataport May 17, 2024
2060d47
chore: remove unneeded import
hoeppner-dataport May 17, 2024
01eaf51
fix: problem with delete element
hoeppner-dataport May 21, 2024
98b8829
Merge branch 'main' of github.com:hpi-schul-cloud/schulcloud-server i…
hoeppner-dataport May 22, 2024
cc28192
fix move card, move column, create element api tests
NFriedo May 22, 2024
09d9d5c
Merge branch 'BC-7008-element-socket-actions' of github.com:hpi-schul…
hoeppner-dataport May 22, 2024
4c2ab51
fix: deleteElement tests
hoeppner-dataport May 22, 2024
71b4960
Merge branch 'main' into BC-7008-element-socket-actions
hoeppner-dataport May 22, 2024
a25f1f4
chore: removed console.logs
hoeppner-dataport May 22, 2024
9b2a482
Merge branch 'main' into BC-7008-element-socket-actions
NFriedo May 23, 2024
7cde1ae
test validation error
Metauriel May 23, 2024
44cc260
Merge branch 'main' of github.com:hpi-schul-cloud/schulcloud-server i…
hoeppner-dataport May 23, 2024
1e40199
Merge branch 'BC-7008-element-socket-actions' of github.com:hpi-schul…
hoeppner-dataport May 23, 2024
0975573
add isOwnAction-property to success actions
hoeppner-dataport May 23, 2024
3eb7b8d
fix unit tests
hoeppner-dataport May 23, 2024
f5def84
Merge branch 'main' of github.com:hpi-schul-cloud/schulcloud-server i…
hoeppner-dataport May 23, 2024
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
4 changes: 2 additions & 2 deletions apps/server/src/modules/board/board-ws-api.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { LoggerModule } from '@src/core/logger';
import { AuthorizationModule } from '../authorization';
import { BoardModule } from './board.module';
import { BoardCollaborationGateway } from './gateway/board-collaboration.gateway';
import { BoardUc, CardUc, ColumnUc } from './uc';
import { BoardUc, CardUc, ColumnUc, ElementUc } from './uc';

@Module({
imports: [BoardModule, forwardRef(() => AuthorizationModule), LoggerModule],
providers: [BoardCollaborationGateway, CardUc, ColumnUc, BoardUc, CourseRepo],
providers: [BoardCollaborationGateway, CardUc, ColumnUc, ElementUc, BoardUc, CourseRepo],
exports: [],
})
export class BoardWsApiModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ export class UpdateElementContentBodyParams {
{ value: RichTextElementContentBody, name: ContentElementType.RICH_TEXT },
{ value: SubmissionContainerElementContentBody, name: ContentElementType.SUBMISSION_CONTAINER },
{ value: ExternalToolElementContentBody, name: ContentElementType.EXTERNAL_TOOL },
{ value: ExternalToolElementContentBody, name: ContentElementType.DRAWING },
{ value: DrawingElementContentBody, name: ContentElementType.DRAWING },
],
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { EntityManager } from '@mikro-orm/mongodb';
import { EntityManager, ObjectId } from '@mikro-orm/mongodb';
import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';

import { BoardExternalReferenceType, CardProps } from '@shared/domain/domainobject';
import { BoardExternalReferenceType, CardProps, ContentElementType } from '@shared/domain/domainobject';
import { InputFormat } from '@shared/domain/types';
import {
cardNodeFactory,
cleanupCollections,
columnBoardNodeFactory,
columnNodeFactory,
courseFactory,
richTextElementNodeFactory,
userFactory,
} from '@shared/testing';
import { getSocketApiClient, waitForEvent } from '@shared/testing/test-socket-api-client';
Expand Down Expand Up @@ -55,19 +57,31 @@ describe(BoardCollaborationGateway.name, () => {
const columnNode = columnNodeFactory.buildWithId({ parent: columnBoardNode });
const columnNode2 = columnNodeFactory.buildWithId({ parent: columnBoardNode });

const cardNodes = cardNodeFactory.buildList(2, { parent: columnNode });
const cardNodes = cardNodeFactory.buildListWithId(2, { parent: columnNode });
const elementNodes = richTextElementNodeFactory.buildListWithId(3, { parent: cardNodes[0] });

await em.persistAndFlush([columnBoardNode, columnNode, columnNode2, ...cardNodes]);
await em.persistAndFlush([columnBoardNode, columnNode, columnNode2, ...cardNodes, ...elementNodes]);

em.clear();

return { user, columnBoardNode, columnNode, columnNode2, cardNodes };
return { user, columnBoardNode, columnNode, columnNode2, cardNodes, elementNodes };
};

it('should be defined', () => {
expect(ws).toBeDefined();
});

describe('validation errors', () => {
it('should answer with failure', async () => {
await setup();
ioClient.emit('create-card-request', { columnId: 'invalid' });

const failure = await waitForEvent(ioClient, 'exception');

expect(failure).toBeDefined();
});
});

describe('create card', () => {
describe('when column exists', () => {
it('should answer with new card', async () => {
Expand All @@ -87,7 +101,7 @@ describe(BoardCollaborationGateway.name, () => {
it('should answer with failure', async () => {
await setup();

ioClient.emit('create-card-request', { columnId: 'non-existing-column' });
ioClient.emit('create-card-request', { columnId: new ObjectId().toHexString() });
const failure = await waitForEvent(ioClient, 'create-card-failure');

expect(failure).toBeDefined();
Expand All @@ -111,7 +125,7 @@ describe(BoardCollaborationGateway.name, () => {
describe('when board does not exist', () => {
it('should answer with failure', async () => {
await setup();
const boardId = 'non-existing-id';
const boardId = new ObjectId().toHexString();

ioClient.emit('fetch-board-request', { boardId });
const failure = await waitForEvent(ioClient, 'fetch-board-failure');
Expand All @@ -131,6 +145,8 @@ describe(BoardCollaborationGateway.name, () => {
oldIndex: 0,
newIndex: 0,
fromColumnId: columnNode.id,
fromColumnIndex: 0,
toColumnIndex: 1,
toColumnId: columnNode2.id,
};

Expand All @@ -150,6 +166,8 @@ describe(BoardCollaborationGateway.name, () => {
oldIndex: 0,
newIndex: 1,
fromColumnId: columnNode.id,
fromColumnIndex: 0,
toColumnIndex: 0,
toColumnId: columnNode.id,
};

Expand All @@ -165,11 +183,13 @@ describe(BoardCollaborationGateway.name, () => {
const { columnNode } = await setup();

const moveCardProps = {
cardId: 'non-existing-card',
cardId: new ObjectId().toHexString(),
oldIndex: 0,
newIndex: 1,
fromColumnId: columnNode.id,
fromColumnIndex: 0,
toColumnId: columnNode.id,
toColumnIndex: 0,
};

ioClient.emit('move-card-request', moveCardProps);
Expand All @@ -196,7 +216,7 @@ describe(BoardCollaborationGateway.name, () => {
it('should answer with failure', async () => {
await setup();

ioClient.emit('update-column-title-request', { columnId: 'non-existing-id', newTitle: 'new title' });
ioClient.emit('update-column-title-request', { columnId: new ObjectId().toHexString(), newTitle: 'new title' });
const failure = await waitForEvent(ioClient, 'update-column-title-failure');

expect(failure).toBeDefined();
Expand All @@ -220,7 +240,7 @@ describe(BoardCollaborationGateway.name, () => {
describe('when board does not exist', () => {
it('should answer with failure', async () => {
await setup();
const boardId = 'non-existing-id';
const boardId = new ObjectId().toHexString();

ioClient.emit('delete-board-request', { boardId });
const failure = await waitForEvent(ioClient, 'delete-board-failure');
Expand All @@ -246,7 +266,7 @@ describe(BoardCollaborationGateway.name, () => {
describe('when board does not exist', () => {
it('should answer with failure', async () => {
await setup();
const boardId = 'non-existing-id';
const boardId = new ObjectId().toHexString();

ioClient.emit('update-board-title-request', { boardId, newTitle: 'new title' });
const failure = await waitForEvent(ioClient, 'update-board-title-failure');
Expand All @@ -272,7 +292,7 @@ describe(BoardCollaborationGateway.name, () => {
describe('when board does not exist', () => {
it('should answer with failure', async () => {
await setup();
const boardId = 'non-existing-id';
const boardId = new ObjectId().toHexString();

ioClient.emit('create-column-request', { boardId });
const failure = await waitForEvent(ioClient, 'create-column-failure');
Expand All @@ -298,7 +318,7 @@ describe(BoardCollaborationGateway.name, () => {
describe('when board does not exist', () => {
it('should answer with failure', async () => {
await setup();
const boardId = 'non-existing-id';
const boardId = new ObjectId().toHexString();

ioClient.emit('update-board-visibility-request', { boardId, isVisible: false });
const failure = await waitForEvent(ioClient, 'update-board-visibility-failure');
Expand All @@ -324,7 +344,7 @@ describe(BoardCollaborationGateway.name, () => {
describe('when column does not exist', () => {
it('should answer with failure', async () => {
await setup();
const columnId = 'not-existing-id';
const columnId = new ObjectId().toHexString();

ioClient.emit('delete-column-request', { columnId });
const failure = await waitForEvent(ioClient, 'delete-column-failure');
Expand All @@ -340,9 +360,7 @@ describe(BoardCollaborationGateway.name, () => {
const { columnBoardNode, columnNode } = await setup();

const moveColumnProps = {
columnId: columnNode.id,
targetBoardId: columnBoardNode.id,
newIndex: 1,
columnMove: {
addedIndex: 1,
removedIndex: 0,
Expand All @@ -361,13 +379,13 @@ describe(BoardCollaborationGateway.name, () => {
const { columnBoardNode } = await setup();

const moveColumnProps = {
columnId: 'non-existing-id',
columnId: new ObjectId().toHexString(),
targetBoardId: columnBoardNode.id,
newIndex: 1,
columnMove: {
addedIndex: 1,
removedIndex: 0,
columnId: 'non-existing-id',
columnId: new ObjectId().toHexString(),
},
};

Expand Down Expand Up @@ -395,7 +413,7 @@ describe(BoardCollaborationGateway.name, () => {
describe('when card does not exist', () => {
it('should answer with failure', async () => {
await setup();
const cardId = 'non-existing-id';
const cardId = new ObjectId().toHexString();

ioClient.emit('update-card-title-request', { cardId, newTitle: 'new title' });
const failure = await waitForEvent(ioClient, 'update-card-title-failure');
Expand All @@ -422,7 +440,7 @@ describe(BoardCollaborationGateway.name, () => {
describe('when card does not exist', () => {
it('should answer with failure', async () => {
await setup();
const cardId = 'non-existing-id';
const cardId = new ObjectId().toHexString();

ioClient.emit('update-card-height-request', { cardId, newHeight: 200 });
const failure = await waitForEvent(ioClient, 'update-card-height-failure');
Expand All @@ -448,7 +466,7 @@ describe(BoardCollaborationGateway.name, () => {
describe('when card does not exist', () => {
it('should answer with failure', async () => {
await setup();
const cardId = 'non-existing-id';
const cardId = new ObjectId().toHexString();

ioClient.emit('fetch-card-request', { cardIds: [cardId] });
const failure = await waitForEvent(ioClient, 'fetch-card-failure');
Expand All @@ -467,20 +485,142 @@ describe(BoardCollaborationGateway.name, () => {
ioClient.emit('delete-card-request', { cardId });
const success = await waitForEvent(ioClient, 'delete-card-success');

expect(success).toEqual({ cardId });
expect(success).toEqual(expect.objectContaining({ cardId }));
});
});

describe('when card does not exist', () => {
it('should answer with failure', async () => {
await setup();
const cardId = 'non-existing-id';
const cardId = new ObjectId().toHexString();

ioClient.emit('delete-card-request', { cardIds: [cardId] });
ioClient.emit('delete-card-request', { cardId });
const failure = await waitForEvent(ioClient, 'delete-card-failure');

expect(failure).toBeDefined();
});
});
});

describe('create element', () => {
it('should answer with success', async () => {
const { cardNodes } = await setup();
const cardId = cardNodes[1].id;

ioClient.emit('create-element-request', { cardId, type: ContentElementType.RICH_TEXT });
const success = (await waitForEvent(ioClient, 'create-element-success')) as {
cardId: string;
newElement: unknown;
};

expect(Object.keys(success)).toEqual(expect.arrayContaining(['cardId', 'newElement']));
});

describe('when card does not exist', () => {
it('should answer with failure', async () => {
await setup();
const cardId = new ObjectId().toHexString();

ioClient.emit('create-element-request', { cardId, type: ContentElementType.RICH_TEXT });
const failure = await waitForEvent(ioClient, 'create-element-failure');

expect(failure).toBeDefined();
});
});
});

describe('delete element', () => {
describe('when element exists', () => {
it('should answer with success', async () => {
const { cardNodes, elementNodes } = await setup();
const cardId = cardNodes[0].id;
const elementId = elementNodes[0].id;

ioClient.emit('delete-element-request', { cardId, elementId });
const success = await waitForEvent(ioClient, 'delete-element-success');

expect(success).toEqual(expect.objectContaining({ cardId, elementId }));
});
});

describe('when element does not exist', () => {
it('should answer with failure', async () => {
const { cardNodes } = await setup();
const cardId = cardNodes[0].id;
const elementId = new ObjectId().toHexString();

ioClient.emit('delete-element-request', { cardId, elementId });
const failure = await waitForEvent(ioClient, 'delete-element-failure');

expect(failure).toBeDefined();
});
});
});

describe('update element', () => {
describe('when element exists', () => {
it('should answer with success', async () => {
const { elementNodes } = await setup();
const elementId = elementNodes[0].id;

const payload = {
elementId,
data: {
type: ContentElementType.RICH_TEXT,
content: { text: 'some new text', inputFormat: InputFormat.PLAIN_TEXT },
},
};

ioClient.emit('update-element-request', payload);
const success = await waitForEvent(ioClient, 'update-element-success');

expect(success).toEqual(expect.objectContaining(payload));
});
});

describe('when element does not exist', () => {
it('should answer with failure', async () => {
await setup();
const elementId = new ObjectId().toHexString();

ioClient.emit('update-element-request', {
elementId,
data: {
type: ContentElementType.RICH_TEXT,
content: { text: 'some new text', inputFormat: InputFormat.PLAIN_TEXT },
},
});
const failure = await waitForEvent(ioClient, 'update-element-failure');

expect(failure).toBeDefined();
});
});
});

describe('move element', () => {
describe('when element exists', () => {
it('should answer with success', async () => {
const { cardNodes, elementNodes } = await setup();
const data = { elementId: elementNodes[0].id, toCardId: cardNodes[0].id, toPosition: 2 };

ioClient.emit('move-element-request', data);
const success = await waitForEvent(ioClient, 'move-element-success');

expect(success).toEqual(expect.objectContaining(data));
});
});

describe('when element does not exist', () => {
it('should answer with failure', async () => {
const { cardNodes } = await setup();
const elementId = new ObjectId().toHexString();
const toCardId = cardNodes[0].id;

ioClient.emit('move-element-request', { elementId, toCardId, toPosition: 2 });
const failure = await waitForEvent(ioClient, 'move-element-failure');

expect(failure).toBeDefined();
});
});
});
});
Loading
Loading