From a9740782898161442320e8697cba191cde179a58 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 16 Apr 2024 15:20:03 +0200 Subject: [PATCH] feat: server implementation of list sorting --- server/api/controllers/lists/sort.js | 67 +++++++++++++++++++++++++++ server/api/helpers/lists/sort-one.js | 68 ++++++++++++++++++++++++++++ server/config/routes.js | 1 + 3 files changed, 136 insertions(+) create mode 100644 server/api/controllers/lists/sort.js create mode 100644 server/api/helpers/lists/sort-one.js diff --git a/server/api/controllers/lists/sort.js b/server/api/controllers/lists/sort.js new file mode 100644 index 0000000..10e0606 --- /dev/null +++ b/server/api/controllers/lists/sort.js @@ -0,0 +1,67 @@ +const Errors = { + NOT_ENOUGH_RIGHTS: { + notEnoughRights: 'Not enough rights', + }, + LIST_NOT_FOUND: { + listNotFound: 'List not found', + }, +}; + +module.exports = { + inputs: { + id: { + type: 'string', + regex: /^[0-9]+$/, + required: true, + }, + sortType: { + type: 'string', + isIn: ['name_asc', 'duedate_asc', 'createdat_asc', 'createdat_desc'], + defaultsTo: 'name_asc', + }, + }, + + exits: { + notEnoughRights: { + responseType: 'forbidden', + }, + listNotFound: { + responseType: 'notFound', + }, + }, + + async fn(inputs) { + const { currentUser } = this.req; + + let { list } = await sails.helpers.lists + .getProjectPath(inputs.id) + .intercept('pathNotFound', () => Errors.LIST_NOT_FOUND); + + const boardMembership = await BoardMembership.findOne({ + boardId: list.boardId, + userId: currentUser.id, + }); + + if (!boardMembership) { + throw Errors.LIST_NOT_FOUND; // This should rather be NOT_ENOUGH_RIGHTS if it's a permissions issue + } + + if (boardMembership.role !== BoardMembership.Roles.EDITOR) { + throw Errors.NOT_ENOUGH_RIGHTS; + } + + list = await sails.helpers.lists.sortOne.with({ + record: list, + request: this.req, + sortType: inputs.sortType, + }); + + if (!list) { + throw Errors.LIST_NOT_FOUND; + } + + return { + item: list, + }; + }, +}; diff --git a/server/api/helpers/lists/sort-one.js b/server/api/helpers/lists/sort-one.js new file mode 100644 index 0000000..76e5fcc --- /dev/null +++ b/server/api/helpers/lists/sort-one.js @@ -0,0 +1,68 @@ +module.exports = { + inputs: { + record: { + type: 'ref', + required: true, + }, + request: { + type: 'ref', + }, + sortType: { + type: 'string', + isIn: ['name_asc', 'duedate_asc', 'createdat_asc', 'createdat_desc'], + defaultsTo: 'name_asc', + }, + }, + + async fn(inputs) { + const list = await List.findOne({ id: inputs.record.id }); + if (list) { + let cards = await Card.find({ listId: inputs.record.id }); + + switch (inputs.sortType) { + case 'name_asc': + cards.sort((a, b) => a.name.localeCompare(b.name)); + break; + case 'duedate_asc': + cards.sort((a, b) => { + if (a.dueDate === null) return 1; + if (b.dueDate === null) return -1; + return new Date(a.dueDate) - new Date(b.dueDate); + }); + break; + case 'createdat_asc': + cards.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt)); + break; + case 'createdat_desc': + cards.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); + break; + default: + throw new Error("Invalid sort type specified"); + } + + const positions = cards.map((c) => c.position).sort((a, b) => a - b); + + for (let i = 0; i < cards.length; i++) { + let card = cards[i]; + let nextPosition = positions[i]; + + await Card.updateOne({ id: card.id }).set({ + position: nextPosition, + }); + + sails.sockets.broadcast(`board:${card.boardId}`, 'cardUpdate', { + item: { + id: card.id, + position: nextPosition, + }, + }); + } + + sails.sockets.broadcast(`board:${list.boardId}`, 'listSorted', { + item: list, + }, inputs.request); + } + + return list; + }, +}; diff --git a/server/config/routes.js b/server/config/routes.js index 8b88df5..e1961c9 100644 --- a/server/config/routes.js +++ b/server/config/routes.js @@ -50,6 +50,7 @@ module.exports.routes = { 'POST /api/boards/:boardId/lists': 'lists/create', 'PATCH /api/lists/:id': 'lists/update', + 'POST /api/lists/:id/sort': 'lists/sort', 'DELETE /api/lists/:id': 'lists/delete', 'POST /api/lists/:listId/cards': 'cards/create',