mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
Updated gh-uploader to work with new /images/upload/ endpoint
This commit is contained in:
parent
a0a0c50ff5
commit
72d9732958
6 changed files with 57 additions and 23 deletions
|
@ -3,7 +3,7 @@ import EmberObject from '@ember/object';
|
||||||
import ghostPaths from 'ghost-admin/utils/ghost-paths';
|
import ghostPaths from 'ghost-admin/utils/ghost-paths';
|
||||||
import {all, task} from 'ember-concurrency';
|
import {all, task} from 'ember-concurrency';
|
||||||
import {get} from '@ember/object';
|
import {get} from '@ember/object';
|
||||||
import {isArray as isEmberArray} from '@ember/array';
|
import {isArray} from '@ember/array';
|
||||||
import {isEmpty} from '@ember/utils';
|
import {isEmpty} from '@ember/utils';
|
||||||
import {run} from '@ember/runloop';
|
import {run} from '@ember/runloop';
|
||||||
import {inject as service} from '@ember/service';
|
import {inject as service} from '@ember/service';
|
||||||
|
@ -51,7 +51,9 @@ export default Component.extend({
|
||||||
accept: '',
|
accept: '',
|
||||||
extensions: '',
|
extensions: '',
|
||||||
files: null,
|
files: null,
|
||||||
paramName: 'uploadimage', // TODO: is this the best default?
|
paramName: 'file',
|
||||||
|
paramsHash: null,
|
||||||
|
resourceName: 'images',
|
||||||
uploadUrl: null,
|
uploadUrl: null,
|
||||||
|
|
||||||
// Interal attributes
|
// Interal attributes
|
||||||
|
@ -62,7 +64,7 @@ export default Component.extend({
|
||||||
uploadUrls: null, // [{filename: 'x', url: 'y'}],
|
uploadUrls: null, // [{filename: 'x', url: 'y'}],
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
_defaultUploadUrl: '/images/',
|
_defaultUploadUrl: '/images/upload/',
|
||||||
_files: null,
|
_files: null,
|
||||||
_uploadTrackers: null,
|
_uploadTrackers: null,
|
||||||
|
|
||||||
|
@ -83,6 +85,10 @@ export default Component.extend({
|
||||||
this.set('errors', []);
|
this.set('errors', []);
|
||||||
this.set('uploadUrls', []);
|
this.set('uploadUrls', []);
|
||||||
this._uploadTrackers = [];
|
this._uploadTrackers = [];
|
||||||
|
|
||||||
|
if (!this.paramsHash) {
|
||||||
|
this.set('paramsHash', {purpose: 'image'});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
|
@ -169,7 +175,7 @@ export default Component.extend({
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isEmberArray(extensions)) {
|
if (!isArray(extensions)) {
|
||||||
extensions = extensions.split(',');
|
extensions = extensions.split(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,10 +246,27 @@ export default Component.extend({
|
||||||
tracker.update({loaded: file.size, total: file.size});
|
tracker.update({loaded: file.size, total: file.size});
|
||||||
this._updateProgress();
|
this._updateProgress();
|
||||||
|
|
||||||
let uploadResponse = JSON.parse(response);
|
let uploadResponse;
|
||||||
|
let responseUrl;
|
||||||
|
|
||||||
|
try {
|
||||||
|
uploadResponse = JSON.parse(response);
|
||||||
|
} catch (e) {
|
||||||
|
if (!(e instanceof SyntaxError)) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uploadResponse) {
|
||||||
|
let resource = get(uploadResponse, this.resourceName);
|
||||||
|
if (resource && isArray(resource) && resource[0]) {
|
||||||
|
responseUrl = get(resource[0], 'url');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let result = {
|
let result = {
|
||||||
fileName: file.name,
|
url: responseUrl,
|
||||||
url: get(uploadResponse, 'url')
|
fileName: file.name
|
||||||
};
|
};
|
||||||
|
|
||||||
this.get('uploadUrls')[index] = result;
|
this.get('uploadUrls')[index] = result;
|
||||||
|
@ -274,6 +297,11 @@ export default Component.extend({
|
||||||
_getFormData(file) {
|
_getFormData(file) {
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
formData.append(this.get('paramName'), file, file.name);
|
formData.append(this.get('paramName'), file, file.name);
|
||||||
|
|
||||||
|
Object.keys(this.paramsHash || {}).forEach((key) => {
|
||||||
|
formData.append(key, this.paramsHash[key]);
|
||||||
|
});
|
||||||
|
|
||||||
return formData;
|
return formData;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,8 @@
|
||||||
<div class="gh-setting" data-test-setting="icon">
|
<div class="gh-setting" data-test-setting="icon">
|
||||||
{{#gh-uploader
|
{{#gh-uploader
|
||||||
extensions=iconExtensions
|
extensions=iconExtensions
|
||||||
uploadUrl="/images/icon/"
|
uploadUrl="/images/upload/"
|
||||||
|
paramsHash=(hash purpose="icon")
|
||||||
onComplete=(action "imageUploaded" "icon")
|
onComplete=(action "imageUploaded" "icon")
|
||||||
as |uploader|
|
as |uploader|
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -51,7 +51,7 @@ export function testConfig() {
|
||||||
// this.urlPrefix = ''; // make this `http://localhost:8080`, for example, if your API is on a different server
|
// this.urlPrefix = ''; // make this `http://localhost:8080`, for example, if your API is on a different server
|
||||||
this.namespace = '/ghost/api/v2/admin'; // make this `api`, for example, if your API is namespaced
|
this.namespace = '/ghost/api/v2/admin'; // make this `api`, for example, if your API is namespaced
|
||||||
// this.timing = 400; // delay for each request, automatically set to 0 during testing
|
// this.timing = 400; // delay for each request, automatically set to 0 during testing
|
||||||
this.logging = false;
|
this.logging = true;
|
||||||
|
|
||||||
mockApiKeys(this);
|
mockApiKeys(this);
|
||||||
mockAuthentication(this);
|
mockAuthentication(this);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
const fileUploadResponse = function (db, {requestBody}) {
|
const fileUploadResponse = function (db, {requestBody}) {
|
||||||
let [file] = requestBody.getAll('uploadimage');
|
// let [ref] = requestBody.getAll('ref');
|
||||||
|
let [purpose] = requestBody.getAll('purpose');
|
||||||
|
let [file] = requestBody.getAll('file');
|
||||||
let now = new Date();
|
let now = new Date();
|
||||||
let year = now.getFullYear();
|
let year = now.getFullYear();
|
||||||
let month = `${now.getMonth()}`;
|
let month = `${now.getMonth()}`;
|
||||||
|
@ -8,12 +10,15 @@ const fileUploadResponse = function (db, {requestBody}) {
|
||||||
month = `0${month}`;
|
month = `0${month}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (['image', 'profile_image', 'icon'].includes(purpose)) {
|
||||||
return {
|
return {
|
||||||
|
images: [{
|
||||||
url: `/content/images/${year}/${month}/${file.name}`
|
url: `/content/images/${year}/${month}/${file.name}`
|
||||||
|
}]
|
||||||
};
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function mockUploads(server) {
|
export default function mockUploads(server) {
|
||||||
server.post('/images/', fileUploadResponse, 200, {timing: 100});
|
server.post('/images/upload/', fileUploadResponse, 200, {timing: 100});
|
||||||
server.post('/images/icon/', fileUploadResponse, 200, {timing: 100});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,7 @@ describe('Acceptance: Settings - General', function () {
|
||||||
).to.not.exist;
|
).to.not.exist;
|
||||||
|
|
||||||
// failed upload shows error
|
// failed upload shows error
|
||||||
this.server.post('/images/icon/', function () {
|
this.server.post('/images/upload/', function () {
|
||||||
return {
|
return {
|
||||||
errors: [{
|
errors: [{
|
||||||
errorType: 'ValidationError',
|
errorType: 'ValidationError',
|
||||||
|
|
|
@ -9,13 +9,13 @@ import {run} from '@ember/runloop';
|
||||||
import {setupRenderingTest} from 'ember-mocha';
|
import {setupRenderingTest} from 'ember-mocha';
|
||||||
|
|
||||||
const stubSuccessfulUpload = function (server, delay = 0) {
|
const stubSuccessfulUpload = function (server, delay = 0) {
|
||||||
server.post('/ghost/api/v2/admin/images/', function () {
|
server.post('/ghost/api/v2/admin/images/upload/', function () {
|
||||||
return [200, {'Content-Type': 'application/json'}, '{"url": "/content/images/test.png"}'];
|
return [200, {'Content-Type': 'application/json'}, '{"images": [{"url": "/content/images/test.png"}]}'];
|
||||||
}, delay);
|
}, delay);
|
||||||
};
|
};
|
||||||
|
|
||||||
const stubFailedUpload = function (server, code, error, delay = 0) {
|
const stubFailedUpload = function (server, code, error, delay = 0) {
|
||||||
server.post('/ghost/api/v2/admin/images/', function () {
|
server.post('/ghost/api/v2/admin/images/upload/', function () {
|
||||||
return [code, {'Content-Type': 'application/json'}, JSON.stringify({
|
return [code, {'Content-Type': 'application/json'}, JSON.stringify({
|
||||||
errors: [{
|
errors: [{
|
||||||
errorType: error,
|
errorType: error,
|
||||||
|
@ -51,11 +51,11 @@ describe('Integration: Component: gh-uploader', function () {
|
||||||
|
|
||||||
let [lastRequest] = server.handledRequests;
|
let [lastRequest] = server.handledRequests;
|
||||||
expect(server.handledRequests.length).to.equal(1);
|
expect(server.handledRequests.length).to.equal(1);
|
||||||
expect(lastRequest.url).to.equal('/ghost/api/v2/admin/images/');
|
expect(lastRequest.url).to.equal('/ghost/api/v2/admin/images/upload/');
|
||||||
// requestBody is a FormData object
|
// requestBody is a FormData object
|
||||||
// this will fail in anything other than Chrome and Firefox
|
// this will fail in anything other than Chrome and Firefox
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/FormData#Browser_compatibility
|
// https://developer.mozilla.org/en-US/docs/Web/API/FormData#Browser_compatibility
|
||||||
expect(lastRequest.requestBody.has('uploadimage')).to.be.true;
|
expect(lastRequest.requestBody.has('file')).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('triggers multiple uploads', async function () {
|
it('triggers multiple uploads', async function () {
|
||||||
|
@ -136,7 +136,7 @@ describe('Integration: Component: gh-uploader', function () {
|
||||||
|
|
||||||
it('onComplete returns results in same order as selected', async function () {
|
it('onComplete returns results in same order as selected', async function () {
|
||||||
// first request has a delay to simulate larger file
|
// first request has a delay to simulate larger file
|
||||||
server.post('/ghost/api/v2/admin/images/', function () {
|
server.post('/ghost/api/v2/admin/images/upload/', function () {
|
||||||
// second request has no delay to simulate small file
|
// second request has no delay to simulate small file
|
||||||
stubSuccessfulUpload(server, 0);
|
stubSuccessfulUpload(server, 0);
|
||||||
|
|
||||||
|
@ -266,7 +266,7 @@ describe('Integration: Component: gh-uploader', function () {
|
||||||
|
|
||||||
it('uploads to supplied `uploadUrl`', async function () {
|
it('uploads to supplied `uploadUrl`', async function () {
|
||||||
server.post('/ghost/api/v2/admin/images/', function () {
|
server.post('/ghost/api/v2/admin/images/', function () {
|
||||||
return [200, {'Content-Type': 'application/json'}, '"/content/images/test.png"'];
|
return [200, {'Content-Type': 'application/json'}, '{"images": [{"url": "/content/images/test.png"}]'];
|
||||||
});
|
});
|
||||||
|
|
||||||
await render(hbs`{{#gh-uploader files=files uploadUrl="/images/"}}{{/gh-uploader}}`);
|
await render(hbs`{{#gh-uploader files=files uploadUrl="/images/"}}{{/gh-uploader}}`);
|
||||||
|
|
Loading…
Add table
Reference in a new issue