Răsfoiți Sursa

Add back old attachments models for attachment migrations.

Thanks to xet7 !
Lauri Ojansivu 1 an în urmă
părinte
comite
e72646a4d4
2 a modificat fișierele cu 147 adăugiri și 0 ștergeri
  1. 118 0
      models/attachments_old.js
  2. 29 0
      models/avatars_old.js

+ 118 - 0
models/attachments_old.js

@@ -0,0 +1,118 @@
+import { ReactiveCache } from '/imports/reactiveCache';
+
+const storeName = 'attachments';
+const defaultStoreOptions = {
+  beforeWrite: fileObj => {
+    if (!fileObj.isImage()) {
+      return {
+        type: 'application/octet-stream',
+      };
+    }
+    return {};
+  },
+};
+let store;
+store = new FS.Store.GridFS(storeName, {
+  // XXX Add a new store for cover thumbnails so we don't load big images in
+  // the general board view
+  // If the uploaded document is not an image we need to enforce browser
+  // download instead of execution. This is particularly important for HTML
+  // files that the browser will just execute if we don't serve them with the
+  // appropriate `application/octet-stream` MIME header which can lead to user
+  // data leaks. I imagine other formats (like PDF) can also be attack vectors.
+  // See https://github.com/wekan/wekan/issues/99
+  // XXX Should we use `beforeWrite` option of CollectionFS instead of
+  // collection-hooks?
+  // We should use `beforeWrite`.
+  ...defaultStoreOptions,
+});
+AttachmentsOld = new FS.Collection('attachments', {
+  stores: [store],
+});
+
+if (Meteor.isServer) {
+  Meteor.startup(() => {
+    AttachmentsOld.files._ensureIndex({ cardId: 1 });
+  });
+
+  AttachmentsOld.allow({
+    insert(userId, doc) {
+      return allowIsBoardMember(userId, ReactiveCache.getBoard(doc.boardId));
+    },
+    update(userId, doc) {
+      return allowIsBoardMember(userId, ReactiveCache.getBoard(doc.boardId));
+    },
+    remove(userId, doc) {
+      return allowIsBoardMember(userId, ReactiveCache.getBoard(doc.boardId));
+    },
+    // We authorize the attachment download either:
+    // - if the board is public, everyone (even unconnected) can download it
+    // - if the board is private, only board members can download it
+    download(userId, doc) {
+      const board = ReactiveCache.getBoard(doc.boardId);
+      if (board.isPublic()) {
+        return true;
+      } else {
+        return board.hasMember(userId);
+      }
+    },
+
+    fetch: ['boardId'],
+  });
+}
+
+// XXX Enforce a schema for the AttachmentsOld CollectionFS
+
+if (Meteor.isServer) {
+  AttachmentsOld.files.after.insert((userId, doc) => {
+    // If the attachment doesn't have a source field
+    // or its source is different than import
+    if (!doc.source || doc.source !== 'import') {
+      // Add activity about adding the attachment
+      Activities.insert({
+        userId,
+        type: 'card',
+        activityType: 'addAttachment',
+        attachmentId: doc._id,
+        // this preserves the name so that notifications can be meaningful after
+        // this file is removed
+        attachmentName: doc.original.name,
+        boardId: doc.boardId,
+        cardId: doc.cardId,
+        listId: doc.listId,
+        swimlaneId: doc.swimlaneId,
+      });
+    } else {
+      // Don't add activity about adding the attachment as the activity
+      // be imported and delete source field
+      AttachmentsOld.update(
+        {
+          _id: doc._id,
+        },
+        {
+          $unset: {
+            source: '',
+          },
+        },
+      );
+    }
+  });
+
+  AttachmentsOld.files.before.remove((userId, doc) => {
+    Activities.insert({
+      userId,
+      type: 'card',
+      activityType: 'deleteAttachment',
+      attachmentId: doc._id,
+      // this preserves the name so that notifications can be meaningful after
+      // this file is removed
+      attachmentName: doc.original.name,
+      boardId: doc.boardId,
+      cardId: doc.cardId,
+      listId: doc.listId,
+      swimlaneId: doc.swimlaneId,
+    });
+  });
+}
+
+export default AttachmentsOld;

+ 29 - 0
models/avatars_old.js

@@ -0,0 +1,29 @@
+AvatarsOld = new FS.Collection('avatars', {
+  stores: [new FS.Store.GridFS('avatars')],
+  filter: {
+    maxSize: 72000,
+    allow: {
+      contentTypes: ['image/*'],
+    },
+  },
+});
+
+function isOwner(userId, file) {
+  return userId && userId === file.userId;
+}
+
+AvatarsOld.allow({
+  insert: isOwner,
+  update: isOwner,
+  remove: isOwner,
+  download() {
+    return true;
+  },
+  fetch: ['userId'],
+});
+
+AvatarsOld.files.before.insert((userId, doc) => {
+  doc.userId = userId;
+});
+
+export default AvatarsOld;