From 2435165feffdcdcf9aed4c4357c2cf6ae4e255fb Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Wed, 2 Dec 2015 18:29:56 -0200 Subject: [PATCH] Create page to manage assets and change favicons --- .meteor/packages | 1 + .meteor/versions | 1 + i18n/en.i18n.json | 5 + .../rocketchat-assets/.npm/package/.gitignore | 1 + .../rocketchat-assets/.npm/package/README | 7 + .../.npm/package/npm-shrinkwrap.json | 7 + packages/rocketchat-assets/package.js | 28 +++ .../rocketchat-assets/server/assets.coffee | 165 ++++++++++++++++++ .../server/startup.coffee | 3 + .../server/functions/settings.coffee | 13 ++ .../assets/stylesheets/base.less | 39 +++++ .../rocketchat-ui-admin/admin/admin.coffee | 30 ++++ packages/rocketchat-ui-admin/admin/admin.html | 25 +++ .../rocketchat-ui-master/master/main.html | 14 +- 14 files changed, 332 insertions(+), 7 deletions(-) create mode 100644 packages/rocketchat-assets/.npm/package/.gitignore create mode 100644 packages/rocketchat-assets/.npm/package/README create mode 100644 packages/rocketchat-assets/.npm/package/npm-shrinkwrap.json create mode 100644 packages/rocketchat-assets/package.js create mode 100644 packages/rocketchat-assets/server/assets.coffee diff --git a/.meteor/packages b/.meteor/packages index 5dd240ea647..e64873f3d2a 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -123,3 +123,4 @@ yasaricli:slugify yasinuslu:blaze-meta # sanjo:jasmine # velocity:html-reporter +rocketchat:assets diff --git a/.meteor/versions b/.meteor/versions index 44db73cc5ff..8c88fab5cc1 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -122,6 +122,7 @@ reactive-dict@1.1.3 reactive-var@1.0.6 reload@1.1.4 retry@1.0.4 +rocketchat:assets@0.0.1 rocketchat:authorization@0.0.1 rocketchat:autolinker@0.0.1 rocketchat:channel-settings@0.0.1 diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index fd9b9d2b84f..9dc586d6867 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -168,10 +168,14 @@ "Install_FxOs_done" : "Great! You can now use Rocket.Chat via the icon on your homescreen. Have fun with Rocket.Chat!", "Install_FxOs_error" : "Sorry, that did not work as intended! The following error appeared:", "Install_FxOs_follow_instructions" : "Please confirm the app installation on your device (press \"Install\" when prompted).", + "Invalid_asset" : "Invalid asset", "Invalid_confirm_pass" : "The password confirmation does not match password", "Invalid_Secret_URL" : "Invalid Secret URL", "Invalid_secret_URL_message" : "The URL provided is invalid.", "Invalid_email" : "The e-mail entered is invalid", + "Invalid_file_height" : "Invalid file height", + "Invalid_file_type" : "Invalid file type", + "Invalid_file_width" : "Invalid file width", "Invalid_name" : "The name must not be empty", "Invalid_pass" : "The password must not be empty", "Invalid_room_name" : "%s is not a valid room name,
use only letters, numbers and dashes", @@ -419,6 +423,7 @@ "Unread_Rooms" : "Unread Rooms", "Unread_Rooms_Mode" : "Unread Rooms Mode", "Upload_file_question" : "Upload file?", + "Uploading_file" : "Uploading file...", "Use_Emojis" : "Use Emojis", "Use_initials_avatar" : "Use your username initials", "use_menu" : "Use the side menu to access your rooms and chats", diff --git a/packages/rocketchat-assets/.npm/package/.gitignore b/packages/rocketchat-assets/.npm/package/.gitignore new file mode 100644 index 00000000000..3c3629e647f --- /dev/null +++ b/packages/rocketchat-assets/.npm/package/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/rocketchat-assets/.npm/package/README b/packages/rocketchat-assets/.npm/package/README new file mode 100644 index 00000000000..3d492553a43 --- /dev/null +++ b/packages/rocketchat-assets/.npm/package/README @@ -0,0 +1,7 @@ +This directory and the files immediately inside it are automatically generated +when you change this package's NPM dependencies. Commit the files in this +directory (npm-shrinkwrap.json, .gitignore, and this README) to source control +so that others run the same versions of sub-dependencies. + +You should NOT check in the node_modules directory that Meteor automatically +creates; if you are using git, the .gitignore file tells git to ignore it. diff --git a/packages/rocketchat-assets/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-assets/.npm/package/npm-shrinkwrap.json new file mode 100644 index 00000000000..f69e18d8fe1 --- /dev/null +++ b/packages/rocketchat-assets/.npm/package/npm-shrinkwrap.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "image-size": { + "version": "0.4.0" + } + } +} diff --git a/packages/rocketchat-assets/package.js b/packages/rocketchat-assets/package.js new file mode 100644 index 00000000000..e5f75eaf3d2 --- /dev/null +++ b/packages/rocketchat-assets/package.js @@ -0,0 +1,28 @@ +Package.describe({ + name: 'rocketchat:assets', + version: '0.0.1', + summary: '', + git: '' +}); + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.use([ + 'coffeescript', + 'underscore', + 'webapp', + 'rocketchat:file', + 'rocketchat:lib@0.0.1' + ]); + + api.addFiles('server/assets.coffee', 'server'); +}); + +Npm.depends({ + "image-size": "0.4.0" +}); + +Package.onTest(function(api) { + +}); diff --git a/packages/rocketchat-assets/server/assets.coffee b/packages/rocketchat-assets/server/assets.coffee new file mode 100644 index 00000000000..acf9d258456 --- /dev/null +++ b/packages/rocketchat-assets/server/assets.coffee @@ -0,0 +1,165 @@ +sizeOf = Npm.require 'image-size' + + +@RocketChatAssetsInstance = new RocketChatFile.GridFS + name: 'assets' + + +assets = + 'favicon.ico': + label: 'favicon.ico' + defaultUrl: 'favicon.ico?v=3' + constraints: + type: 'image' + contentType: 'image/vnd.microsoft.icon' + extention: 'ico' + width: undefined + height: undefined + 'favicon.svg': + label: 'favicon.svg' + defaultUrl: '/images/logo/icon.svg?v=3' + constraints: + type: 'image' + contentType: 'image/svg+xml' + extention: 'svg' + width: undefined + height: undefined + 'favicon_64.png': + label: 'favicon.png (64x64)' + defaultUrl: 'images/logo/favicon-64x64.png?v=3' + constraints: + type: 'image' + contentType: 'image/png' + extention: 'png' + width: 64 + height: 64 + 'favicon_96.png': + label: 'favicon.png (96x96)' + defaultUrl: 'images/logo/favicon-96x96.png?v=3' + constraints: + type: 'image' + contentType: 'image/png' + extention: 'png' + width: 96 + height: 96 + 'favicon_128.png': + label: 'favicon.png (128x128)' + defaultUrl: 'images/logo/favicon-128x128.png?v=3' + constraints: + type: 'image' + contentType: 'image/png' + extention: 'png' + width: 128 + height: 128 + 'favicon_192.png': + label: 'favicon.png (192x192)' + defaultUrl: 'images/logo/android-chrome-192x192.png?v=3' + constraints: + type: 'image' + contentType: 'image/png' + extention: 'png' + width: 192 + height: 192 + 'favicon_256.png': + label: 'favicon.png (256x256)' + defaultUrl: 'images/logo/favicon-256x256.png?v=3' + constraints: + type: 'image' + contentType: 'image/png' + extention: 'png' + width: 256 + height: 256 + + +RocketChat.settings.addGroup 'Assets' +for key, value of assets + RocketChat.settings.add "Assets_#{key}", '', { type: 'asset', group: 'Assets', fileConstraints: value.constraints, i18nLabel: value.label, asset: key } + + +Meteor.methods + unsetAsset: (asset) -> + unless Meteor.userId() + throw new Meteor.Error 'invalid-user', "[methods] unsetAsset -> Invalid user" + + hasPermission = RocketChat.authz.hasPermission Meteor.userId(), 'manage-assets' + unless hasPermission + throw new Meteor.Error 'manage-assets-not-allowed', "[methods] unsetAsset -> Manage assets not allowed" + + if not assets[asset]? + throw new Meteor.Error "Invalid_asset" + + RocketChatAssetsInstance.deleteFile asset + RocketChat.settings.clearById "Assets_#{asset}" + + +Meteor.methods + setAsset: (binaryContent, contentType, asset) -> + unless Meteor.userId() + throw new Meteor.Error 'invalid-user', "[methods] setAsset -> Invalid user" + + hasPermission = RocketChat.authz.hasPermission Meteor.userId(), 'manage-assets' + unless hasPermission + throw new Meteor.Error 'manage-assets-not-allowed', "[methods] unsetAsset -> Manage assets not allowed" + + if not assets[asset]? + throw new Meteor.Error "Invalid_asset" + + if contentType isnt assets[asset].constraints.contentType + throw new Meteor.Error "Invalid_file_type" + + file = new Buffer(binaryContent, 'binary') + + if assets[asset].constraints.width? or assets[asset].constraints.height? + dimensions = sizeOf file + + if assets[asset].constraints.width? and assets[asset].constraints.width isnt dimensions.width + throw new Meteor.Error "Invalid_file_width" + + if assets[asset].constraints.height? and assets[asset].constraints.height isnt dimensions.height + throw new Meteor.Error "Invalid_file_height" + + rs = RocketChatFile.bufferToStream file + RocketChatAssetsInstance.deleteFile asset + ws = RocketChatAssetsInstance.createWriteStream asset, contentType + ws.on 'end', Meteor.bindEnvironment -> + Meteor.setTimeout -> + RocketChat.settings.updateById "Assets_#{asset}", "/assets/#{asset}" + , 200 + + rs.pipe ws + return + + +WebApp.connectHandlers.use '/assets/', (req, res, next) -> + params = + asset: decodeURIComponent(req.url.replace(/^\//, '').replace(/\?.*$/, '')) + + file = RocketChatAssetsInstance.getFileWithReadStream params.asset + + # res.setHeader 'Content-Disposition', 'inline' + + if not file? + if assets[params.asset]?.defaultUrl? + res.writeHead 301, + Location: Meteor.absoluteUrl(assets[params.asset].defaultUrl) + else + res.writeHead 404 + res.end() + return + + reqModifiedHeader = req.headers["if-modified-since"]; + if reqModifiedHeader? + if reqModifiedHeader == file.uploadDate?.toUTCString() + res.setHeader 'Last-Modified', reqModifiedHeader + res.writeHead 304 + res.end() + return + + res.setHeader 'Cache-Control', 'public, max-age=0' + res.setHeader 'Expires', '-1' + res.setHeader 'Last-Modified', file.uploadDate?.toUTCString() or new Date().toUTCString() + res.setHeader 'Content-Type', file.contentType + res.setHeader 'Content-Length', file.length + + file.readStream.pipe res + return diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index a938b289c01..e1b57d541e7 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -89,6 +89,9 @@ Meteor.startup -> { _id: 'access-permissions', roles : ['admin']} + + { _id: 'manage-assets', + roles : ['admin']} ] #alanning:roles diff --git a/packages/rocketchat-lib/server/functions/settings.coffee b/packages/rocketchat-lib/server/functions/settings.coffee index 02ade134fca..34f829a6d9d 100644 --- a/packages/rocketchat-lib/server/functions/settings.coffee +++ b/packages/rocketchat-lib/server/functions/settings.coffee @@ -91,6 +91,19 @@ RocketChat.settings.updateById = (_id, value) -> return RocketChat.models.Settings.updateValueById _id, value +### +# Update a setting by id +# @param {String} _id +### +RocketChat.settings.clearById = (_id) -> + # console.log '[functions] RocketChat.settings.clearById -> '.green, 'arguments:', arguments + + if not _id? + return false + + return RocketChat.models.Settings.updateValueById _id, undefined + + ### # Update a setting by id ### diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index bfa3d0bf261..a46ab872cad 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -1729,6 +1729,45 @@ a.github-fork { width: 100%; padding: 0; } + + .settings-file-preview { + display: flex; + align-items: center; + + input[type=file] { + position: absolute !important; + width: 100%; + top: 0; + left: 0; + height: 100%; + opacity: 0; + z-index: 10000; + cursor: pointer; + * { + cursor: pointer; + } + } + + .preview { + height: 50px; + width: 100px; + border-radius: 4px; + overflow: hidden; + box-shadow: 0 0 1px rgba(0,0,0,.5) inset; + background-size: contain; + background-position: center center; + background-repeat: no-repeat; + + &.no-file { + background-color: #fafafa; + display: flex; + align-items: center; + justify-content: center; + color: #ccc; + font-size: 24px; + } + } + } } .page-static { diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index f74cc51206a..fe0aeea2948 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -40,6 +40,9 @@ Template.admin.helpers selectedOption: (_id, val) -> return RocketChat.settings.get(_id) is val + random: -> + return Random.id() + Template.admin.events "click .submit .save": (e, t) -> group = FlowRouter.getParam('group') @@ -100,6 +103,33 @@ Template.admin.events swal config, -> Meteor.call 'removeOAuthService', name + "click .delete-asset": -> + Meteor.call 'unsetAsset', @asset + + "change input[type=file]": -> + e = event.originalEvent or event + files = e.target.files + if not files or files.length is 0 + files = e.dataTransfer?.files or [] + + for blob in files + toastr.info TAPi18n.__ 'Uploading_file' + + if @fileConstraints.contentType isnt blob.type + toastr.error TAPi18n.__ 'Invalid_file_type' + return + + reader = new FileReader() + reader.readAsBinaryString(blob) + reader.onloadend = => + Meteor.call 'setAsset', reader.result, blob.type, @asset, (err, data) -> + if err? + toastr.error TAPi18n.__ err.error + console.log err.error + return + + toastr.success TAPi18n.__ 'File_uploaded' + Template.admin.onRendered -> Tracker.afterFlush -> diff --git a/packages/rocketchat-ui-admin/admin/admin.html b/packages/rocketchat-ui-admin/admin/admin.html index f8152fc11a6..a13f52cb1b0 100644 --- a/packages/rocketchat-ui-admin/admin/admin.html +++ b/packages/rocketchat-ui-admin/admin/admin.html @@ -43,13 +43,16 @@ {{/if}} {{/if}} + {{#if $eq type 'int'}} {{/if}} + {{#if $eq type 'boolean'}} {{/if}} + {{#if $eq type 'select'}} {{/if}} + {{#if $eq type 'color'}} {{/if}} + + {{#if $eq type 'asset'}} + {{#if value}} +
+
+
+ +
+
+ {{else}} +
+
+
+
{{_ 'Select_file'}} + +
+
+
+ {{/if}} + {{/if}} + {{#if description}}
{{{description}}}
{{/if}} diff --git a/packages/rocketchat-ui-master/master/main.html b/packages/rocketchat-ui-master/master/main.html index 68b8c7ccb27..4219a22d722 100644 --- a/packages/rocketchat-ui-master/master/main.html +++ b/packages/rocketchat-ui-master/master/main.html @@ -13,18 +13,18 @@ - - - - - - + + + + + + - +