From 05c53ca01d71a01a608c9ae345475abd67c9939b Mon Sep 17 00:00:00 2001 From: Romulus Urakagi Tsai Date: Mon, 18 Nov 2019 01:47:26 +0000 Subject: Trying to upload an attachment with Meteor-Files --- models/attachments.js | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) (limited to 'models') diff --git a/models/attachments.js b/models/attachments.js index 9b8ec04f..fd03e6d2 100644 --- a/models/attachments.js +++ b/models/attachments.js @@ -1,3 +1,29 @@ +import { FilesCollection } from 'meteor/ostrio:files'; + +Attachments = new FilesCollection({ + storagePath: storagePath(), + debug: true, // FIXME: Remove debug mode + collectionName: 'attachments2', + allowClientCode: false, // Disallow remove files from Client +}); + +if (Meteor.isServer) { + Meteor.startup(() => { + Attachments.collection._ensureIndex({ cardId: 1 }); + }); + + // TODO: Permission related + // TODO: Add Activity update + // TODO: publish and subscribe +// Meteor.publish('files.attachments.all', function () { +// return Attachments.find().cursor; +// }); +} else { +// Meteor.subscribe('files.attachments.all'); +} + +// ---------- Deprecated fallback ---------- // + const localFSStore = process.env.ATTACHMENTS_STORE_PATH; const storeName = 'attachments'; const defaultStoreOptions = { @@ -171,16 +197,16 @@ if (localFSStore) { ...defaultStoreOptions, }); } -Attachments = new FS.Collection('attachments', { +DeprecatedAttachs = new FS.Collection('attachments', { stores: [store], }); if (Meteor.isServer) { Meteor.startup(() => { - Attachments.files._ensureIndex({ cardId: 1 }); + DeprecatedAttachs.files._ensureIndex({ cardId: 1 }); }); - Attachments.allow({ + DeprecatedAttachs.allow({ insert(userId, doc) { return allowIsBoardMember(userId, Boards.findOne(doc.boardId)); }, @@ -206,10 +232,10 @@ if (Meteor.isServer) { }); } -// XXX Enforce a schema for the Attachments CollectionFS +// XXX Enforce a schema for the DeprecatedAttachs CollectionFS if (Meteor.isServer) { - Attachments.files.after.insert((userId, doc) => { + DeprecatedAttachs.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') { @@ -227,7 +253,7 @@ if (Meteor.isServer) { } else { // Don't add activity about adding the attachment as the activity // be imported and delete source field - Attachments.update( + DeprecatedAttachs.update( { _id: doc._id, }, @@ -240,7 +266,7 @@ if (Meteor.isServer) { } }); - Attachments.files.before.remove((userId, doc) => { + DeprecatedAttachs.files.before.remove((userId, doc) => { Activities.insert({ userId, type: 'card', @@ -253,11 +279,16 @@ if (Meteor.isServer) { }); }); - Attachments.files.after.remove((userId, doc) => { + DeprecatedAttachs.files.after.remove((userId, doc) => { Activities.remove({ attachmentId: doc._id, }); }); } +function storagePath(defaultPath) { + const storePath = process.env.ATTACHMENTS_STORE_PATH; + return storePath ? storePath : defaultPath; +} + export default Attachments; -- cgit v1.2.3-1-g7c22 From 4dcdec0084414e7dde9e630add01ecd2865bd941 Mon Sep 17 00:00:00 2001 From: Romulus Urakagi Tsai Date: Wed, 20 Nov 2019 10:40:09 +0000 Subject: Attachment upload from card done, need to fix download link --- models/attachments.js | 10 +++++----- models/cards.js | 12 +++++++----- models/export.js | 2 +- models/trelloCreator.js | 1 + models/wekanCreator.js | 2 ++ 5 files changed, 16 insertions(+), 11 deletions(-) (limited to 'models') diff --git a/models/attachments.js b/models/attachments.js index fd03e6d2..4537e47c 100644 --- a/models/attachments.js +++ b/models/attachments.js @@ -4,7 +4,7 @@ Attachments = new FilesCollection({ storagePath: storagePath(), debug: true, // FIXME: Remove debug mode collectionName: 'attachments2', - allowClientCode: false, // Disallow remove files from Client + allowClientCode: true, // FIXME: Permissions }); if (Meteor.isServer) { @@ -15,11 +15,11 @@ if (Meteor.isServer) { // TODO: Permission related // TODO: Add Activity update // TODO: publish and subscribe -// Meteor.publish('files.attachments.all', function () { -// return Attachments.find().cursor; -// }); + Meteor.publish('attachments', function() { + return Attachments.find().cursor; + }); } else { -// Meteor.subscribe('files.attachments.all'); + Meteor.subscribe('attachments'); } // ---------- Deprecated fallback ---------- // diff --git a/models/cards.js b/models/cards.js index 3944b09f..4c3e2c99 100644 --- a/models/cards.js +++ b/models/cards.js @@ -366,7 +366,7 @@ Cards.helpers({ // Copy attachments oldCard.attachments().forEach(att => { - att.cardId = _id; + att.meta.cardId = _id; delete att._id; return Attachments.insert(att); }); @@ -456,14 +456,16 @@ Cards.helpers({ attachments() { if (this.isLinkedCard()) { return Attachments.find( - { cardId: this.linkedId }, + { 'meta.cardId': this.linkedId }, { sort: { uploadedAt: -1 } }, ); } else { - return Attachments.find( - { cardId: this._id }, + const ret = Attachments.find( + { 'meta.cardId': this._id }, { sort: { uploadedAt: -1 } }, ); + if (ret.first()) console.log('link', Attachments.link(ret.first())); + return ret; } }, @@ -471,7 +473,7 @@ Cards.helpers({ const cover = Attachments.findOne(this.coverId); // if we return a cover before it is fully stored, we will get errors when we try to display it // todo XXX we could return a default "upload pending" image in the meantime? - return cover && cover.url() && cover; + return cover && cover.link(); }, checklists() { diff --git a/models/export.js b/models/export.js index cc979ce0..c93a8bda 100644 --- a/models/export.js +++ b/models/export.js @@ -162,7 +162,7 @@ export class Exporter { readStream.pipe(tmpWriteable); }; const getBase64DataSync = Meteor.wrapAsync(getBase64Data); - result.attachments = Attachments.find(byBoard) + result.attachments = Attachments.find({ 'meta.boardId': byBoard.boardId }) .fetch() .map(attachment => { return { diff --git a/models/trelloCreator.js b/models/trelloCreator.js index cb1a6a67..b38e4652 100644 --- a/models/trelloCreator.js +++ b/models/trelloCreator.js @@ -345,6 +345,7 @@ export class TrelloCreator { // so we make it server only, and let UI catch up once it is done, forget about latency comp. const self = this; if (Meteor.isServer) { + // FIXME: Change to new model file.attachData(att.url, function(error) { file.boardId = boardId; file.cardId = cardId; diff --git a/models/wekanCreator.js b/models/wekanCreator.js index ec85d93f..175c156d 100644 --- a/models/wekanCreator.js +++ b/models/wekanCreator.js @@ -415,6 +415,7 @@ export class WekanCreator { const self = this; if (Meteor.isServer) { if (att.url) { + // FIXME: Change to new file library file.attachData(att.url, function(error) { file.boardId = boardId; file.cardId = cardId; @@ -440,6 +441,7 @@ export class WekanCreator { } }); } else if (att.file) { + // FIXME: Change to new file library file.attachData( new Buffer(att.file, 'base64'), { -- cgit v1.2.3-1-g7c22 From 6cdd464f54fca423876a27ec2a4269ae5841cdb0 Mon Sep 17 00:00:00 2001 From: Romulus Urakagi Tsai Date: Wed, 27 Nov 2019 09:40:19 +0000 Subject: Uploaded done, but uploading not --- models/attachments.js | 6 +++++- models/cards.js | 3 +-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'models') diff --git a/models/attachments.js b/models/attachments.js index 4537e47c..5dcc75e6 100644 --- a/models/attachments.js +++ b/models/attachments.js @@ -2,9 +2,12 @@ import { FilesCollection } from 'meteor/ostrio:files'; Attachments = new FilesCollection({ storagePath: storagePath(), - debug: true, // FIXME: Remove debug mode + debug: false, // FIXME: Remove debug mode collectionName: 'attachments2', allowClientCode: true, // FIXME: Permissions + onAfterUpload: (fileRef) => { + Attachments.update({_id:fileRef._id}, {$set: {"meta.uploaded": true}}); + } }); if (Meteor.isServer) { @@ -15,6 +18,7 @@ if (Meteor.isServer) { // TODO: Permission related // TODO: Add Activity update // TODO: publish and subscribe + Meteor.publish('attachments', function() { return Attachments.find().cursor; }); diff --git a/models/cards.js b/models/cards.js index 4c3e2c99..86d22c53 100644 --- a/models/cards.js +++ b/models/cards.js @@ -460,11 +460,10 @@ Cards.helpers({ { sort: { uploadedAt: -1 } }, ); } else { - const ret = Attachments.find( + let ret = Attachments.find( { 'meta.cardId': this._id }, { sort: { uploadedAt: -1 } }, ); - if (ret.first()) console.log('link', Attachments.link(ret.first())); return ret; } }, -- cgit v1.2.3-1-g7c22 From d26bf04bfa088b770c85a895700fd704cc08e234 Mon Sep 17 00:00:00 2001 From: Romulus Urakagi Tsai Date: Tue, 14 Jan 2020 06:29:34 +0000 Subject: Change to relative path and /var/attachments to store --- models/attachments.js | 2 ++ 1 file changed, 2 insertions(+) (limited to 'models') diff --git a/models/attachments.js b/models/attachments.js index 5dcc75e6..25e4b4bb 100644 --- a/models/attachments.js +++ b/models/attachments.js @@ -291,6 +291,8 @@ if (Meteor.isServer) { } function storagePath(defaultPath) { + // FIXME + return '/var/attachments'; const storePath = process.env.ATTACHMENTS_STORE_PATH; return storePath ? storePath : defaultPath; } -- cgit v1.2.3-1-g7c22 From 617fdaeb7418d4e6c2530e7a9d4a3feb62e5a00e Mon Sep 17 00:00:00 2001 From: Romulus Urakagi Tsai Date: Tue, 14 Jan 2020 07:06:20 +0000 Subject: Fix sandstorm storage path --- models/attachments.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'models') diff --git a/models/attachments.js b/models/attachments.js index 25e4b4bb..903f6490 100644 --- a/models/attachments.js +++ b/models/attachments.js @@ -291,8 +291,12 @@ if (Meteor.isServer) { } function storagePath(defaultPath) { +/* + console.log('path', process.env.ATTACHMENTS_STORE_PATH); + console.log('env', process.env); // FIXME return '/var/attachments'; +*/ const storePath = process.env.ATTACHMENTS_STORE_PATH; return storePath ? storePath : defaultPath; } -- cgit v1.2.3-1-g7c22 From b34ed58289a3dae5838d3b621260938a3ecf52d5 Mon Sep 17 00:00:00 2001 From: Romulus Urakagi Tsai Date: Thu, 13 Feb 2020 08:47:41 +0000 Subject: Start writing migration --- models/attachments.js | 100 ++------------------------------------------------ 1 file changed, 3 insertions(+), 97 deletions(-) (limited to 'models') diff --git a/models/attachments.js b/models/attachments.js index 903f6490..c35d3d4c 100644 --- a/models/attachments.js +++ b/models/attachments.js @@ -19,17 +19,17 @@ if (Meteor.isServer) { // TODO: Add Activity update // TODO: publish and subscribe - Meteor.publish('attachments', function() { + Meteor.publish('attachments2', function() { return Attachments.find().cursor; }); } else { - Meteor.subscribe('attachments'); + Meteor.subscribe('attachments2'); } // ---------- Deprecated fallback ---------- // const localFSStore = process.env.ATTACHMENTS_STORE_PATH; -const storeName = 'attachments'; +const storeName = 'attachments2'; const defaultStoreOptions = { beforeWrite: fileObj => { if (!fileObj.isImage()) { @@ -201,102 +201,8 @@ if (localFSStore) { ...defaultStoreOptions, }); } -DeprecatedAttachs = new FS.Collection('attachments', { - stores: [store], -}); - -if (Meteor.isServer) { - Meteor.startup(() => { - DeprecatedAttachs.files._ensureIndex({ cardId: 1 }); - }); - - DeprecatedAttachs.allow({ - insert(userId, doc) { - return allowIsBoardMember(userId, Boards.findOne(doc.boardId)); - }, - update(userId, doc) { - return allowIsBoardMember(userId, Boards.findOne(doc.boardId)); - }, - remove(userId, doc) { - return allowIsBoardMember(userId, Boards.findOne(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 = Boards.findOne(doc.boardId); - if (board.isPublic()) { - return true; - } else { - return board.hasMember(userId); - } - }, - - fetch: ['boardId'], - }); -} - -// XXX Enforce a schema for the DeprecatedAttachs CollectionFS - -if (Meteor.isServer) { - DeprecatedAttachs.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, - 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 - DeprecatedAttachs.update( - { - _id: doc._id, - }, - { - $unset: { - source: '', - }, - }, - ); - } - }); - - DeprecatedAttachs.files.before.remove((userId, doc) => { - Activities.insert({ - userId, - type: 'card', - activityType: 'deleteAttachment', - attachmentId: doc._id, - boardId: doc.boardId, - cardId: doc.cardId, - listId: doc.listId, - swimlaneId: doc.swimlaneId, - }); - }); - - DeprecatedAttachs.files.after.remove((userId, doc) => { - Activities.remove({ - attachmentId: doc._id, - }); - }); -} function storagePath(defaultPath) { -/* - console.log('path', process.env.ATTACHMENTS_STORE_PATH); - console.log('env', process.env); - // FIXME - return '/var/attachments'; -*/ const storePath = process.env.ATTACHMENTS_STORE_PATH; return storePath ? storePath : defaultPath; } -- cgit v1.2.3-1-g7c22 From 444848876759173ad80203129250d2f0311f30fc Mon Sep 17 00:00:00 2001 From: Romulus Urakagi Tsai Date: Fri, 8 May 2020 09:32:19 +0800 Subject: Done attachments activities operating --- models/activities.js | 6 +- models/attachments.js | 241 +++++++++++++------------------------------------- 2 files changed, 66 insertions(+), 181 deletions(-) (limited to 'models') diff --git a/models/activities.js b/models/activities.js index 19e3fb7d..3f8a0d35 100644 --- a/models/activities.js +++ b/models/activities.js @@ -214,7 +214,11 @@ if (Meteor.isServer) { } if (activity.attachmentId) { const attachment = activity.attachment(); - params.attachment = attachment.original.name; + if (attachment.original) { + params.attachment = attachment.original.name; + } else { + params.attachment = attachment.versions.original.name; + } params.attachmentId = attachment._id; } if (activity.checklistId) { diff --git a/models/attachments.js b/models/attachments.js index c35d3d4c..798d04be 100644 --- a/models/attachments.js +++ b/models/attachments.js @@ -1,13 +1,15 @@ import { FilesCollection } from 'meteor/ostrio:files'; +const collectionName = 'attachments2'; + Attachments = new FilesCollection({ storagePath: storagePath(), - debug: false, // FIXME: Remove debug mode + debug: false, + allowClientCode: true, collectionName: 'attachments2', - allowClientCode: true, // FIXME: Permissions - onAfterUpload: (fileRef) => { - Attachments.update({_id:fileRef._id}, {$set: {"meta.uploaded": true}}); - } + onAfterUpload: onAttachmentUploaded, + onBeforeRemove: onAttachmentRemoving, + onAfterRemove: onAttachmentRemoved }); if (Meteor.isServer) { @@ -17,194 +19,73 @@ if (Meteor.isServer) { // TODO: Permission related // TODO: Add Activity update - // TODO: publish and subscribe - Meteor.publish('attachments2', function() { + Meteor.publish(collectionName, function() { return Attachments.find().cursor; }); } else { - Meteor.subscribe('attachments2'); + Meteor.subscribe(collectionName); } -// ---------- Deprecated fallback ---------- // - -const localFSStore = process.env.ATTACHMENTS_STORE_PATH; -const storeName = 'attachments2'; -const defaultStoreOptions = { - beforeWrite: fileObj => { - if (!fileObj.isImage()) { - return { - type: 'application/octet-stream', - }; - } - return {}; - }, -}; -let store; -if (localFSStore) { - // have to reinvent methods from FS.Store.GridFS and FS.Store.FileSystem - const fs = Npm.require('fs'); - const path = Npm.require('path'); - const mongodb = Npm.require('mongodb'); - const Grid = Npm.require('gridfs-stream'); - // calulate the absolute path here, because FS.Store.FileSystem didn't expose the aboslutepath or FS.Store didn't expose api calls :( - let pathname = localFSStore; - /*eslint camelcase: ["error", {allow: ["__meteor_bootstrap__"]}] */ +function storagePath(defaultPath) { + const storePath = process.env.ATTACHMENTS_STORE_PATH; + return storePath ? storePath : defaultPath; +} - if (!pathname && __meteor_bootstrap__ && __meteor_bootstrap__.serverDir) { - pathname = path.join( - __meteor_bootstrap__.serverDir, - `../../../cfs/files/${storeName}`, +function onAttachmentUploaded(fileRef) { + Attachments.update({_id:fileRef._id}, {$set: {"meta.uploaded": true}}); + if (!fileRef.meta.source || fileRef.meta.source !== 'import') { + // Add activity about adding the attachment + Activities.insert({ + userId: fileRef.userId, + type: 'card', + activityType: 'addAttachment', + attachmentId: fileRef._id, + boardId: fileRef.meta.boardId, + cardId: fileRef.meta.cardId, + listId: fileRef.meta.listId, + swimlaneId: fileRef.meta.swimlaneId, + }); + } else { + // Don't add activity about adding the attachment as the activity + // be imported and delete source field + CFSAttachments.update( + { + _id: fileRef._id, + }, + { + $unset: { + source: '', + }, + }, ); } +} - if (!pathname) - throw new Error('FS.Store.FileSystem unable to determine path'); - - // Check if we have '~/foo/bar' - if (pathname.split(path.sep)[0] === '~') { - const homepath = - process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE; - if (homepath) { - pathname = pathname.replace('~', homepath); - } else { - throw new Error('FS.Store.FileSystem unable to resolve "~" in path'); - } - } - - // Set absolute path - const absolutePath = path.resolve(pathname); - - const _FStore = new FS.Store.FileSystem(storeName, { - path: localFSStore, - ...defaultStoreOptions, - }); - const GStore = { - fileKey(fileObj) { - const key = { - _id: null, - filename: null, - }; - - // If we're passed a fileObj, we retrieve the _id and filename from it. - if (fileObj) { - const info = fileObj._getInfo(storeName, { - updateFileRecordFirst: false, - }); - key._id = info.key || null; - key.filename = - info.name || - fileObj.name({ updateFileRecordFirst: false }) || - `${fileObj.collectionName}-${fileObj._id}`; - } - - // If key._id is null at this point, createWriteStream will let GridFS generate a new ID - return key; - }, - db: undefined, - mongoOptions: { useNewUrlParser: true }, - mongoUrl: process.env.MONGO_URL, - init() { - this._init(err => { - this.inited = !err; - }); - }, - _init(callback) { - const self = this; - mongodb.MongoClient.connect(self.mongoUrl, self.mongoOptions, function( - err, - db, - ) { - if (err) { - return callback(err); - } - self.db = db; - return callback(null); - }); - return; - }, - createReadStream(fileKey, options) { - const self = this; - if (!self.inited) { - self.init(); - return undefined; - } - options = options || {}; - - // Init GridFS - const gfs = new Grid(self.db, mongodb); - - // Set the default streamning settings - const settings = { - _id: new mongodb.ObjectID(fileKey._id), - root: `cfs_gridfs.${storeName}`, - }; - - // Check if this should be a partial read - if ( - typeof options.start !== 'undefined' && - typeof options.end !== 'undefined' - ) { - // Add partial info - settings.range = { - startPos: options.start, - endPos: options.end, - }; - } - return gfs.createReadStream(settings); - }, - }; - GStore.init(); - const CRS = 'createReadStream'; - const _CRS = `_${CRS}`; - const FStore = _FStore._transform; - FStore[_CRS] = FStore[CRS].bind(FStore); - FStore[CRS] = function(fileObj, options) { - let stream; - try { - const localFile = path.join( - absolutePath, - FStore.storage.fileKey(fileObj), - ); - const state = fs.statSync(localFile); - if (state) { - stream = FStore[_CRS](fileObj, options); - } - } catch (e) { - // file is not there, try GridFS ? - stream = undefined; - } - if (stream) return stream; - else { - try { - const stream = GStore[CRS](GStore.fileKey(fileObj), options); - return stream; - } catch (e) { - return undefined; - } - } - }.bind(FStore); - store = _FStore; -} else { - store = new FS.Store.GridFS(localFSStore ? `G${storeName}` : 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, +function onAttachmentRemoving(cursor) { + const file = cursor.get()[0]; + const meta = file.meta; + Activities.insert({ + userId: this.userId, + type: 'card', + activityType: 'deleteAttachment', + attachmentId: file._id, + boardId: meta.boardId, + cardId: meta.cardId, + listId: meta.listId, + swimlaneId: meta.swimlaneId, }); + return true; } -function storagePath(defaultPath) { - const storePath = process.env.ATTACHMENTS_STORE_PATH; - return storePath ? storePath : defaultPath; +function onAttachmentRemoved(files) { + // Don't know why we need to remove the activity +/* for (let i in files) { + let doc = files[i]; + Activities.remove({ + attachmentId: doc._id, + }); + }*/ } export default Attachments; -- cgit v1.2.3-1-g7c22 From 012ca39a8dc29517aef191e85325f3e5889daf37 Mon Sep 17 00:00:00 2001 From: Romulus Urakagi Tsai Date: Fri, 8 May 2020 11:50:43 +0800 Subject: Attachment activities merging done --- models/activities.js | 6 +----- models/attachments.js | 21 +++++---------------- 2 files changed, 6 insertions(+), 21 deletions(-) (limited to 'models') diff --git a/models/activities.js b/models/activities.js index df207bca..2663dd29 100644 --- a/models/activities.js +++ b/models/activities.js @@ -217,11 +217,7 @@ if (Meteor.isServer) { } if (activity.attachmentId) { const attachment = activity.attachment(); - if (attachment.original) { - params.attachment = attachment.original.name; - } else { - params.attachment = attachment.versions.original.name; - } + params.attachment = attachment.name; params.attachmentId = attachment._id; } if (activity.checklistId) { diff --git a/models/attachments.js b/models/attachments.js index cab3d9e3..d469f702 100644 --- a/models/attachments.js +++ b/models/attachments.js @@ -8,8 +8,7 @@ Attachments = new FilesCollection({ allowClientCode: true, collectionName: 'attachments2', onAfterUpload: onAttachmentUploaded, - onBeforeRemove: onAttachmentRemoving, - onAfterRemove: onAttachmentRemoved + onBeforeRemove: onAttachmentRemoving }); if (Meteor.isServer) { @@ -41,9 +40,9 @@ function onAttachmentUploaded(fileRef) { type: 'card', activityType: 'addAttachment', attachmentId: fileRef._id, - // this preserves the name so that notifications can be meaningful after + // this preserves the name so that notifications can be meaningful after // this file is removed - attachmentName: fileRef.versions.original.name, + attachmentName: fileRef.name, boardId: fileRef.meta.boardId, cardId: fileRef.meta.cardId, listId: fileRef.meta.listId, @@ -73,9 +72,9 @@ function onAttachmentRemoving(cursor) { type: 'card', activityType: 'deleteAttachment', attachmentId: file._id, - // this preserves the name so that notifications can be meaningful after + // this preserves the name so that notifications can be meaningful after // this file is removed - attachmentName: file.versions.original.name, + attachmentName: file.name, boardId: meta.boardId, cardId: meta.cardId, listId: meta.listId, @@ -84,14 +83,4 @@ function onAttachmentRemoving(cursor) { return true; } -function onAttachmentRemoved(files) { - // Don't know why we need to remove the activity -/* for (let i in files) { - let doc = files[i]; - Activities.remove({ - attachmentId: doc._id, - }); - }*/ -} - export default Attachments; -- cgit v1.2.3-1-g7c22 From 4c5a2fbd1f8ad2f2447235442bf96b893f18a409 Mon Sep 17 00:00:00 2001 From: Romulus Urakagi Tsai Date: Thu, 14 May 2020 14:55:54 +0800 Subject: Card clone OK --- models/attachments.js | 35 +++++++++++++++++++++++++++++++++-- models/cards.js | 12 ++++++++---- 2 files changed, 41 insertions(+), 6 deletions(-) (limited to 'models') diff --git a/models/attachments.js b/models/attachments.js index d469f702..1a55cb85 100644 --- a/models/attachments.js +++ b/models/attachments.js @@ -1,4 +1,5 @@ import { FilesCollection } from 'meteor/ostrio:files'; +const fs = require('fs'); const collectionName = 'attachments2'; @@ -19,6 +20,36 @@ if (Meteor.isServer) { // TODO: Permission related // TODO: Add Activity update + Meteor.methods({ + cloneAttachment(file, overrides) { + check(file, Object); + check(overrides, Match.Maybe(Object)); + const path = file.path; + const opts = { + fileName: file.name, + type: file.type, + meta: file.meta, + userId: file.userId + }; + for (let key in overrides) { + if (key === 'meta') { + for (let metaKey in overrides.meta) { + opts.meta[metaKey] = overrides.meta[metaKey]; + } + } else { + opts[key] = overrides[key]; + } + } + const buffer = fs.readFileSync(path); + Attachments.write(buffer, opts, (err, fileRef) => { + if (err) { + console.log('Error when cloning record', err); + } + }); + return true; + } + }); + Meteor.publish(collectionName, function() { return Attachments.find().cursor; }); @@ -51,13 +82,13 @@ function onAttachmentUploaded(fileRef) { } else { // Don't add activity about adding the attachment as the activity // be imported and delete source field - CFSAttachments.update( + Attachments.collection.update( { _id: fileRef._id, }, { $unset: { - source: '', + 'meta.source': '', }, }, ); diff --git a/models/cards.js b/models/cards.js index 1236de1a..ae52ff04 100644 --- a/models/cards.js +++ b/models/cards.js @@ -402,10 +402,14 @@ Cards.helpers({ const _id = Cards.insert(this); // Copy attachments - oldCard.attachments().forEach(att => { - att.meta.cardId = _id; - delete att._id; - return Attachments.insert(att); + oldCard.attachments().forEach((file) => { + Meteor.call('cloneAttachment', file, + { + meta: { + cardId: _id + } + } + ); }); // copy checklists -- cgit v1.2.3-1-g7c22 From 4064f3f4063136c97aa7bcbcdc18fec923934b74 Mon Sep 17 00:00:00 2001 From: Romulus Urakagi Tsai Date: Wed, 20 May 2020 15:11:22 +0800 Subject: Fix migrated attachment not readable bug Remove reduandant files --- models/attachments.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'models') diff --git a/models/attachments.js b/models/attachments.js index 1a55cb85..03999f55 100644 --- a/models/attachments.js +++ b/models/attachments.js @@ -6,7 +6,7 @@ const collectionName = 'attachments2'; Attachments = new FilesCollection({ storagePath: storagePath(), debug: false, - allowClientCode: true, +// allowClientCode: true, collectionName: 'attachments2', onAfterUpload: onAttachmentUploaded, onBeforeRemove: onAttachmentRemoving @@ -18,7 +18,17 @@ if (Meteor.isServer) { }); // TODO: Permission related - // TODO: Add Activity update + Attachments.allow({ + insert() { + return false; + }, + update() { + return true; + }, + remove() { + return true; + } + }); Meteor.methods({ cloneAttachment(file, overrides) { @@ -63,7 +73,7 @@ function storagePath(defaultPath) { } function onAttachmentUploaded(fileRef) { - Attachments.update({_id:fileRef._id}, {$set: {"meta.uploaded": true}}); + Attachments.update({_id:fileRef._id}, {$set: {"meta.uploading": false}}); if (!fileRef.meta.source || fileRef.meta.source !== 'import') { // Add activity about adding the attachment Activities.insert({ -- cgit v1.2.3-1-g7c22 From 921460db4031134db863e32101c0ad60a17416b5 Mon Sep 17 00:00:00 2001 From: Romulus Urakagi Tsai Date: Fri, 22 May 2020 14:59:56 +0800 Subject: Fix export attachments (not tested) --- models/export.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'models') diff --git a/models/export.js b/models/export.js index 35e55804..1eb47e54 100644 --- a/models/export.js +++ b/models/export.js @@ -146,7 +146,7 @@ export class Exporter { `tmpexport${process.pid}${Math.random()}`, ); const tmpWriteable = fs.createWriteStream(tmpFile); - const readStream = doc.createReadStream(); + const readStream = fs.createReadStream(doc.path); readStream.on('data', function(chunk) { buffer = Buffer.concat([buffer, chunk]); }); @@ -173,11 +173,11 @@ export class Exporter { return { _id: attachment._id, - cardId: attachment.cardId, + cardId: attachment.meta.cardId, //url: FlowRouter.url(attachment.url()), file: filebase64, - name: attachment.original.name, - type: attachment.original.type, + name: attachment.name, + type: attachment.type, }; }); -- cgit v1.2.3-1-g7c22