attachments.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { Meteor } from 'meteor/meteor';
  2. import { FilesCollection } from 'meteor/ostrio:files';
  3. import { createBucket } from './lib/grid/createBucket';
  4. import { createOnAfterUpload } from './lib/fsHooks/createOnAfterUpload';
  5. import { createInterceptDownload } from './lib/fsHooks/createInterceptDownload';
  6. import { createOnAfterRemove } from './lib/fsHooks/createOnAfterRemove';
  7. const attachmentBucket = createBucket('attachments');
  8. // XXX Enforce a schema for the Attachments FilesCollection
  9. // see: https://github.com/VeliovGroup/Meteor-Files/wiki/Schema
  10. export const Attachments = new FilesCollection({
  11. debug: false, // Change to `true` for debugging
  12. collectionName: 'attachments',
  13. allowClientCode: false,
  14. onAfterUpload(doc) {
  15. // If the attachment doesn't have a source field
  16. // or its source is different than import
  17. if (!doc.source || doc.source !== 'import') {
  18. // Add activity about adding the attachment
  19. Activities.insert({
  20. userId,
  21. type: 'card',
  22. activityType: 'addAttachment',
  23. attachmentId: doc._id,
  24. // this preserves the name so that notifications can be meaningful after
  25. // this file is removed
  26. attachmentName: doc.original.name,
  27. boardId: doc.boardId,
  28. cardId: doc.cardId,
  29. listId: doc.listId,
  30. swimlaneId: doc.swimlaneId,
  31. });
  32. } else {
  33. // Don't add activity about adding the attachment as the activity
  34. // be imported and delete source field
  35. Attachments.update(
  36. {
  37. _id: doc._id,
  38. },
  39. {
  40. $unset: {
  41. source: '',
  42. },
  43. },
  44. );
  45. }
  46. createOnAfterUpload(attachmentBucket)(doc);
  47. },
  48. interceptDownload: createInterceptDownload(attachmentBucket),
  49. onAfterRemove(docs) {
  50. docs.forEach(function(doc) {
  51. Activities.insert({
  52. userId: doc.userId,
  53. type: 'card',
  54. activityType: 'deleteAttachment',
  55. attachmentId: doc._id,
  56. // this preserves the name so that notifications can be meaningful after
  57. // this file is removed
  58. attachmentName: doc.original.name,
  59. boardId: doc.boardId,
  60. cardId: doc.cardId,
  61. listId: doc.listId,
  62. swimlaneId: doc.swimlaneId,
  63. });
  64. });
  65. createOnAfterRemove(attachmentBucket)(docs);
  66. },
  67. // We authorize the attachment download either:
  68. // - if the board is public, everyone (even unconnected) can download it
  69. // - if the board is private, only board members can download it
  70. downloadCallback(doc) {
  71. const board = Boards.findOne(doc.boardId);
  72. if (board.isPublic()) {
  73. return true;
  74. } else {
  75. return board.hasMember(this.userId);
  76. }
  77. },
  78. });
  79. if (Meteor.isServer) {
  80. Attachments.allow({
  81. insert(userId, doc) {
  82. return allowIsBoardMember(userId, Boards.findOne(doc.boardId));
  83. },
  84. update(userId, doc) {
  85. return allowIsBoardMember(userId, Boards.findOne(doc.boardId));
  86. },
  87. remove(userId, doc) {
  88. return allowIsBoardMember(userId, Boards.findOne(doc.boardId));
  89. },
  90. fetch: ['boardId'],
  91. });
  92. Meteor.startup(() => {
  93. Attachments.collection._ensureIndex({ cardId: 1 });
  94. });
  95. }
  96. export default Attachments;