summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLauri Ojansivu <x@xet7.org>2018-04-16 21:27:24 +0300
committerLauri Ojansivu <x@xet7.org>2018-04-16 21:27:24 +0300
commite402200b872026d0a01b89cf50578ab6b49bf103 (patch)
tree614bf240fd85826ab990ace8ba8ec2c5a9dc64d4
parentaede4dd9c5c5a1f1654c4251dbf949761ff9b811 (diff)
parentea289c781075c893a0e3a6f05e96f3b3263f0466 (diff)
downloadwekan-e402200b872026d0a01b89cf50578ab6b49bf103.tar.gz
wekan-e402200b872026d0a01b89cf50578ab6b49bf103.tar.bz2
wekan-e402200b872026d0a01b89cf50578ab6b49bf103.zip
Merge branch 'devel'
-rw-r--r--CHANGELOG.md17
-rw-r--r--Dockerfile25
-rw-r--r--client/components/cards/cardDetails.js33
-rw-r--r--client/components/lists/listHeader.js7
-rw-r--r--client/components/users/userHeader.jade2
-rw-r--r--i18n/es-AR.i18n.json92
-rw-r--r--i18n/es.i18n.json2
-rw-r--r--models/checklistItems.js50
-rw-r--r--models/checklists.js116
-rw-r--r--package.json2
-rw-r--r--sandstorm-pkgdef.capnp4
-rw-r--r--server/authentication.js7
-rw-r--r--snapcraft.yaml20
13 files changed, 253 insertions, 124 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e0d1e55a..d9fa04d7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,20 @@
+# v0.84 2018-04-16 Wekan release
+
+This release adds the following new features:
+
+- [Add Checklist Items REST API](https://github.com/wekan/wekan/commit/9eef5112dc1c1c30590d19fbfd2f615714112a3f).
+
+and fixes the following bugs:
+
+- [Fix Node Fibers 100% CPU issue](https://github.com/wekan/wekan/commit/e26a4824cfb119a15767c4827190a6b9ab65b904);
+- [Plus button on a Swimlane row, always add an element on the first row](https://github.com/wekan/wekan/issues/1577);
+- [Fix Checklist REST API](https://github.com/wekan/wekan/commit/9eef5112dc1c1c30590d19fbfd2f615714112a3f);
+- [Fix Disabling "show cards count" not possible, now zero means disable](https://github.com/wekan/wekan/issues/1570);
+- [Fix Checklist not copied when copied a card and Copy Checklist Template to Many Cards](https://github.com/wekan/wekan/issues/1565);
+- [Fix Filter cards hides checklist items](https://github.com/wekan/wekan/issues/1561).
+
+Thanks to GitHub users andresmanelli, kentonv and xet7 for their contributions.
+
# v0.83 2018-04-12 Wekan release
- Updated translations: Czech and French.
diff --git a/Dockerfile b/Dockerfile
index cb323ab0..38a81cef 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -14,7 +14,7 @@ ARG SRC_PATH
# Set the environment variables (defaults where required)
# paxctl fix for alpine linux: https://github.com/wekan/wekan/issues/1303
ENV BUILD_DEPS="apt-utils gnupg gosu wget curl bzip2 build-essential python git ca-certificates gcc-7 paxctl"
-ENV NODE_VERSION ${NODE_VERSION:-v8.9.3}
+ENV NODE_VERSION ${NODE_VERSION:-v8.11.1}
ENV METEOR_RELEASE ${METEOR_RELEASE:-1.6.0.1}
ENV USE_EDGE ${USE_EDGE:-false}
ENV METEOR_EDGE ${METEOR_EDGE:-1.5-beta.17}
@@ -68,6 +68,29 @@ RUN \
tar xvzf node-${NODE_VERSION}-${ARCHITECTURE}.tar.gz && \
rm node-${NODE_VERSION}-${ARCHITECTURE}.tar.gz && \
mv node-${NODE_VERSION}-${ARCHITECTURE} /opt/nodejs && \
+ \
+ # Remove original node, use Fibers 100% CPU usage issue patched node
+ rm /opt/nodejs/bin/node && \
+ # Node Fibers 100% CPU usage issue:
+ # https://github.com/wekan/wekan-mongodb/issues/2#issuecomment-381453161
+ # https://github.com/meteor/meteor/issues/9796#issuecomment-381676326
+ # https://github.com/sandstorm-io/sandstorm/blob/0f1fec013fe7208ed0fd97eb88b31b77e3c61f42/shell/server/00-startup.js#L99-L129
+ # Also see beginning of wekan/server/authentication.js
+ # import Fiber from "fibers";
+ # Fiber.poolSize = 1e9;
+ # Download node version 8.11.1 that has fix included, node binary copied from Sandstorm
+ # Description at https://releases.wekan.team/node.txt
+ # SHA256SUM: 18c99d5e79e2fe91e75157a31be30e5420787213684d4048eb91e602e092725d
+ echo "18c99d5e79e2fe91e75157a31be30e5420787213684d4048eb91e602e092725d node" >> node-SHASUMS256.txt.asc && \
+ wget https://releases.wekan.team/node && \
+ # Verify Fibers patched node authenticity
+ echo "Fibers patched node authenticity:" && \
+ grep node node-SHASUMS256.txt.asc | shasum -a 256 -c - && \
+ rm -f node-SHASUMS256.txt.asc && \
+ chmod +x node && \
+ mv node /opt/nodejs/bin/ && \
+ \
+ # Create symlinks
ln -s /opt/nodejs/bin/node /usr/bin/node && \
ln -s /opt/nodejs/bin/npm /usr/bin/npm && \
\
diff --git a/client/components/cards/cardDetails.js b/client/components/cards/cardDetails.js
index 421cef53..cdd027e6 100644
--- a/client/components/cards/cardDetails.js
+++ b/client/components/cards/cardDetails.js
@@ -343,9 +343,16 @@ Template.copyCardPopup.events({
cursor.forEach(function() {
'use strict';
const checklist = arguments[0];
+ const checklistId = checklist._id;
checklist.cardId = _id;
checklist._id = null;
- Checklists.insert(checklist);
+ const newChecklistId = Checklists.insert(checklist);
+ ChecklistItems.find({checklistId}).forEach(function(item) {
+ item._id = null;
+ item.checklistId = newChecklistId;
+ item.cardId = _id;
+ ChecklistItems.insert(item);
+ });
});
// copy card comments
@@ -363,17 +370,20 @@ Template.copyCardPopup.events({
});
Template.copyChecklistToManyCardsPopup.events({
- 'click .js-select-list' (evt) {
+ 'click .js-done' () {
const card = Cards.findOne(Session.get('currentCard'));
const oldId = card._id;
card._id = null;
- card.listId = this._id;
- const list = Lists.findOne(card.listId);
- card.boardId = list.boardId;
- const textarea = $(evt.currentTarget).parents('.content').find('textarea');
+ const lSelect = $('.js-select-lists')[0];
+ card.listId = lSelect.options[lSelect.selectedIndex].value;
+ const slSelect = $('.js-select-swimlanes')[0];
+ card.swimlaneId = slSelect.options[slSelect.selectedIndex].value;
+ const bSelect = $('.js-select-boards')[0];
+ card.boardId = bSelect.options[bSelect.selectedIndex].value;
+ const textarea = $('#copy-card-title');
const titleEntry = textarea.val().trim();
// insert new card to the bottom of new list
- card.sort = Lists.findOne(this._id).cards().count();
+ card.sort = Lists.findOne(card.listId).cards().count();
if (titleEntry) {
const titleList = JSON.parse(titleEntry);
@@ -394,9 +404,16 @@ Template.copyChecklistToManyCardsPopup.events({
cursor.forEach(function() {
'use strict';
const checklist = arguments[0];
+ const checklistId = checklist._id;
checklist.cardId = _id;
checklist._id = null;
- Checklists.insert(checklist);
+ const newChecklistId = Checklists.insert(checklist);
+ ChecklistItems.find({checklistId}).forEach(function(item) {
+ item._id = null;
+ item.checklistId = newChecklistId;
+ item.cardId = _id;
+ ChecklistItems.insert(item);
+ });
});
// copy card comments
diff --git a/client/components/lists/listHeader.js b/client/components/lists/listHeader.js
index 60dd6a34..4b6bf196 100644
--- a/client/components/lists/listHeader.js
+++ b/client/components/lists/listHeader.js
@@ -28,14 +28,15 @@ BlazeComponent.extendComponent({
},
showCardsCountForList(count) {
- return count > this.limitToShowCardsCount();
+ const limit = this.limitToShowCardsCount();
+ return limit > 0 && count > limit;
},
events() {
return [{
'click .js-open-list-menu': Popup.open('listAction'),
- 'click .js-add-card' () {
- const listDom = document.getElementById(`js-list-${this.currentData()._id}`);
+ 'click .js-add-card' (evt) {
+ const listDom = $(evt.target).parents(`#js-list-${this.currentData()._id}`)[0];
const listComponent = BlazeComponent.getComponentForElement(listDom);
listComponent.openForm({
position: 'top',
diff --git a/client/components/users/userHeader.jade b/client/components/users/userHeader.jade
index 096745ad..4ac59f45 100644
--- a/client/components/users/userHeader.jade
+++ b/client/components/users/userHeader.jade
@@ -86,5 +86,5 @@ template(name="changeSettingsPopup")
li
label.bold
| {{_ 'show-cards-minimum-count'}}
- input#show-cards-count-at.inline-input.left(type="number" value="#{showCardsCountAt}" min="1" max="99" onkeydown="return false")
+ input#show-cards-count-at.inline-input.left(type="number" value="#{showCardsCountAt}" min="0" max="99" onkeydown="return false")
input.js-apply-show-cards-at.left(type="submit" value="{{_ 'apply'}}")
diff --git a/i18n/es-AR.i18n.json b/i18n/es-AR.i18n.json
index 0d0e53e1..e9a7d38c 100644
--- a/i18n/es-AR.i18n.json
+++ b/i18n/es-AR.i18n.json
@@ -9,10 +9,10 @@
"act-createCard": "agregada __card__ a __list__",
"act-createList": "agregada __list__ a __board__",
"act-addBoardMember": "agregado __member__ a __board__",
- "act-archivedBoard": "__board__ moved to Recycle Bin",
- "act-archivedCard": "__card__ moved to Recycle Bin",
- "act-archivedList": "__list__ moved to Recycle Bin",
- "act-archivedSwimlane": "__swimlane__ moved to Recycle Bin",
+ "act-archivedBoard": "__board__ movido a Papelera de Reciclaje",
+ "act-archivedCard": "__card__ movido a Papelera de Reciclaje",
+ "act-archivedList": "__list__ movido a Papelera de Reciclaje",
+ "act-archivedSwimlane": "__swimlane__ movido a Papelera de Reciclaje",
"act-importBoard": "__board__ importado",
"act-importCard": "__card__ importada",
"act-importList": "__list__ importada",
@@ -27,7 +27,7 @@
"activities": "Actividades",
"activity": "Actividad",
"activity-added": "agregadas %s a %s",
- "activity-archived": "%s moved to Recycle Bin",
+ "activity-archived": "%s movido a Papelera de Reciclaje",
"activity-attached": "adjuntadas %s a %s",
"activity-created": "creadas %s",
"activity-excluded": "excluidas %s de %s",
@@ -45,7 +45,7 @@
"add-attachment": "Agregar Adjunto",
"add-board": "Agregar Tablero",
"add-card": "Agregar Tarjeta",
- "add-swimlane": "Add Swimlane",
+ "add-swimlane": "Agregar Calle",
"add-checklist": "Agregar Lista de Tareas",
"add-checklist-item": "Agregar ítem a lista de tareas",
"add-cover": "Agregar Portadas",
@@ -64,19 +64,19 @@
"and-n-other-card_plural": "Y __count__ otras tarjetas",
"apply": "Aplicar",
"app-is-offline": "Wekan está cargándose, por favor espere. Refrescar la página va a causar pérdida de datos. Si Wekan no se carga, por favor revise que el servidor de Wekan no se haya detenido.",
- "archive": "Move to Recycle Bin",
- "archive-all": "Move All to Recycle Bin",
- "archive-board": "Move Board to Recycle Bin",
- "archive-card": "Move Card to Recycle Bin",
- "archive-list": "Move List to Recycle Bin",
- "archive-swimlane": "Move Swimlane to Recycle Bin",
- "archive-selection": "Move selection to Recycle Bin",
- "archiveBoardPopup-title": "Move Board to Recycle Bin?",
- "archived-items": "Recycle Bin",
- "archived-boards": "Boards in Recycle Bin",
+ "archive": "Mover a Papelera de Reciclaje",
+ "archive-all": "Mover Todo a la Papelera de Reciclaje",
+ "archive-board": "Mover Tablero a la Papelera de Reciclaje",
+ "archive-card": "Mover Tarjeta a la Papelera de Reciclaje",
+ "archive-list": "Mover Lista a la Papelera de Reciclaje",
+ "archive-swimlane": "Mover Calle a la Papelera de Reciclaje",
+ "archive-selection": "Mover selección a la Papelera de Reciclaje",
+ "archiveBoardPopup-title": "¿Mover Tablero a la Papelera de Reciclaje?",
+ "archived-items": "Papelera de Reciclaje",
+ "archived-boards": "Tableros en la Papelera de Reciclaje",
"restore-board": "Restaurar Tablero",
- "no-archived-boards": "No Boards in Recycle Bin.",
- "archives": "Recycle Bin",
+ "no-archived-boards": "No hay tableros en la Papelera de Reciclaje",
+ "archives": "Papelera de Reciclaje",
"assign-member": "Asignar miembro",
"attached": "adjunto(s)",
"attachment": "Adjunto",
@@ -97,16 +97,16 @@
"boardChangeWatchPopup-title": "Alternar Seguimiento",
"boardMenuPopup-title": "Menú del Tablero",
"boards": "Tableros",
- "board-view": "Board View",
- "board-view-swimlanes": "Swimlanes",
+ "board-view": "Vista de Tablero",
+ "board-view-swimlanes": "Calles",
"board-view-lists": "Listas",
"bucket-example": "Como \"Lista de Contenedores\" por ejemplo",
"cancel": "Cancelar",
- "card-archived": "This card is moved to Recycle Bin.",
+ "card-archived": "Esta tarjeta es movida a la Papelera de Reciclaje",
"card-comments-title": "Esta tarjeta tiene %s comentario.",
"card-delete-notice": "Borrar es permanente. Perderás todas las acciones asociadas con esta tarjeta.",
"card-delete-pop": "Todas las acciones van a ser eliminadas del agregador de actividad y no podrás re-abrir la tarjeta. No hay deshacer.",
- "card-delete-suggest-archive": "You can move a card Recycle Bin to remove it from the board and preserve the activity.",
+ "card-delete-suggest-archive": "Tu puedes mover una tarjeta a la Papelera de Reciclaje para removerla del tablero y preservar la actividad.",
"card-due": "Vence",
"card-due-on": "Vence en",
"card-spent": "Tiempo Empleado",
@@ -141,7 +141,7 @@
"clipboard": "Portapapeles o arrastrar y soltar",
"close": "Cerrar",
"close-board": "Cerrar Tablero",
- "close-board-pop": "You will be able to restore the board by clicking the “Recycle Bin” button from the home header.",
+ "close-board-pop": "Podrás restaurar el tablero apretando el botón \"Papelera de Reciclaje\" del encabezado en inicio.",
"color-black": "negro",
"color-blue": "azul",
"color-green": "verde",
@@ -160,9 +160,9 @@
"confirm-checklist-delete-dialog": "¿Estás segur@ que querés borrar la lista de ítems?",
"copy-card-link-to-clipboard": "Copiar enlace a tarjeta en el portapapeles",
"copyCardPopup-title": "Copiar Tarjeta",
- "copyChecklistToManyCardsPopup-title": "Copy Checklist Template to Many Cards",
- "copyChecklistToManyCardsPopup-instructions": "Destination Card Titles and Descriptions in this JSON format",
- "copyChecklistToManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
+ "copyChecklistToManyCardsPopup-title": "Copiar Plantilla Checklist a Muchas Tarjetas",
+ "copyChecklistToManyCardsPopup-instructions": "Títulos y Descripciones de la Tarjeta Destino en este formato JSON",
+ "copyChecklistToManyCardsPopup-format": "[ {\"title\": \"Título de primera tarjeta\", \"description\":\"Descripción de primera tarjeta\"}, {\"title\":\"Título de segunda tarjeta\",\"description\":\"Descripción de segunda tarjeta\"},{\"title\":\"Título de última tarjeta\",\"description\":\"Descripción de última tarjeta\"} ]",
"create": "Crear",
"createBoardPopup-title": "Crear Tablero",
"chooseBoardSourcePopup-title": "Importar tablero",
@@ -188,7 +188,7 @@
"editCardDueDatePopup-title": "Cambiar fecha de vencimiento",
"editCardSpentTimePopup-title": "Cambiar tiempo empleado",
"editLabelPopup-title": "Cambiar Etiqueta",
- "editNotificationPopup-title": "Editar Notificació",
+ "editNotificationPopup-title": "Editar Notificación",
"editProfilePopup-title": "Editar Perfil",
"email": "Email",
"email-enrollAccount-subject": "Una cuenta creada para vos en __siteName__",
@@ -264,19 +264,19 @@
"leave-board-pop": "¿Estás seguro que querés dejar __boardTitle__? Vas a salir de todas las tarjetas en este tablero.",
"leaveBoardPopup-title": "¿Dejar Tablero?",
"link-card": "Enlace a esta tarjeta",
- "list-archive-cards": "Move all cards in this list to Recycle Bin",
- "list-archive-cards-pop": "This will remove all the cards in this list from the board. To view cards in Recycle Bin and bring them back to the board, click “Menu” > “Recycle Bin”.",
+ "list-archive-cards": "Mover todas las tarjetas en esta lista a la Papelera de Reciclaje",
+ "list-archive-cards-pop": "Esto va a remover las tarjetas en esta lista del tablero. Para ver tarjetas en la Papelera de Reciclaje y traerlas de vuelta al tablero, clickeá \"Menú\" > \"Papelera de Reciclaje\".",
"list-move-cards": "Mueve todas las tarjetas en esta lista",
"list-select-cards": "Selecciona todas las tarjetas en esta lista",
"listActionPopup-title": "Listar Acciones",
- "swimlaneActionPopup-title": "Swimlane Actions",
+ "swimlaneActionPopup-title": "Acciones de la Calle",
"listImportCardPopup-title": "Importar una tarjeta Trello",
"listMorePopup-title": "Mas",
"link-list": "Enlace a esta lista",
"list-delete-pop": "Todas las acciones van a ser eliminadas del agregador de actividad y no podás recuperar la lista. No se puede deshacer.",
- "list-delete-suggest-archive": "You can move a list to Recycle Bin to remove it from the board and preserve the activity.",
+ "list-delete-suggest-archive": "Podés mover la lista a la Papelera de Reciclaje para remvoerla del tablero y preservar la actividad.",
"lists": "Listas",
- "swimlanes": "Swimlanes",
+ "swimlanes": "Calles",
"log-out": "Salir",
"log-in": "Entrar",
"loginPopup-title": "Entrar",
@@ -294,9 +294,9 @@
"muted-info": "No serás notificado de ningún cambio en este tablero",
"my-boards": "Mis Tableros",
"name": "Nombre",
- "no-archived-cards": "No cards in Recycle Bin.",
- "no-archived-lists": "No lists in Recycle Bin.",
- "no-archived-swimlanes": "No swimlanes in Recycle Bin.",
+ "no-archived-cards": "No hay tarjetas en la Papelera de Reciclaje",
+ "no-archived-lists": "No hay listas en la Papelera de Reciclaje",
+ "no-archived-swimlanes": "No hay calles en la Papelera de Reciclaje",
"no-results": "No hay resultados",
"normal": "Normal",
"normal-desc": "Puede ver y editar tarjetas. No puede cambiar opciones.",
@@ -332,8 +332,8 @@
"restore": "Restaurar",
"save": "Grabar",
"search": "Buscar",
- "search-cards": "Search from card titles and descriptions on this board",
- "search-example": "Text to search for?",
+ "search-cards": "Buscar en títulos y descripciones de tarjeta en este tablero",
+ "search-example": "¿Texto a buscar?",
"select-color": "Seleccionar Color",
"set-wip-limit-value": "Fijar un límite para el número máximo de tareas en esta lista",
"setWipLimitPopup-title": "Establecer Límite TEP",
@@ -361,7 +361,7 @@
"overtime-hours": "Sobretiempo (horas)",
"overtime": "Sobretiempo",
"has-overtime-cards": "Tiene tarjetas con sobretiempo",
- "has-spenttime-cards": "Has spent time cards",
+ "has-spenttime-cards": "Ha gastado tarjetas de tiempo",
"time": "Hora",
"title": "Título",
"tracking": "Seguimiento",
@@ -374,12 +374,12 @@
"uploaded-avatar": "Cargado un avatar",
"username": "Nombre de usuario",
"view-it": "Verlo",
- "warn-list-archived": "warning: this card is in an list at Recycle Bin",
+ "warn-list-archived": "cuidado; esta tarjeta está en la Papelera de Reciclaje",
"watch": "Seguir",
"watching": "Siguiendo",
"watching-info": "Serás notificado de cualquier cambio en este tablero",
"welcome-board": "Tablero de Bienvenida",
- "welcome-swimlane": "Milestone 1",
+ "welcome-swimlane": "Hito 1",
"welcome-list1": "Básicos",
"welcome-list2": "Avanzado",
"what-to-do": "¿Qué querés hacer?",
@@ -437,10 +437,10 @@
"createdAt": "Creado en",
"verified": "Verificado",
"active": "Activo",
- "card-received": "Received",
- "card-received-on": "Received on",
- "card-end": "End",
- "card-end-on": "Ends on",
- "editCardReceivedDatePopup-title": "Change received date",
- "editCardEndDatePopup-title": "Change end date"
+ "card-received": "Recibido",
+ "card-received-on": "Recibido en",
+ "card-end": "Termino",
+ "card-end-on": "Termina en",
+ "editCardReceivedDatePopup-title": "Cambiar fecha de recepción",
+ "editCardEndDatePopup-title": "Cambiar fecha de término"
} \ No newline at end of file
diff --git a/i18n/es.i18n.json b/i18n/es.i18n.json
index 7dd6baa5..fcb2bbec 100644
--- a/i18n/es.i18n.json
+++ b/i18n/es.i18n.json
@@ -102,7 +102,7 @@
"board-view-lists": "Listas",
"bucket-example": "Como “Cosas por hacer” por ejemplo",
"cancel": "Cancelar",
- "card-archived": "Esta tarjeta se envió a la papelera de reciclaje",
+ "card-archived": "Esta tarjeta se ha enviado a la papelera de reciclaje.",
"card-comments-title": "Esta tarjeta tiene %s comentarios.",
"card-delete-notice": "la eliminación es permanente. Perderás todas las acciones asociadas a esta tarjeta.",
"card-delete-pop": "Se eliminarán todas las acciones del historial de actividades y no se podrá volver a abrir la tarjeta. Esta acción no puede deshacerse.",
diff --git a/models/checklistItems.js b/models/checklistItems.js
index 3c01d476..e075eda2 100644
--- a/models/checklistItems.js
+++ b/models/checklistItems.js
@@ -93,3 +93,53 @@ if (Meteor.isServer) {
itemRemover(userId, doc);
});
}
+
+if (Meteor.isServer) {
+ JsonRoutes.add('GET', '/api/boards/:boardId/cards/:cardId/checklists/:checklistId/items/:itemId', function (req, res) {
+ Authentication.checkUserId( req.userId);
+ const paramItemId = req.params.itemId;
+ const checklistItem = ChecklistItems.findOne({ _id: paramItemId });
+ if (checklistItem) {
+ JsonRoutes.sendResult(res, {
+ code: 200,
+ data: checklistItem,
+ });
+ } else {
+ JsonRoutes.sendResult(res, {
+ code: 500,
+ });
+ }
+ });
+
+ JsonRoutes.add('PUT', '/api/boards/:boardId/cards/:cardId/checklists/:checklistId/items/:itemId', function (req, res) {
+ Authentication.checkUserId( req.userId);
+
+ const paramItemId = req.params.itemId;
+
+ if (req.body.hasOwnProperty('isFinished')) {
+ ChecklistItems.direct.update({_id: paramItemId}, {$set: {isFinished: req.body.isFinished}});
+ }
+ if (req.body.hasOwnProperty('title')) {
+ ChecklistItems.direct.update({_id: paramItemId}, {$set: {title: req.body.title}});
+ }
+
+ JsonRoutes.sendResult(res, {
+ code: 200,
+ data: {
+ _id: paramItemId,
+ },
+ });
+ });
+
+ JsonRoutes.add('DELETE', '/api/boards/:boardId/cards/:cardId/checklists/:checklistId/items/:itemId', function (req, res) {
+ Authentication.checkUserId( req.userId);
+ const paramItemId = req.params.itemId;
+ ChecklistItems.direct.remove({ _id: paramItemId });
+ JsonRoutes.sendResult(res, {
+ code: 200,
+ data: {
+ _id: paramItemId,
+ },
+ });
+ });
+}
diff --git a/models/checklists.js b/models/checklists.js
index 9946f98e..c58453ef 100644
--- a/models/checklists.js
+++ b/models/checklists.js
@@ -34,9 +34,9 @@ Checklists.helpers({
return ChecklistItems.find({ checklistId: this._id }).count();
},
items() {
- return ChecklistItems.find(Filter.mongoSelector({
+ return ChecklistItems.find({
checklistId: this._id,
- }), { sort: ['sort'] });
+ }, { sort: ['sort'] });
},
finishedCount() {
return ChecklistItems.find({
@@ -106,94 +106,90 @@ if (Meteor.isServer) {
if (Meteor.isServer) {
JsonRoutes.add('GET', '/api/boards/:boardId/cards/:cardId/checklists', function (req, res) {
- try {
- Authentication.checkUserId( req.userId);
- const paramCardId = req.params.cardId;
+ Authentication.checkUserId( req.userId);
+ const paramCardId = req.params.cardId;
+ const checklists = Checklists.find({ cardId: paramCardId }).map(function (doc) {
+ return {
+ _id: doc._id,
+ title: doc.title,
+ };
+ });
+ if (checklists) {
JsonRoutes.sendResult(res, {
code: 200,
- data: Checklists.find({ cardId: paramCardId }).map(function (doc) {
- return {
- _id: doc._id,
- title: doc.title,
- };
- }),
+ data: checklists,
});
- }
- catch (error) {
+ } else {
JsonRoutes.sendResult(res, {
- code: 200,
- data: error,
+ code: 500,
});
}
});
JsonRoutes.add('GET', '/api/boards/:boardId/cards/:cardId/checklists/:checklistId', function (req, res) {
- try {
- Authentication.checkUserId( req.userId);
- const paramChecklistId = req.params.checklistId;
- const paramCardId = req.params.cardId;
+ Authentication.checkUserId( req.userId);
+ const paramChecklistId = req.params.checklistId;
+ const paramCardId = req.params.cardId;
+ const checklist = Checklists.findOne({ _id: paramChecklistId, cardId: paramCardId });
+ if (checklist) {
+ checklist.items = ChecklistItems.find({checklistId: checklist._id}).map(function (doc) {
+ return {
+ _id: doc._id,
+ title: doc.title,
+ isFinished: doc.isFinished,
+ };
+ });
JsonRoutes.sendResult(res, {
code: 200,
- data: Checklists.findOne({ _id: paramChecklistId, cardId: paramCardId }),
+ data: checklist,
});
- }
- catch (error) {
+ } else {
JsonRoutes.sendResult(res, {
- code: 200,
- data: error,
+ code: 500,
});
}
});
JsonRoutes.add('POST', '/api/boards/:boardId/cards/:cardId/checklists', function (req, res) {
- try {
- Authentication.checkUserId( req.userId);
- const paramCardId = req.params.cardId;
-
- const checklistToSend = {};
- checklistToSend.cardId = paramCardId;
- checklistToSend.title = req.body.title;
- checklistToSend.items = [];
- const id = Checklists.insert(checklistToSend);
- const checklist = Checklists.findOne({_id: id});
- req.body.items.forEach(function (item) {
- checklist.addItem(item);
- }, this);
-
+ Authentication.checkUserId( req.userId);
+ const paramCardId = req.params.cardId;
+ const id = Checklists.insert({
+ title: req.body.title,
+ cardId: paramCardId,
+ sort: 0,
+ });
+ if (id) {
+ req.body.items.forEach(function (item, idx) {
+ ChecklistItems.insert({
+ cardId: paramCardId,
+ checklistId: id,
+ title: item.title,
+ sort: idx,
+ });
+ });
JsonRoutes.sendResult(res, {
code: 200,
data: {
_id: id,
},
});
- }
- catch (error) {
+ } else {
JsonRoutes.sendResult(res, {
- code: 200,
- data: error,
+ code: 400,
});
}
});
JsonRoutes.add('DELETE', '/api/boards/:boardId/cards/:cardId/checklists/:checklistId', function (req, res) {
- try {
- Authentication.checkUserId( req.userId);
- const paramCommentId = req.params.commentId;
- const paramCardId = req.params.cardId;
- Checklists.remove({ _id: paramCommentId, cardId: paramCardId });
- JsonRoutes.sendResult(res, {
- code: 200,
- data: {
- _id: paramCardId,
- },
- });
- }
- catch (error) {
- JsonRoutes.sendResult(res, {
- code: 200,
- data: error,
- });
- }
+ Authentication.checkUserId( req.userId);
+ const paramChecklistId = req.params.checklistId;
+ Checklists.remove({ _id: paramChecklistId });
+ JsonRoutes.sendResult(res, {
+ code: 200,
+ data: {
+ _id: paramChecklistId,
+ },
+ });
});
}
diff --git a/package.json b/package.json
index 3e979ec4..a0053ca2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "wekan",
- "version": "0.83.0",
+ "version": "0.84.0",
"description": "The open-source Trello-like kanban",
"private": true,
"scripts": {
diff --git a/sandstorm-pkgdef.capnp b/sandstorm-pkgdef.capnp
index 066bb3cb..554f5cc6 100644
--- a/sandstorm-pkgdef.capnp
+++ b/sandstorm-pkgdef.capnp
@@ -22,10 +22,10 @@ const pkgdef :Spk.PackageDefinition = (
appTitle = (defaultText = "Wekan"),
# The name of the app as it is displayed to the user.
- appVersion = 68,
+ appVersion = 69,
# Increment this for every release.
- appMarketingVersion = (defaultText = "0.83.0~2018-04-12"),
+ appMarketingVersion = (defaultText = "0.84.0~2018-04-16"),
# Human-readable presentation of the app version.
minUpgradableAppVersion = 0,
diff --git a/server/authentication.js b/server/authentication.js
index acc101cc..efe95015 100644
--- a/server/authentication.js
+++ b/server/authentication.js
@@ -1,5 +1,12 @@
Meteor.startup(() => {
+ // Node Fibers 100% CPU usage issue
+ // https://github.com/wekan/wekan-mongodb/issues/2#issuecomment-381453161
+ // https://github.com/meteor/meteor/issues/9796#issuecomment-381676326
+ // https://github.com/sandstorm-io/sandstorm/blob/0f1fec013fe7208ed0fd97eb88b31b77e3c61f42/shell/server/00-startup.js#L99-L129
+ import Fiber from "fibers";
+ Fiber.poolSize = 1e9;
+
Accounts.validateLoginAttempt(function (options) {
const user = options.user || {};
return !user.loginDisabled;
diff --git a/snapcraft.yaml b/snapcraft.yaml
index fd123b21..abcd1cc6 100644
--- a/snapcraft.yaml
+++ b/snapcraft.yaml
@@ -81,7 +81,7 @@ parts:
wekan:
source: .
plugin: nodejs
- node-engine: 8.9.3
+ node-engine: 8.11.1
node-packages:
- npm@5.5.1
- node-gyp
@@ -100,6 +100,24 @@ parts:
prepare: |
echo "Cleaning environment first"
rm -rf ~/.meteor ~/.npm /usr/local/lib/node_modules
+ # Node Fibers 100% CPU usage issue:
+ # https://github.com/wekan/wekan-mongodb/issues/2#issuecomment-381453161
+ # https://github.com/meteor/meteor/issues/9796#issuecomment-381676326
+ # https://github.com/sandstorm-io/sandstorm/blob/0f1fec013fe7208ed0fd97eb88b31b77e3c61f42/shell/server/00-startup.js#L99-L129
+ # Also see beginning of wekan/server/authentication.js
+ # import Fiber from "fibers";
+ # Fiber.poolSize = 1e9;
+ # Download node version 8.11.1 that has fix included, node binary copied from Sandstorm
+ # Description at https://releases.wekan.team/node.txt
+ # SHA256SUM: 18c99d5e79e2fe91e75157a31be30e5420787213684d4048eb91e602e092725d
+ echo "18c99d5e79e2fe91e75157a31be30e5420787213684d4048eb91e602e092725d node" >> node-SHASUMS256.txt.asc
+ wget https://releases.wekan.team/node
+ # Verify Fibers patched node authenticity
+ echo "Fibers 100% CPU issue patched node authenticity:"
+ grep node node-SHASUMS256.txt.asc | shasum -a 256 -c -
+ rm -f node-SHASUMS256.txt.asc
+ chmod +x node
+ mv node `which node`
echo "Applying paxctl fix for alpine linux: https://github.com/wekan/wekan/issues/1303"
paxctl -mC `which node`
echo "Installing meteor"