checklistItems.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. ChecklistItems = new Mongo.Collection('checklistItems');
  2. ChecklistItems.attachSchema(new SimpleSchema({
  3. title: {
  4. type: String,
  5. },
  6. sort: {
  7. type: Number,
  8. decimal: true,
  9. },
  10. isFinished: {
  11. type: Boolean,
  12. defaultValue: false,
  13. },
  14. checklistId: {
  15. type: String,
  16. },
  17. cardId: {
  18. type: String,
  19. },
  20. }));
  21. ChecklistItems.allow({
  22. insert(userId, doc) {
  23. return allowIsBoardMemberByCard(userId, Cards.findOne(doc.cardId));
  24. },
  25. update(userId, doc) {
  26. return allowIsBoardMemberByCard(userId, Cards.findOne(doc.cardId));
  27. },
  28. remove(userId, doc) {
  29. return allowIsBoardMemberByCard(userId, Cards.findOne(doc.cardId));
  30. },
  31. fetch: ['userId', 'cardId'],
  32. });
  33. ChecklistItems.before.insert((userId, doc) => {
  34. if (!doc.userId) {
  35. doc.userId = userId;
  36. }
  37. });
  38. // Mutations
  39. ChecklistItems.mutations({
  40. setTitle(title) {
  41. return { $set: { title } };
  42. },
  43. check(){
  44. return { $set: { isFinished: true } };
  45. },
  46. uncheck(){
  47. return { $set: { isFinished: false } };
  48. },
  49. toggleItem() {
  50. return { $set: { isFinished: !this.isFinished } };
  51. },
  52. move(checklistId, sortIndex) {
  53. const cardId = Checklists.findOne(checklistId).cardId;
  54. const mutatedFields = {
  55. cardId,
  56. checklistId,
  57. sort: sortIndex,
  58. };
  59. return {$set: mutatedFields};
  60. },
  61. });
  62. // Activities helper
  63. function itemCreation(userId, doc) {
  64. const card = Cards.findOne(doc.cardId);
  65. const boardId = card.boardId;
  66. Activities.insert({
  67. userId,
  68. activityType: 'addChecklistItem',
  69. cardId: doc.cardId,
  70. boardId,
  71. checklistId: doc.checklistId,
  72. checklistItemId: doc._id,
  73. checklistItemName:doc.title,
  74. });
  75. }
  76. function itemRemover(userId, doc) {
  77. const card = Cards.findOne(doc.cardId);
  78. const boardId = card.boardId;
  79. Activities.insert({
  80. userId,
  81. activityType: 'removedChecklistItem',
  82. cardId: doc.cardId,
  83. boardId,
  84. checklistId: doc.checklistId,
  85. checklistItemId: doc._id,
  86. checklistItemName:doc.title,
  87. });
  88. Activities.remove({
  89. checklistItemId: doc._id,
  90. });
  91. }
  92. function publishCheckActivity(userId, doc){
  93. const card = Cards.findOne(doc.cardId);
  94. const boardId = card.boardId;
  95. let activityType;
  96. if(doc.isFinished){
  97. activityType = 'checkedItem';
  98. }else{
  99. activityType = 'uncheckedItem';
  100. }
  101. const act = {
  102. userId,
  103. activityType,
  104. cardId: doc.cardId,
  105. boardId,
  106. checklistId: doc.checklistId,
  107. checklistItemId: doc._id,
  108. checklistItemName:doc.title,
  109. };
  110. Activities.insert(act);
  111. }
  112. function publishChekListCompleted(userId, doc){
  113. const card = Cards.findOne(doc.cardId);
  114. const boardId = card.boardId;
  115. const checklistId = doc.checklistId;
  116. const checkList = Checklists.findOne({_id:checklistId});
  117. if(checkList.isFinished()){
  118. const act = {
  119. userId,
  120. activityType: 'completeChecklist',
  121. cardId: doc.cardId,
  122. boardId,
  123. checklistId: doc.checklistId,
  124. checklistName: checkList.title,
  125. };
  126. Activities.insert(act);
  127. }
  128. }
  129. function publishChekListUncompleted(userId, doc){
  130. const card = Cards.findOne(doc.cardId);
  131. const boardId = card.boardId;
  132. const checklistId = doc.checklistId;
  133. const checkList = Checklists.findOne({_id:checklistId});
  134. // BUGS in IFTTT Rules: https://github.com/wekan/wekan/issues/1972
  135. // Currently in checklist all are set as uncompleted/not checked,
  136. // IFTTT Rule does not move card to other list.
  137. // If following line is negated/changed to:
  138. // if(!checkList.isFinished()){
  139. // then unchecking of any checkbox will move card to other list,
  140. // even when all checkboxes are not yet unchecked.
  141. // What is correct code for only moving when all in list is unchecked?
  142. // TIPS: Finding files, ignoring some directories with grep -v:
  143. // cd wekan
  144. // find . | xargs grep 'count' -sl | grep -v .meteor | grep -v node_modules | grep -v .build
  145. // Maybe something related here?
  146. // wekan/client/components/rules/triggers/checklistTriggers.js
  147. if(checkList.isFinished()){
  148. const act = {
  149. userId,
  150. activityType: 'uncompleteChecklist',
  151. cardId: doc.cardId,
  152. boardId,
  153. checklistId: doc.checklistId,
  154. checklistName: checkList.title,
  155. };
  156. Activities.insert(act);
  157. }
  158. }
  159. // Activities
  160. if (Meteor.isServer) {
  161. Meteor.startup(() => {
  162. ChecklistItems._collection._ensureIndex({ checklistId: 1 });
  163. });
  164. ChecklistItems.after.update((userId, doc, fieldNames) => {
  165. publishCheckActivity(userId, doc);
  166. publishChekListCompleted(userId, doc, fieldNames);
  167. });
  168. ChecklistItems.before.update((userId, doc, fieldNames) => {
  169. publishChekListUncompleted(userId, doc, fieldNames);
  170. });
  171. ChecklistItems.after.insert((userId, doc) => {
  172. itemCreation(userId, doc);
  173. });
  174. ChecklistItems.after.remove((userId, doc) => {
  175. itemRemover(userId, doc);
  176. });
  177. }
  178. if (Meteor.isServer) {
  179. JsonRoutes.add('GET', '/api/boards/:boardId/cards/:cardId/checklists/:checklistId/items/:itemId', function (req, res) {
  180. Authentication.checkUserId( req.userId);
  181. const paramItemId = req.params.itemId;
  182. const checklistItem = ChecklistItems.findOne({ _id: paramItemId });
  183. if (checklistItem) {
  184. JsonRoutes.sendResult(res, {
  185. code: 200,
  186. data: checklistItem,
  187. });
  188. } else {
  189. JsonRoutes.sendResult(res, {
  190. code: 500,
  191. });
  192. }
  193. });
  194. JsonRoutes.add('PUT', '/api/boards/:boardId/cards/:cardId/checklists/:checklistId/items/:itemId', function (req, res) {
  195. Authentication.checkUserId( req.userId);
  196. const paramItemId = req.params.itemId;
  197. if (req.body.hasOwnProperty('isFinished')) {
  198. ChecklistItems.direct.update({_id: paramItemId}, {$set: {isFinished: req.body.isFinished}});
  199. }
  200. if (req.body.hasOwnProperty('title')) {
  201. ChecklistItems.direct.update({_id: paramItemId}, {$set: {title: req.body.title}});
  202. }
  203. JsonRoutes.sendResult(res, {
  204. code: 200,
  205. data: {
  206. _id: paramItemId,
  207. },
  208. });
  209. });
  210. JsonRoutes.add('DELETE', '/api/boards/:boardId/cards/:cardId/checklists/:checklistId/items/:itemId', function (req, res) {
  211. Authentication.checkUserId( req.userId);
  212. const paramItemId = req.params.itemId;
  213. ChecklistItems.direct.remove({ _id: paramItemId });
  214. JsonRoutes.sendResult(res, {
  215. code: 200,
  216. data: {
  217. _id: paramItemId,
  218. },
  219. });
  220. });
  221. }