0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-24 23:48:13 -05:00

Blog icon uplod (#397)

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.
This commit is contained in:
Aileen Nowak 2017-01-26 18:17:34 +07:00 committed by Kevin Ansfield
parent c16d633d4b
commit 66f7bad47b
9 changed files with 105 additions and 16 deletions

View file

@ -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();

View file

@ -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');

View file

@ -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'),

View file

@ -19,10 +19,11 @@
<div class="description">{{description}}</div>
{{/gh-file-input}}
</div>
<a class="image-url" {{action "switchForm" "url-input"}}>
<i class="icon-link"><span class="hidden">URL</span></i>
</a>
{{#if allowUrlInput}}
<a class="image-url" {{action "switchForm" "url-input"}}>
<i class="icon-link"><span class="hidden">URL</span></i>
</a>
{{/if}}
{{else}}
{{!-- URL input --}}
<form class="url-form">

View file

@ -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}}
</div>
@ -19,4 +23,4 @@
<div class="modal-footer">
<button {{action "closeModal"}} class="btn btn-default btn-minor">Cancel</button>
{{#gh-task-button task=uploadImage class="btn btn-blue right js-button-accept"}}Save{{/gh-task-button}}
</div>
</div>

View file

@ -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}}
</div>
{{#if config.fileStorage}}
<div class="form-group">
<label>Blog Icon</label>
{{#if model.icon}}
<img class="blog-icon" src="{{model.icon}}" alt="icon" role="button" {{action "toggleUploadIconModal"}}>
{{else}}
<button type="button" class="btn btn-green js-modal-logo" {{action "toggleUploadIconModal"}}>Upload Image</button>
{{/if}}
<p>Upload a square blog icon ('.ico' or '.png', max. 100kb, 32px * 32px up to 1,000px * 1,000px) for your publication</p>
{{#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}}
</div>
{{/if}}
<div class="form-group">
<label>Blog Cover</label>
{{#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}}

View file

@ -53,7 +53,7 @@
<button class="btn btn-default user-cover-edit" {{action "toggleUploadCoverModal"}}>Change Cover</button>
{{#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 @@
<button type="button" {{action "toggleUploadImageModal"}} class="edit-user-image">Edit Picture</button>
{{#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}}

View file

@ -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
}
];

View file

@ -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