Skip to content

Commit

Permalink
BC-6770 - Create a list board (#4914)
Browse files Browse the repository at this point in the history
* implement functionality to create separate list board
* added property 'layout' for existing boards
* adapt column board structure to list board
* added feature flag for list board
  • Loading branch information
uidp authored and bergatco committed May 6, 2024
1 parent 9bb8472 commit 87ac1f0
Show file tree
Hide file tree
Showing 31 changed files with 289 additions and 125 deletions.
19 changes: 19 additions & 0 deletions apps/server/src/migrations/mikro-orm/Migration20240415124640.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Migration } from '@mikro-orm/migrations-mongodb';
import { BoardLayout } from '@shared/domain/domainobject';
import { BoardNodeType } from '@shared/domain/entity';

export class Migration20240415124640 extends Migration {
async up(): Promise<void> {
const columBoardResponse = await this.driver.nativeUpdate<{ type: BoardNodeType; layout: BoardLayout }>(
'boardnodes',
{ $and: [{ type: 'column-board' }, { layout: { $exists: false } }] },
{ layout: BoardLayout.COLUMNS }
);
console.info(`Updated ${columBoardResponse.affectedRows} records in boardnodes`);
}

// eslint-disable-next-line @typescript-eslint/require-await
async down(): Promise<void> {
console.error(`boardnodes cannot be rolled-back. It must be restored from backup!`);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { EntityManager } from '@mikro-orm/mongodb';
import { ServerTestModule } from '@modules/server/server.module';
import { INestApplication } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { BoardExternalReferenceType } from '@shared/domain/domainobject';
import { BoardExternalReferenceType, BoardLayout } from '@shared/domain/domainobject';
import { ColumnBoardNode } from '@shared/domain/entity';
import { TestApiClient, UserAndAccountTestFactory, cleanupCollections, courseFactory } from '@shared/testing';
import { cleanupCollections, courseFactory, TestApiClient, UserAndAccountTestFactory } from '@shared/testing';
import { CreateBoardBodyParams } from '../dto';

const baseRouteName = '/boards';

Expand Down Expand Up @@ -46,14 +47,15 @@ describe(`create board (api)`, () => {
return { loggedInClient, course };
};

it('should return status 204 and board', async () => {
it('should return status 201 and board', async () => {
const { loggedInClient, course } = await setup();
const title = 'new board';

const response = await loggedInClient.post(undefined, {
const response = await loggedInClient.post(undefined, <CreateBoardBodyParams>{
title,
parentId: course.id,
parentType: BoardExternalReferenceType.Course,
layout: BoardLayout.COLUMNS,
});

const boardId = (response.body as { id: string }).id;
Expand All @@ -63,6 +65,78 @@ describe(`create board (api)`, () => {
const dbResult = await em.findOneOrFail(ColumnBoardNode, boardId);
expect(dbResult.title).toEqual(title);
});

describe('Board layout', () => {
describe(`When layout is set to "${BoardLayout.COLUMNS}"`, () => {
it('should create a column board', async () => {
const { loggedInClient, course } = await setup();

const response = await loggedInClient.post(undefined, <CreateBoardBodyParams>{
title: 'new board',
parentId: course.id,
parentType: BoardExternalReferenceType.Course,
layout: BoardLayout.COLUMNS,
});

const boardId = (response.body as { id: string }).id;
expect(response.status).toEqual(201);
expect(boardId).toBeDefined();

const dbResult = await em.findOneOrFail(ColumnBoardNode, boardId);
expect(dbResult.layout).toEqual(BoardLayout.COLUMNS);
});
});

describe(`When layout is set to "${BoardLayout.LIST}"`, () => {
it('should create a list board', async () => {
const { loggedInClient, course } = await setup();

const response = await loggedInClient.post(undefined, <CreateBoardBodyParams>{
title: 'new board',
parentId: course.id,
parentType: BoardExternalReferenceType.Course,
layout: BoardLayout.LIST,
});

const boardId = (response.body as { id: string }).id;
expect(response.status).toEqual(201);
expect(boardId).toBeDefined();

const dbResult = await em.findOneOrFail(ColumnBoardNode, boardId);
expect(dbResult.layout).toEqual(BoardLayout.LIST);
});
});
});

describe('When layout is omitted', () => {
it('should return status 400', async () => {
const { loggedInClient, course } = await setup();

const response = await loggedInClient.post(undefined, <Omit<CreateBoardBodyParams, 'layout'>>{
title: 'new board',
parentId: course.id,
parentType: BoardExternalReferenceType.Course,
layout: undefined,
});

expect(response.status).toEqual(400);
});
});

describe('When layout is invalid', () => {
it('should return status 400', async () => {
const { loggedInClient, course } = await setup();

const response = await loggedInClient.post(undefined, <Omit<CreateBoardBodyParams, 'layout'>>{
title: 'new board',
parentId: course.id,
parentType: BoardExternalReferenceType.Course,
layout: 'invalid',
});

expect(response.status).toEqual(400);
});
});
});

describe('When user is teacher and has no course permission', () => {
Expand All @@ -78,21 +152,21 @@ describe(`create board (api)`, () => {
return { loggedInClient, course };
};

it('should return status 204 and board', async () => {
it('should return status 403', async () => {
const { loggedInClient, course } = await setup();
const title = 'new board';

const response = await loggedInClient.post(undefined, {
title,
const response = await loggedInClient.post(undefined, <CreateBoardBodyParams>{
title: 'new board',
parentId: course.id,
parentType: BoardExternalReferenceType.Course,
layout: BoardLayout.COLUMNS,
});

expect(response.status).toEqual(403);
});
});

describe('When user is student and has course permission', () => {
describe('When user is student and has no course permission', () => {
const setup = async () => {
const { studentAccount, studentUser } = UserAndAccountTestFactory.buildStudent();

Expand All @@ -105,14 +179,14 @@ describe(`create board (api)`, () => {
return { loggedInClient, course };
};

it('should return status 204 and board', async () => {
it('should return status 403', async () => {
const { loggedInClient, course } = await setup();
const title = 'new board';

const response = await loggedInClient.post(undefined, {
title,
const response = await loggedInClient.post(undefined, <CreateBoardBodyParams>{
title: 'new board',
parentId: course.id,
parentType: BoardExternalReferenceType.Course,
layout: BoardLayout.COLUMNS,
});

expect(response.status).toEqual(403);
Expand All @@ -136,10 +210,9 @@ describe(`create board (api)`, () => {

it('should return status 400', async () => {
const { loggedInClient, course } = await setup();
const title = '';

const response = await loggedInClient.post(undefined, {
title,
const response = await loggedInClient.post(undefined, <CreateBoardBodyParams>{
title: '',
parentId: course.id,
parentType: BoardExternalReferenceType.Course,
});
Expand All @@ -163,10 +236,9 @@ describe(`create board (api)`, () => {

it('should return status 400', async () => {
const { loggedInClient, course } = await setup();
const title = 'a'.repeat(101);

const response = await loggedInClient.post(undefined, {
title,
const response = await loggedInClient.post(undefined, <CreateBoardBodyParams>{
title: 'a'.repeat(101),
parentId: course.id,
parentType: BoardExternalReferenceType.Course,
});
Expand All @@ -191,7 +263,7 @@ describe(`create board (api)`, () => {
const { loggedInClient } = await setup();
const title = 'new board';

const response = await loggedInClient.post(undefined, {
const response = await loggedInClient.post(undefined, <CreateBoardBodyParams>{
title,
parentId: '123',
parentType: BoardExternalReferenceType.Course,
Expand All @@ -216,12 +288,12 @@ describe(`create board (api)`, () => {

it('should return status 400', async () => {
const { loggedInClient, course } = await setup();
const title = 'new board';

const response = await loggedInClient.post(undefined, {
title,
const response = await loggedInClient.post(undefined, <Omit<CreateBoardBodyParams, 'parentType'>>{
title: 'new board',
parentId: course.id,
parentType: 'invalid',
layout: BoardLayout.COLUMNS,
});

expect(response.status).toEqual(400);
Expand Down
Loading

0 comments on commit 87ac1f0

Please sign in to comment.