attachments.js 2.9 KB

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