customFields.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. CustomFields = new Mongo.Collection('customFields');
  2. /**
  3. * A custom field on a card in the board
  4. */
  5. CustomFields.attachSchema(
  6. new SimpleSchema({
  7. boardIds: {
  8. /**
  9. * the ID of the board
  10. */
  11. type: [String],
  12. },
  13. name: {
  14. /**
  15. * name of the custom field
  16. */
  17. type: String,
  18. },
  19. type: {
  20. /**
  21. * type of the custom field
  22. */
  23. type: String,
  24. allowedValues: ['text', 'number', 'date', 'dropdown'],
  25. },
  26. settings: {
  27. /**
  28. * settings of the custom field
  29. */
  30. type: Object,
  31. },
  32. 'settings.dropdownItems': {
  33. /**
  34. * list of drop down items objects
  35. */
  36. type: [Object],
  37. optional: true,
  38. },
  39. 'settings.dropdownItems.$': {
  40. type: new SimpleSchema({
  41. _id: {
  42. /**
  43. * ID of the drop down item
  44. */
  45. type: String,
  46. },
  47. name: {
  48. /**
  49. * name of the drop down item
  50. */
  51. type: String,
  52. },
  53. }),
  54. },
  55. showOnCard: {
  56. /**
  57. * should we show on the cards this custom field
  58. */
  59. type: Boolean,
  60. },
  61. automaticallyOnCard: {
  62. /**
  63. * should the custom fields automatically be added on cards?
  64. */
  65. type: Boolean,
  66. },
  67. showLabelOnMiniCard: {
  68. /**
  69. * should the label of the custom field be shown on minicards?
  70. */
  71. type: Boolean,
  72. },
  73. createdAt: {
  74. type: Date,
  75. optional: true,
  76. // eslint-disable-next-line consistent-return
  77. autoValue() {
  78. if (this.isInsert) {
  79. return new Date();
  80. } else {
  81. this.unset();
  82. }
  83. },
  84. },
  85. modifiedAt: {
  86. type: Date,
  87. denyUpdate: false,
  88. // eslint-disable-next-line consistent-return
  89. autoValue() {
  90. if (this.isInsert || this.isUpsert || this.isUpdate) {
  91. return new Date();
  92. } else {
  93. this.unset();
  94. }
  95. },
  96. },
  97. }),
  98. );
  99. CustomFields.mutations({
  100. addBoard(boardId) {
  101. if (boardId) {
  102. return {
  103. $push: {
  104. boardIds: boardId,
  105. },
  106. };
  107. } else {
  108. return null;
  109. }
  110. },
  111. });
  112. CustomFields.allow({
  113. insert(userId, doc) {
  114. return allowIsAnyBoardMember(
  115. userId,
  116. Boards.find({
  117. _id: { $in: doc.boardIds },
  118. }).fetch(),
  119. );
  120. },
  121. update(userId, doc) {
  122. return allowIsAnyBoardMember(
  123. userId,
  124. Boards.find({
  125. _id: { $in: doc.boardIds },
  126. }).fetch(),
  127. );
  128. },
  129. remove(userId, doc) {
  130. return allowIsAnyBoardMember(
  131. userId,
  132. Boards.find({
  133. _id: { $in: doc.boardIds },
  134. }).fetch(),
  135. );
  136. },
  137. fetch: ['userId', 'boardIds'],
  138. });
  139. // not sure if we need this?
  140. //CustomFields.hookOptions.after.update = { fetchPrevious: false };
  141. function customFieldCreation(userId, doc) {
  142. Activities.insert({
  143. userId,
  144. activityType: 'createCustomField',
  145. boardId: doc.boardIds[0], // We are creating a customField, it has only one boardId
  146. customFieldId: doc._id,
  147. });
  148. }
  149. function customFieldDeletion(userId, doc) {
  150. Activities.insert({
  151. userId,
  152. activityType: 'deleteCustomField',
  153. boardId: doc.boardIds[0], // We are creating a customField, it has only one boardId
  154. customFieldId: doc._id,
  155. });
  156. }
  157. // This has some bug, it does not show edited customField value at Outgoing Webhook,
  158. // instead it shows undefined, and no listId and swimlaneId.
  159. function customFieldEdit(userId, doc) {
  160. const card = Cards.findOne(doc.cardId);
  161. Activities.insert({
  162. userId,
  163. activityType: 'editCustomField',
  164. boardId: doc.boardIds[0], // We are creating a customField, it has only one boardId
  165. customFieldId: doc._id,
  166. listId: card.listId,
  167. swimlaneId: card.swimlaneId,
  168. });
  169. }
  170. if (Meteor.isServer) {
  171. Meteor.startup(() => {
  172. CustomFields._collection._ensureIndex({ modifiedAt: -1 });
  173. CustomFields._collection._ensureIndex({ boardIds: 1 });
  174. });
  175. CustomFields.after.insert((userId, doc) => {
  176. customFieldCreation(userId, doc);
  177. });
  178. CustomFields.before.update((userId, doc, fieldNames, modifier) => {
  179. if (_.contains(fieldNames, 'boardIds') && modifier.$pull) {
  180. Cards.update(
  181. { boardId: modifier.$pull.boardIds, 'customFields._id': doc._id },
  182. { $pull: { customFields: { _id: doc._id } } },
  183. { multi: true },
  184. );
  185. customFieldEdit(userId, doc);
  186. Activities.remove({
  187. customFieldId: doc._id,
  188. boardId: modifier.$pull.boardIds,
  189. listId: card.listId,
  190. swimlaneId: card.swimlaneId,
  191. });
  192. } else if (_.contains(fieldNames, 'boardIds') && modifier.$push) {
  193. Activities.insert({
  194. userId,
  195. activityType: 'createCustomField',
  196. boardId: modifier.$push.boardIds,
  197. customFieldId: doc._id,
  198. });
  199. }
  200. });
  201. CustomFields.before.remove((userId, doc) => {
  202. customFieldDeletion(userId, doc);
  203. Activities.remove({
  204. customFieldId: doc._id,
  205. });
  206. Cards.update(
  207. { boardId: { $in: doc.boardIds }, 'customFields._id': doc._id },
  208. { $pull: { customFields: { _id: doc._id } } },
  209. { multi: true },
  210. );
  211. });
  212. }
  213. //CUSTOM FIELD REST API
  214. if (Meteor.isServer) {
  215. /**
  216. * @operation get_all_custom_fields
  217. * @summary Get the list of Custom Fields attached to a board
  218. *
  219. * @param {string} boardID the ID of the board
  220. * @return_type [{_id: string,
  221. * name: string,
  222. * type: string}]
  223. */
  224. JsonRoutes.add('GET', '/api/boards/:boardId/custom-fields', function(
  225. req,
  226. res,
  227. ) {
  228. Authentication.checkUserId(req.userId);
  229. const paramBoardId = req.params.boardId;
  230. JsonRoutes.sendResult(res, {
  231. code: 200,
  232. data: CustomFields.find({ boardIds: { $in: [paramBoardId] } }).map(
  233. function(cf) {
  234. return {
  235. _id: cf._id,
  236. name: cf.name,
  237. type: cf.type,
  238. };
  239. },
  240. ),
  241. });
  242. });
  243. /**
  244. * @operation get_custom_field
  245. * @summary Get a Custom Fields attached to a board
  246. *
  247. * @param {string} boardID the ID of the board
  248. * @param {string} customFieldId the ID of the custom field
  249. * @return_type CustomFields
  250. */
  251. JsonRoutes.add(
  252. 'GET',
  253. '/api/boards/:boardId/custom-fields/:customFieldId',
  254. function(req, res) {
  255. Authentication.checkUserId(req.userId);
  256. const paramBoardId = req.params.boardId;
  257. const paramCustomFieldId = req.params.customFieldId;
  258. JsonRoutes.sendResult(res, {
  259. code: 200,
  260. data: CustomFields.findOne({
  261. _id: paramCustomFieldId,
  262. boardIds: { $in: [paramBoardId] },
  263. }),
  264. });
  265. },
  266. );
  267. /**
  268. * @operation new_custom_field
  269. * @summary Create a Custom Field
  270. *
  271. * @param {string} boardID the ID of the board
  272. * @param {string} name the name of the custom field
  273. * @param {string} type the type of the custom field
  274. * @param {string} settings the settings object of the custom field
  275. * @param {boolean} showOnCard should we show the custom field on cards?
  276. * @param {boolean} automaticallyOnCard should the custom fields automatically be added on cards?
  277. * @param {boolean} showLabelOnMiniCard should the label of the custom field be shown on minicards?
  278. * @return_type {_id: string}
  279. */
  280. JsonRoutes.add('POST', '/api/boards/:boardId/custom-fields', function(
  281. req,
  282. res,
  283. ) {
  284. Authentication.checkUserId(req.userId);
  285. const paramBoardId = req.params.boardId;
  286. const id = CustomFields.direct.insert({
  287. name: req.body.name,
  288. type: req.body.type,
  289. settings: req.body.settings,
  290. showOnCard: req.body.showOnCard,
  291. automaticallyOnCard: req.body.automaticallyOnCard,
  292. showLabelOnMiniCard: req.body.showLabelOnMiniCard,
  293. boardIds: { $in: [paramBoardId] },
  294. });
  295. const customField = CustomFields.findOne({
  296. _id: id,
  297. boardIds: { $in: [paramBoardId] },
  298. });
  299. customFieldCreation(req.body.authorId, customField);
  300. JsonRoutes.sendResult(res, {
  301. code: 200,
  302. data: {
  303. _id: id,
  304. },
  305. });
  306. });
  307. /**
  308. * @operation delete_custom_field
  309. * @summary Delete a Custom Fields attached to a board
  310. *
  311. * @description The Custom Field can't be retrieved after this operation
  312. *
  313. * @param {string} boardID the ID of the board
  314. * @param {string} customFieldId the ID of the custom field
  315. * @return_type {_id: string}
  316. */
  317. JsonRoutes.add(
  318. 'DELETE',
  319. '/api/boards/:boardId/custom-fields/:customFieldId',
  320. function(req, res) {
  321. Authentication.checkUserId(req.userId);
  322. const paramBoardId = req.params.boardId;
  323. const id = req.params.customFieldId;
  324. CustomFields.remove({ _id: id, boardIds: { $in: [paramBoardId] } });
  325. JsonRoutes.sendResult(res, {
  326. code: 200,
  327. data: {
  328. _id: id,
  329. },
  330. });
  331. },
  332. );
  333. }
  334. export default CustomFields;