diff --git a/client/components/settings/attachments.jade b/client/components/settings/attachments.jade new file mode 100644 index 000000000..e9a3da328 --- /dev/null +++ b/client/components/settings/attachments.jade @@ -0,0 +1,81 @@ +template(name="attachments") + .setting-content.attachments-content + unless currentUser.isAdmin + | {{_ 'error-notAuthorized'}} + else + .content-body + .side-menu + ul + li + a.js-move-attachments(data-id="move-attachments") + i.fa.fa-arrow-right + | {{_ 'attachment-move'}} + + .main-body + if loading.get + +spinner + else if showMoveAttachments.get + +moveAttachments + +template(name="moveAttachments") + .js-move-attachment + button.js-move-all-attachments-to-fs {{_ 'move-all-attachments-to-fs'}} + .js-move-attachment + button.js-move-all-attachments-to-gridfs {{_ 'move-all-attachments-to-gridfs'}} + + each board in getBoardsWithAttachments + +moveBoardAttachments board + +template(name="moveBoardAttachments") + .board-description + table + tr + th {{_ 'board'}} ID + th {{_ 'board-title'}} + tr + td {{ _id }} + td {{ title }} + + .js-move-attachment + button.js-move-all-attachments-of-board-to-fs {{_ 'move-all-attachments-of-board-to-fs'}} + .js-move-attachment + button.js-move-all-attachments-of-board-to-gridfs {{_ 'move-all-attachments-of-board-to-gridfs'}} + + .board-attachments + table + tr + th {{_ 'card'}}-Id + th {{_ 'attachment'}}-Id + th {{_ 'name'}} + th {{_ 'path'}} + th {{_ 'version-name'}} + th {{_ 'size'}} (B) + th GridFsFileId + th {{_ 'storage'}} + th {{_ 'action'}} + + each attachment in attachments + +moveAttachment attachment + +template(name="moveAttachment") + each version in flatVersion + tr + td {{ meta.cardId }} + td {{ _id }} + td {{ name }} + td {{ version.path }} + td {{ version.versionName }} + td {{ version.size }} + td {{ version.meta.gridFsFileId }} + td {{ version.storageName }} + td + if $neq version.storageName "fs" + button.js-move-storage-fs + i.fa.fa-arrow-right + | {{_ 'attachment-move-storage-fs'}} + + if $neq version.storageName "gridfs" + if version.storageName + button.js-move-storage-gridfs + i.fa.fa-arrow-right + | {{_ 'attachment-move-storage-gridfs'}} diff --git a/client/components/settings/attachments.js b/client/components/settings/attachments.js new file mode 100644 index 000000000..c101ffcc7 --- /dev/null +++ b/client/components/settings/attachments.js @@ -0,0 +1,123 @@ +import Attachments, { fileStoreStrategyFactory } from '/models/attachments'; + +BlazeComponent.extendComponent({ + subscription: null, + showMoveAttachments: new ReactiveVar(false), + sessionId: null, + + onCreated() { + this.error = new ReactiveVar(''); + this.loading = new ReactiveVar(false); + }, + + events() { + return [ + { + 'click a.js-move-attachments': this.switchMenu, + }, + ]; + }, + + switchMenu(event) { + const target = $(event.target); + if (!target.hasClass('active')) { + this.loading.set(true); + this.showMoveAttachments.set(false); + if (this.subscription) { + this.subscription.stop(); + } + + $('.side-menu li.active').removeClass('active'); + target.parent().addClass('active'); + const targetID = target.data('id'); + + if ('move-attachments' === targetID) { + this.showMoveAttachments.set(true); + this.subscription = Meteor.subscribe('attachmentsList', () => { + this.loading.set(false); + }); + } + } + }, +}).register('attachments'); + +BlazeComponent.extendComponent({ + getBoardsWithAttachments() { + this.attachments = Attachments.find().get(); + this.attachmentsByBoardId = _.chain(this.attachments) + .groupBy(fileObj => fileObj.meta.boardId) + .value(); + + const ret = Object.keys(this.attachmentsByBoardId) + .map(boardId => { + const boardAttachments = this.attachmentsByBoardId[boardId]; + + _.each(boardAttachments, _attachment => { + _attachment.flatVersion = Object.keys(_attachment.versions) + .map(_versionName => { + const _version = Object.assign(_attachment.versions[_versionName], {"versionName": _versionName}); + _version.storageName = fileStoreStrategyFactory.getFileStrategy(_attachment, _versionName).getStorageName(); + return _version; + }); + }); + const board = Boards.findOne(boardId); + board.attachments = boardAttachments; + return board; + }) + return ret; + }, + getBoardData(boardid) { + const ret = Boards.findOne(boardId); + return ret; + }, + events() { + return [ + { + 'click button.js-move-all-attachments-to-fs'(event) { + this.attachments.forEach(_attachment => { + Meteor.call('moveAttachmentToStorage', _attachment._id, "fs"); + }); + }, + 'click button.js-move-all-attachments-to-gridfs'(event) { + this.attachments.forEach(_attachment => { + Meteor.call('moveAttachmentToStorage', _attachment._id, "gridfs"); + }); + }, + } + ] + } +}).register('moveAttachments'); + +BlazeComponent.extendComponent({ + events() { + return [ + { + 'click button.js-move-all-attachments-of-board-to-fs'(event) { + this.data().attachments.forEach(_attachment => { + Meteor.call('moveAttachmentToStorage', _attachment._id, "fs"); + }); + }, + 'click button.js-move-all-attachments-of-board-to-gridfs'(event) { + this.data().attachments.forEach(_attachment => { + Meteor.call('moveAttachmentToStorage', _attachment._id, "gridfs"); + }); + }, + } + ] + }, +}).register('moveBoardAttachments'); + +BlazeComponent.extendComponent({ + events() { + return [ + { + 'click button.js-move-storage-fs'(event) { + Meteor.call('moveAttachmentToStorage', this.data()._id, "fs"); + }, + 'click button.js-move-storage-gridfs'(event) { + Meteor.call('moveAttachmentToStorage', this.data()._id, "gridfs"); + }, + } + ] + }, +}).register('moveAttachment'); diff --git a/client/components/settings/settingHeader.jade b/client/components/settings/settingHeader.jade index 14de3ab1f..72ed611c8 100644 --- a/client/components/settings/settingHeader.jade +++ b/client/components/settings/settingHeader.jade @@ -16,6 +16,10 @@ template(name="settingHeaderBar") i.fa(class="fa-list") span {{_ 'reports'}} + a.setting-header-btn.informations(href="{{pathFor 'attachments'}}") + i.fa(class="fa-paperclip") + span {{_ 'attachments'}} + a.setting-header-btn.informations(href="{{pathFor 'information'}}") i.fa(class="fa-info-circle") span {{_ 'info'}} diff --git a/config/router.js b/config/router.js index 7e8f78660..43900da69 100644 --- a/config/router.js +++ b/config/router.js @@ -355,6 +355,30 @@ FlowRouter.route('/admin-reports', { }, }); +FlowRouter.route('/attachments', { + name: 'attachments', + triggersEnter: [ + AccountsTemplates.ensureSignedIn, + () => { + Session.set('currentBoard', null); + Session.set('currentList', null); + Session.set('currentCard', null); + Session.set('popupCardId', null); + Session.set('popupCardBoardId', null); + + Filter.reset(); + Session.set('sortBy', ''); + EscapeActions.executeAll(); + }, + ], + action() { + BlazeLayout.render('defaultLayout', { + headerBar: 'settingHeaderBar', + content: 'attachments', + }); + }, +}); + FlowRouter.notFound = { action() { BlazeLayout.render('defaultLayout', { content: 'notFound' }); diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 639667f6e..a4f2d204c 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -1166,5 +1166,16 @@ "subtaskActionsPopup-title": "Subtask Actions", "attachmentActionsPopup-title": "Attachment Actions", "attachment-move-storage-fs": "Move attachment to filesystem", - "attachment-move-storage-gridfs": "Move attachment to GridFS" + "attachment-move-storage-gridfs": "Move attachment to GridFS", + "attachment-move": "Move Attachment", + "move-all-attachments-to-fs": "Move all attachments to filesystem", + "move-all-attachments-to-gridfs": "Move all attachments to GridFS", + "move-all-attachments-of-board-to-fs": "Move all attachments of board to filesystem", + "move-all-attachments-of-board-to-gridfs": "Move all attachments of board to GridFS", + "path": "Path", + "version-name": "Version-Name", + "size": "Size", + "storage": "Storage", + "action": "Action", + "board-title": "Board Title" } diff --git a/models/attachments.js b/models/attachments.js index b89fda85c..aaa4f370e 100644 --- a/models/attachments.js +++ b/models/attachments.js @@ -13,7 +13,7 @@ if (Meteor.isServer) { storagePath = path.join(process.env.WRITABLE_PATH, 'attachments'); } -const fileStoreStrategyFactory = new FileStoreStrategyFactory(AttachmentStoreStrategyFilesystem, storagePath, AttachmentStoreStrategyGridFs, attachmentBucket); +export const fileStoreStrategyFactory = new FileStoreStrategyFactory(AttachmentStoreStrategyFilesystem, storagePath, AttachmentStoreStrategyGridFs, attachmentBucket); // XXX Enforce a schema for the Attachments FilesCollection // see: https://github.com/VeliovGroup/Meteor-Files/wiki/Schema diff --git a/server/publications/attachments.js b/server/publications/attachments.js index fe89cd3c8..d6eab790c 100644 --- a/server/publications/attachments.js +++ b/server/publications/attachments.js @@ -1,7 +1,7 @@ import Attachments from '/models/attachments'; import { ObjectID } from 'bson'; -Meteor.publish('attachmentsList', function() { +Meteor.publish('attachmentsList', function(limit) { const ret = Attachments.find( {}, { @@ -11,11 +11,13 @@ Meteor.publish('attachmentsList', function() { size: 1, type: 1, meta: 1, + path: 1, + versions: 1, }, sort: { name: 1, }, - limit: 250, + limit: limit, }, ).cursor; return ret;