From 66f7bad47b76543dbb72a9907df640e212bcd0b1 Mon Sep 17 00:00:00 2001 From: Aileen Nowak Date: Thu, 26 Jan 2017 18:17:34 +0700 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=20Blog=20icon=20uplod=20(#397)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refs TryGhost/Ghost#7688 - Adds new upload functionality for a blog icon in general settings. - Icons will be uploaded to a new endpoint `uploads/icons` to trigger different validations. --- .../admin/app/components/gh-image-uploader.js | 29 ++++++++++++++++--- .../admin/app/controllers/settings/general.js | 12 ++++++++ ghost/admin/app/models/setting.js | 1 + .../components/gh-image-uploader.hbs | 9 +++--- .../components/modals/upload-image.hbs | 6 +++- .../admin/app/templates/settings/general.hbs | 23 +++++++++++++-- ghost/admin/app/templates/team/user.hbs | 4 +-- ghost/admin/mirage/fixtures/settings.js | 10 +++++++ .../tests/acceptance/settings/general-test.js | 27 +++++++++++++++-- 9 files changed, 105 insertions(+), 16 deletions(-) diff --git a/ghost/admin/app/components/gh-image-uploader.js b/ghost/admin/app/components/gh-image-uploader.js index 8dd3ef1953..bf5f21841c 100644 --- a/ghost/admin/app/components/gh-image-uploader.js +++ b/ghost/admin/app/components/gh-image-uploader.js @@ -24,8 +24,10 @@ export default Component.extend({ text: '', altText: '', saveButton: true, - accept: 'image/gif,image/jpg,image/jpeg,image/png,image/svg+xml', - extensions: ['gif', 'jpg', 'jpeg', 'png', 'svg'], + accept: null, + extensions: null, + uploadUrl: null, + allowUrlInput: true, validate: null, dragClass: null, @@ -39,6 +41,10 @@ export default Component.extend({ config: injectService(), notifications: injectService(), + _defaultAccept: 'image/gif,image/jpg,image/jpeg,image/png,image/svg+xml', + _defaultExtensions: ['gif', 'jpg', 'jpeg', 'png', 'svg'], + _defaultUploadUrl: '/uploads/', + // TODO: this wouldn't be necessary if the server could accept direct // file uploads formData: computed('file', function () { @@ -83,6 +89,16 @@ export default Component.extend({ didReceiveAttrs() { let image = this.get('image'); this.set('url', image); + + if (!this.get('accept')) { + this.set('accept', this.get('_defaultAccept')); + } + if (!this.get('extensions')) { + this.set('extensions', this.get('_defaultExtensions')); + } + if (!this.get('uploadUrl')) { + this.set('uploadUrl', this.get('_defaultUploadUrl')); + } }, dragOver(event) { @@ -161,7 +177,10 @@ export default Component.extend({ } if (isUnsupportedMediaTypeError(error)) { - message = 'The image type you uploaded is not supported. Please use .PNG, .JPG, .GIF, .SVG.'; + let validExtensions = this.get('extensions').join(', .').toUpperCase(); + validExtensions = `.${validExtensions}`; + + message = `The image type you uploaded is not supported. Please use ${validExtensions}`; } else if (isRequestEntityTooLargeError(error)) { message = 'The image you uploaded was larger than the maximum file size your server allows.'; } else if (error.errors && !isBlank(error.errors[0].message)) { @@ -177,7 +196,9 @@ export default Component.extend({ generateRequest() { let ajax = this.get('ajax'); let formData = this.get('formData'); - let url = `${ghostPaths().apiRoot}/uploads/`; + let uploadUrl = this.get('uploadUrl'); + // CASE: we want to upload an icon and we have to POST it to a different endpoint, expecially for icons + let url = `${ghostPaths().apiRoot}${uploadUrl}`; this._uploadStarted(); diff --git a/ghost/admin/app/controllers/settings/general.js b/ghost/admin/app/controllers/settings/general.js index e6b45210b3..8ab8a3489d 100644 --- a/ghost/admin/app/controllers/settings/general.js +++ b/ghost/admin/app/controllers/settings/general.js @@ -14,6 +14,7 @@ export default Controller.extend(SettingsSaveMixin, { showUploadLogoModal: false, showUploadCoverModal: false, + showUploadIconModal: false, showDeleteThemeModal: notEmpty('themeToDelete'), ajax: injectService(), @@ -24,10 +25,17 @@ export default Controller.extend(SettingsSaveMixin, { _scratchFacebook: null, _scratchTwitter: null, + iconMimeTypes: 'image/png,image/x-icon', + iconExtensions: ['ico', 'png'], + logoImageSource: computed('model.logo', function () { return this.get('model.logo') || ''; }), + iconImageSource: computed('model.icon', function () { + return this.get('model.icon') || ''; + }), + coverImageSource: computed('model.cover', function () { return this.get('model.cover') || ''; }), @@ -131,6 +139,10 @@ export default Controller.extend(SettingsSaveMixin, { this.toggleProperty('showUploadLogoModal'); }, + toggleUploadIconModal() { + this.toggleProperty('showUploadIconModal'); + }, + validateFacebookUrl() { let newUrl = this.get('_scratchFacebook'); let oldUrl = this.get('model.facebook'); diff --git a/ghost/admin/app/models/setting.js b/ghost/admin/app/models/setting.js index 9bcad64dba..86a4e70425 100644 --- a/ghost/admin/app/models/setting.js +++ b/ghost/admin/app/models/setting.js @@ -10,6 +10,7 @@ export default Model.extend(ValidationEngine, { description: attr('string'), logo: attr('string'), cover: attr('string'), + icon: attr('string'), defaultLang: attr('string'), postsPerPage: attr('number'), forceI18n: attr('boolean'), diff --git a/ghost/admin/app/templates/components/gh-image-uploader.hbs b/ghost/admin/app/templates/components/gh-image-uploader.hbs index af8a63071e..ebfc9d95aa 100644 --- a/ghost/admin/app/templates/components/gh-image-uploader.hbs +++ b/ghost/admin/app/templates/components/gh-image-uploader.hbs @@ -19,10 +19,11 @@
{{description}}
{{/gh-file-input}} - - - - + {{#if allowUrlInput}} + + + + {{/if}} {{else}} {{!-- URL input --}}
diff --git a/ghost/admin/app/templates/components/modals/upload-image.hbs b/ghost/admin/app/templates/components/modals/upload-image.hbs index c322a0402f..1225a30ffa 100644 --- a/ghost/admin/app/templates/components/modals/upload-image.hbs +++ b/ghost/admin/app/templates/components/modals/upload-image.hbs @@ -12,6 +12,10 @@ saveButton=false update=(action 'fileUploaded') onInput=(action (mut newUrl)) + accept=model.accept + extensions=model.extensions + allowUrlInput=model.allowUrlInput + uploadUrl=model.uploadUrl }} {{/if}} @@ -19,4 +23,4 @@ \ No newline at end of file + diff --git a/ghost/admin/app/templates/settings/general.hbs b/ghost/admin/app/templates/settings/general.hbs index 1fd7541cc3..0f7847284b 100644 --- a/ghost/admin/app/templates/settings/general.hbs +++ b/ghost/admin/app/templates/settings/general.hbs @@ -39,12 +39,31 @@ {{#if showUploadLogoModal}} {{gh-fullscreen-modal "upload-image" - model=(hash model=model imageProperty="logo") + model=(hash model=model imageProperty="logo" allowUrlInput=true) close=(action "toggleUploadLogoModal") modifier="action wide"}} {{/if}} + {{#if config.fileStorage}} +
+ + {{#if model.icon}} + icon + {{else}} + + {{/if}} +

Upload a square blog icon ('.ico' or '.png', max. 100kb, 32px * 32px up to 1,000px * 1,000px) for your publication

+ + {{#if showUploadIconModal}} + {{gh-fullscreen-modal "upload-image" + model=(hash model=model imageProperty="icon" accept=iconMimeTypes extensions=iconExtensions allowUrlInput=false uploadUrl="/uploads/icon/") + close=(action "toggleUploadIconModal") + modifier="action wide"}} + {{/if}} +
+ {{/if}} +
{{#if model.cover}} @@ -56,7 +75,7 @@ {{#if showUploadCoverModal}} {{gh-fullscreen-modal "upload-image" - model=(hash model=model imageProperty="cover") + model=(hash model=model imageProperty="cover" allowUrlInput=true) close=(action "toggleUploadCoverModal") modifier="action wide"}} {{/if}} diff --git a/ghost/admin/app/templates/team/user.hbs b/ghost/admin/app/templates/team/user.hbs index 38e41bfdf1..a7639fa158 100644 --- a/ghost/admin/app/templates/team/user.hbs +++ b/ghost/admin/app/templates/team/user.hbs @@ -53,7 +53,7 @@ {{#if showUploadCoverModal}} {{gh-fullscreen-modal "upload-image" - model=(hash model=user imageProperty="cover") + model=(hash model=user imageProperty="cover" allowUrlInput=true) close=(action "toggleUploadCoverModal") modifier="action wide"}} {{/if}} @@ -72,7 +72,7 @@ {{#if showUploadImageModal}} {{gh-fullscreen-modal "upload-image" - model=(hash model=user imageProperty="image") + model=(hash model=user imageProperty="image" allowUrlInput=true) close=(action "toggleUploadImageModal") modifier="action wide"}} {{/if}} diff --git a/ghost/admin/mirage/fixtures/settings.js b/ghost/admin/mirage/fixtures/settings.js index 7ea0d3508a..fe3cfe49ae 100644 --- a/ghost/admin/mirage/fixtures/settings.js +++ b/ghost/admin/mirage/fixtures/settings.js @@ -227,5 +227,15 @@ export default [ updated_at: '2017-01-09T08:49:42.991Z', updated_by: 1, value: 'true' + }, + { + id: 22, + key: 'icon', + value: '/content/images/2014/Feb/favicon.ico', + type: 'blog', + created_at: '2013-11-25T14:48:11.000Z', + created_by: 1, + updated_at: '2015-10-27T17:39:58.276Z', + updated_by: 1 } ]; diff --git a/ghost/admin/tests/acceptance/settings/general-test.js b/ghost/admin/tests/acceptance/settings/general-test.js index 680a07558b..ba757f1435 100644 --- a/ghost/admin/tests/acceptance/settings/general-test.js +++ b/ghost/admin/tests/acceptance/settings/general-test.js @@ -16,11 +16,11 @@ import mockThemes from 'ghost-admin/mirage/config/themes'; describe('Acceptance: Settings - General', function () { let application; - beforeEach(function() { + beforeEach(function () { application = startApp(); }); - afterEach(function() { + afterEach(function () { destroyApp(application); }); @@ -28,7 +28,7 @@ describe('Acceptance: Settings - General', function () { invalidateSession(application); visit('/settings/general'); - andThen(function() { + andThen(function () { expect(currentURL(), 'currentURL').to.equal('/signin'); }); }); @@ -104,6 +104,27 @@ describe('Acceptance: Settings - General', function () { andThen(() => { expect(find('.fullscreen-modal .modal-content .gh-image-uploader .description').text()).to.equal('Upload an image'); + expect(find('.fullscreen-modal .modal-content .gh-image-uploader .image-url').length, 'url upload').to.equal(1); + }); + + // click cancel button + click('.fullscreen-modal .modal-footer .btn.btn-minor'); + + andThen(() => { + expect(find('.fullscreen-modal').length).to.equal(0); + }); + + click('.blog-icon'); + + andThen(() => { + expect(find('.fullscreen-modal .modal-content .gh-image-uploader').length, 'modal selector').to.equal(1); + }); + + click('.fullscreen-modal .modal-content .gh-image-uploader .image-cancel'); + + andThen(() => { + expect(find('.fullscreen-modal .modal-content .gh-image-uploader .description').text()).to.equal('Upload an image'); + expect(find('.fullscreen-modal .modal-content .gh-image-uploader .image-url').length, 'url upload').to.equal(0); }); // click cancel button