diff options
author | Lauri Ojansivu <x@xet7.org> | 2020-05-25 17:54:51 +0300 |
---|---|---|
committer | Lauri Ojansivu <x@xet7.org> | 2020-05-25 17:54:51 +0300 |
commit | d52affe65893f17bab59bb43aa9f5afbb54993d3 (patch) | |
tree | 82b88066d4fb8efb6610ed77177d3747d34f0480 /server | |
parent | 23dcd084a49de4e6568527d8f97ed25adb04dafd (diff) | |
download | wekan-d52affe65893f17bab59bb43aa9f5afbb54993d3.tar.gz wekan-d52affe65893f17bab59bb43aa9f5afbb54993d3.tar.bz2 wekan-d52affe65893f17bab59bb43aa9f5afbb54993d3.zip |
Move In Progress ostrio-files changes to separate branch, and revert ostrio-files changes, so that:
- Export to CSV/TSV with custom fields works
- Attachments are not exported to disk
- It is possible to build arm64/s390x versions again.
Thanks to xet7 !
Related #3110
Diffstat (limited to 'server')
-rw-r--r-- | server/migrations.js | 45 | ||||
-rw-r--r-- | server/old-attachments-migration.js | 212 | ||||
-rw-r--r-- | server/publications/boards.js | 2 |
3 files changed, 2 insertions, 257 deletions
diff --git a/server/migrations.js b/server/migrations.js index 72b39ea7..5655bd1d 100644 --- a/server/migrations.js +++ b/server/migrations.js @@ -80,7 +80,7 @@ Migrations.add('lowercase-board-permission', () => { Migrations.add('change-attachments-type-for-non-images', () => { const newTypeForNonImage = 'application/octet-stream'; Attachments.find().forEach(file => { - if (!file.isImage) { + if (!file.isImage()) { Attachments.update( file._id, { @@ -1044,46 +1044,3 @@ Migrations.add('add-sort-field-to-boards', () => { } }); }); - -import { MongoInternals } from 'meteor/mongo'; - -Migrations.add('change-attachment-library', () => { - const fs = require('fs'); - CFSAttachments.find().forEach(file => { - const bucket = new MongoInternals.NpmModule.GridFSBucket(MongoInternals.defaultRemoteCollectionDriver().mongo.db, {bucketName: 'cfs_gridfs.attachments'}); - const gfsId = new MongoInternals.NpmModule.ObjectID(file.copies.attachments.key); - const reader = bucket.openDownloadStream(gfsId); - let store = Attachments.storagePath(); - if (store.charAt(store.length - 1) === '/') { - store = store.substring(0, store.length - 1); - } - const path = `${store}/${file.name()}`; - const fd = fs.createWriteStream(path); - reader.pipe(fd); - reader.on('end', () => { - let opts = { - fileName: file.name(), - type: file.type(), - size: file.size(), - fileId: file._id, - meta: { - userId: file.userId, - boardId: file.boardId, - cardId: file.cardId - } - }; - if (file.listId) { - opts.meta.listId = file.listId; - } - if (file.swimlaneId) { - opts.meta.swimlaneId = file.swimlaneId; - } - Attachments.addFile(path, opts, (err, fileRef) => { - if (err) { - console.log('error when migrating', file.name(), err); - } - }); - }); - }); -}); - diff --git a/server/old-attachments-migration.js b/server/old-attachments-migration.js deleted file mode 100644 index 3a6aa85d..00000000 --- a/server/old-attachments-migration.js +++ /dev/null @@ -1,212 +0,0 @@ -const localFSStore = process.env.ATTACHMENTS_STORE_PATH; -const storeName = 'attachments'; -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__"]}] */ - - if (!pathname && __meteor_bootstrap__ && __meteor_bootstrap__.serverDir) { - pathname = path.join( - __meteor_bootstrap__.serverDir, - `../../../cfs/files/${storeName}`, - ); - } - - 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, - }); -} -CFSAttachments = new FS.Collection('attachments', { - stores: [store], -}); - -if (Meteor.isServer) { - Meteor.startup(() => { - CFSAttachments.files._ensureIndex({ cardId: 1 }); - }); - - CFSAttachments.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) { - if (Meteor.isServer) { - return true; - } - const board = Boards.findOne(doc.boardId); - if (board.isPublic()) { - return true; - } else { - return board.hasMember(userId); - } - }, - - fetch: ['boardId'], - }); -} - -export default CFSAttachments; diff --git a/server/publications/boards.js b/server/publications/boards.js index ae82d28c..b80a6b23 100644 --- a/server/publications/boards.js +++ b/server/publications/boards.js @@ -131,7 +131,7 @@ Meteor.publishRelations('board', function(boardId, isArchived) { // Gather queries and send in bulk const cardComments = this.join(CardComments); cardComments.selector = _ids => ({ cardId: _ids }); - const attachments = this.join(Attachments.collection); + const attachments = this.join(Attachments); attachments.selector = _ids => ({ cardId: _ids }); const checklists = this.join(Checklists); checklists.selector = _ids => ({ cardId: _ids }); |