diff --git a/.meteor/packages b/.meteor/packages index f234baea6..a455c6392 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -96,3 +96,4 @@ konecty:mongo-counter percolate:synced-cron easylogic:summernote cfs:filesystem +ostrio:files diff --git a/.meteor/versions b/.meteor/versions index 3b45f9864..9b5fb93e7 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -133,6 +133,8 @@ oauth2@1.2.1 observe-sequence@1.0.16 ongoworks:speakingurl@1.1.0 ordered-dict@1.1.0 +ostrio:cookies@2.5.0 +ostrio:files@1.13.0 peerlibrary:assert@0.2.5 peerlibrary:base-component@0.16.0 peerlibrary:blaze-components@0.15.1 diff --git a/atachments/attachments-gAjLYeSrtAneFBdzt-提議者電子郵件(第一波+第二波).xlsx b/atachments/attachments-gAjLYeSrtAneFBdzt-提議者電子郵件(第一波+第二波).xlsx new file mode 100644 index 000000000..4e89ac5d9 Binary files /dev/null and b/atachments/attachments-gAjLYeSrtAneFBdzt-提議者電子郵件(第一波+第二波).xlsx differ diff --git a/client/components/cards/attachments.js b/client/components/cards/attachments.js index e4439155e..604dc0783 100644 --- a/client/components/cards/attachments.js +++ b/client/components/cards/attachments.js @@ -149,20 +149,28 @@ Template.previewClipboardImagePopup.events({ if (results && results.file) { window.oPasted = pastedResults; const card = this; - const file = new FS.File(results.file); + const settings = { + file: results.file, + streams: 'dynamic', + chunkSize: 'dynamic' + }; if (!results.name) { // if no filename, it's from clipboard. then we give it a name, with ext name from MIME type + // FIXME: Check this behavior if (typeof results.file.type === 'string') { - file.name(results.file.type.replace('image/', 'clipboard.')); + settings.fileName = new Date().getTime() + results.file.type.replace('.+/', ''); } } - file.updatedAt(new Date()); - file.boardId = card.boardId; - file.cardId = card._id; - file.userId = Meteor.userId(); - const attachment = Attachments.insert(file); + settings.meta = {}; + settings.meta.updatedAt = new Date().getTime(); + settings.meta.boardId = card.boardId; + settings.meta.cardId = card._id; + settings.meta.userId = Meteor.userId(); + console.log('settings', settings); + const attachment = Attachments.insert(settings, false); - if (attachment && attachment._id && attachment.isImage()) { + // TODO: Check image cover behavior + if (attachment && attachment._id && attachment.isImage) { card.setCover(attachment._id); } diff --git a/client/lib/utils.js b/client/lib/utils.js index cc3526c03..2694396f0 100644 --- a/client/lib/utils.js +++ b/client/lib/utils.js @@ -34,21 +34,27 @@ Utils = { if (!card) { return next(); } - const file = new FS.File(fileObj); + let settings = { + file: fileObj, + streams: 'dynamic', + chunkSize: 'dynamic' + }; + settings.meta = {}; if (card.isLinkedCard()) { - file.boardId = Cards.findOne(card.linkedId).boardId; - file.cardId = card.linkedId; + settings.meta.boardId = Cards.findOne(card.linkedId).boardId; + settings.meta.cardId = card.linkedId; } else { - file.boardId = card.boardId; - file.swimlaneId = card.swimlaneId; - file.listId = card.listId; - file.cardId = card._id; + settings.meta.boardId = card.boardId; + settings.meta.swimlaneId = card.swimlaneId; + settings.meta.listId = card.listId; + settings.meta.cardId = card._id; } - file.userId = Meteor.userId(); - if (file.original) { + settings.meta.userId = Meteor.userId(); + // FIXME: What is this? +/* if (file.original) { file.original.name = fileObj.name; - } - return next(Attachments.insert(file)); + }*/ + return next(Attachments.insert(settings, false)); }, shrinkImage(options) { // shrink image to certain size diff --git a/models/attachments.js b/models/attachments.js index 9b8ec04f3..fd03e6d24 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; diff --git a/rebuild-wekan.bat b/rebuild-wekan.bat index 056148995..8ea786cbb 100644 --- a/rebuild-wekan.bat +++ b/rebuild-wekan.bat @@ -1,56 +1,56 @@ -@ECHO OFF - -REM NOTE: THIS .BAT DOES NOT WORK !! -REM Use instead this webpage instructions to build on Windows: -REM https://github.com/wekan/wekan/wiki/Install-Wekan-from-source-on-Windows -REM Please add fix PRs, like config of MongoDB etc. - -md C:\repos -cd C:\repos - -REM Install chocolatey -@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin" - -choco install -y git curl python2 dotnet4.5.2 nano mongodb-3 mongoclient meteor - -curl -O https://nodejs.org/dist/v8.16.1/node-v8.16.1-x64.msi -call node-v8.16.1-x64.msi - -call npm config -g set msvs_version 2015 -call meteor npm config -g set msvs_version 2015 - -call npm -g install npm -call npm -g install node-gyp -call npm -g install fibers -cd C:\repos -git clone https://github.com/wekan/wekan.git -cd wekan -git checkout edge -echo "Building Wekan." -REM del /S /F /Q packages -REM ## REPOS BELOW ARE INCLUDED TO WEKAN -REM md packages -REM cd packages -REM git clone --depth 1 -b master https://github.com/wekan/flow-router.git kadira-flow-router -REM git clone --depth 1 -b master https://github.com/meteor-useraccounts/core.git meteor-useraccounts-core -REM git clone --depth 1 -b master https://github.com/wekan/meteor-accounts-cas.git -REM git clone --depth 1 -b master https://github.com/wekan/wekan-ldap.git -REM git clone --depth 1 -b master https://github.com/wekan/wekan-scrollbar.git -REM git clone --depth 1 -b master https://github.com/wekan/meteor-accounts-oidc.git -REM git clone --depth 1 -b master --recurse-submodules https://github.com/wekan/markdown.git -REM move meteor-accounts-oidc/packages/switch_accounts-oidc wekan_accounts-oidc -REM move meteor-accounts-oidc/packages/switch_oidc wekan_oidc -REM del /S /F /Q meteor-accounts-oidc -REM sed -i 's/api\.versionsFrom/\/\/api.versionsFrom/' ~/repos/wekan/packages/meteor-useraccounts-core/package.js -cd .. -REM del /S /F /Q node_modules -call meteor npm install -REM del /S /F /Q .build -call meteor build .build --directory -copy fix-download-unicode\cfs_access-point.txt .build\bundle\programs\server\packages\cfs_access-point.js -cd .build\bundle\programs\server -call meteor npm install -REM cd C:\repos\wekan\.meteor\local\build\programs\server -REM del node_modules -cd C:\repos\wekan -call start-wekan.bat +@ECHO OFF + +REM NOTE: THIS .BAT DOES NOT WORK !! +REM Use instead this webpage instructions to build on Windows: +REM https://github.com/wekan/wekan/wiki/Install-Wekan-from-source-on-Windows +REM Please add fix PRs, like config of MongoDB etc. + +md C:\repos +cd C:\repos + +REM Install chocolatey +@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin" + +choco install -y git curl python2 dotnet4.5.2 nano mongodb-3 mongoclient meteor + +curl -O https://nodejs.org/dist/v8.16.1/node-v8.16.1-x64.msi +call node-v8.16.1-x64.msi + +call npm config -g set msvs_version 2015 +call meteor npm config -g set msvs_version 2015 + +call npm -g install npm +call npm -g install node-gyp +call npm -g install fibers +cd C:\repos +git clone https://github.com/wekan/wekan.git +cd wekan +git checkout edge +echo "Building Wekan." +REM del /S /F /Q packages +REM ## REPOS BELOW ARE INCLUDED TO WEKAN +REM md packages +REM cd packages +REM git clone --depth 1 -b master https://github.com/wekan/flow-router.git kadira-flow-router +REM git clone --depth 1 -b master https://github.com/meteor-useraccounts/core.git meteor-useraccounts-core +REM git clone --depth 1 -b master https://github.com/wekan/meteor-accounts-cas.git +REM git clone --depth 1 -b master https://github.com/wekan/wekan-ldap.git +REM git clone --depth 1 -b master https://github.com/wekan/wekan-scrollbar.git +REM git clone --depth 1 -b master https://github.com/wekan/meteor-accounts-oidc.git +REM git clone --depth 1 -b master --recurse-submodules https://github.com/wekan/markdown.git +REM move meteor-accounts-oidc/packages/switch_accounts-oidc wekan_accounts-oidc +REM move meteor-accounts-oidc/packages/switch_oidc wekan_oidc +REM del /S /F /Q meteor-accounts-oidc +REM sed -i 's/api\.versionsFrom/\/\/api.versionsFrom/' ~/repos/wekan/packages/meteor-useraccounts-core/package.js +cd .. +REM del /S /F /Q node_modules +call meteor npm install +REM del /S /F /Q .build +call meteor build .build --directory +copy fix-download-unicode\cfs_access-point.txt .build\bundle\programs\server\packages\cfs_access-point.js +cd .build\bundle\programs\server +call meteor npm install +REM cd C:\repos\wekan\.meteor\local\build\programs\server +REM del node_modules +cd C:\repos\wekan +call start-wekan.bat diff --git a/server/publications/boards.js b/server/publications/boards.js index e30958332..79e578b85 100644 --- a/server/publications/boards.js +++ b/server/publications/boards.js @@ -128,7 +128,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); + const attachments = this.join(Attachments.collection); attachments.selector = _ids => ({ cardId: _ids }); const checklists = this.join(Checklists); checklists.selector = _ids => ({ cardId: _ids });