Skip to content

Commit

Permalink
Added oembed controller to v2 api (#10057)
Browse files Browse the repository at this point in the history
refs #9866

- Added oembed controller to v2 API
  • Loading branch information
rishabhgrg authored and naz committed Nov 2, 2018
1 parent 31c35e1 commit 94b3735
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 1 deletion.
4 changes: 4 additions & 0 deletions core/server/api/v2/index.js
Expand Up @@ -69,5 +69,9 @@ module.exports = {

get preview() {
return shared.pipeline(require('./preview'), localUtils);
},

get oembed() {
return shared.pipeline(require('./oembed'), localUtils);
}
};
102 changes: 102 additions & 0 deletions core/server/api/v2/oembed.js
@@ -0,0 +1,102 @@
const common = require('../../lib/common');
const {extract, hasProvider} = require('oembed-parser');
const Promise = require('bluebird');
const request = require('../../lib/request');
const cheerio = require('cheerio');

const findUrlWithProvider = (url) => {
let provider;

// build up a list of URL variations to test against because the oembed
// providers list is not always up to date with scheme or www vs non-www
let baseUrl = url.replace(/^\/\/|^https?:\/\/(?:www\.)?/, '');
let testUrls = [
`http://${baseUrl}`,
`https://${baseUrl}`,
`http://www.${baseUrl}`,
`https://www.${baseUrl}`
];

for (let testUrl of testUrls) {
provider = hasProvider(testUrl);
if (provider) {
url = testUrl;
break;
}
}

return {url, provider};
};

const getOembedUrlFromHTML = (html) => {
return cheerio('link[type="application/json+oembed"]', html).attr('href');
};

module.exports = {
docName: 'oembed',

read: {
permissions: false,
data: [
'url'
],
options: [],
query({data}) {
let {url} = data;

if (!url || !url.trim()) {
return Promise.reject(new common.errors.BadRequestError({
message: common.i18n.t('errors.api.oembed.noUrlProvided')
}));
}

function unknownProvider() {
return Promise.reject(new common.errors.ValidationError({
message: common.i18n.t('errors.api.oembed.unknownProvider')
}));
}

function knownProvider(url) {
return extract(url).catch((err) => {
return Promise.reject(new common.errors.InternalServerError({
message: err.message
}));
});
}

let provider;
({url, provider} = findUrlWithProvider(url));

if (provider) {
return knownProvider(url);
}

// see if the URL is a redirect to cater for shortened urls
return request(url, {
method: 'GET',
timeout: 2 * 1000,
followRedirect: true
}).then((response) => {
if (response.url !== url) {
({url, provider} = findUrlWithProvider(response.url));
return provider ? knownProvider(url) : unknownProvider();
}

const oembedUrl = getOembedUrlFromHTML(response.body);

if (!oembedUrl) {
return unknownProvider();
}

return request(oembedUrl, {
method: 'GET',
json: true
}).then((response) => {
return response.body;
});
}).catch(() => {
return unknownProvider();
});
}
}
};
4 changes: 4 additions & 0 deletions core/server/api/v2/utils/serializers/output/index.js
Expand Up @@ -57,5 +57,9 @@ module.exports = {

get preview() {
return require('./preview');
},

get oembed() {
return require('./oembed');
}
};
9 changes: 9 additions & 0 deletions core/server/api/v2/utils/serializers/output/oembed.js
@@ -0,0 +1,9 @@
const debug = require('ghost-ignition').debug('api:v2:utils:serializers:output:oembed');

module.exports = {
all(res, apiConfig, frame) {
debug('all');
frame.response = res;
debug(frame.response);
}
};
2 changes: 1 addition & 1 deletion core/server/web/api/v2/admin/routes.js
Expand Up @@ -226,7 +226,7 @@ module.exports = function apiRoutes() {
router.del('/webhooks/:id', mw.authAdminAPI, apiv2.http(apiv2.webhooks.destroy));

// ## Oembed (fetch response from oembed provider)
router.get('/oembed', mw.authAdminAPI, api.http(api.oembed.read));
router.get('/oembed', mw.authAdminAPI, apiv2.http(apiv2.oembed.read));

return router;
};
61 changes: 61 additions & 0 deletions core/test/functional/api/v2/admin/oembed_spec.js
@@ -0,0 +1,61 @@
const nock = require('nock');
const should = require('should');
const supertest = require('supertest');
const testUtils = require('../../../../utils');
const config = require('../../../../../../core/server/config');
const localUtils = require('./utils');

const ghost = testUtils.startGhost;

describe('Oembed API', function () {
let ghostServer, request;

before(function () {
return ghost()
.then((_ghostServer) => {
ghostServer = _ghostServer;
request = supertest.agent(config.get('url'));
})
.then(() => {
return localUtils.doAuth(request);
});
});

describe('success', function () {
it('can fetch an embed', function (done) {
let requestMock = nock('https://www.youtube.com')
.get('/oembed')
.query(true)
.reply(200, {
html: '<iframe width="480" height="270" src="https://www.youtube.com/embed/E5yFcdPAGv0?feature=oembed" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>',
thumbnail_width: 480,
width: 480,
author_url: 'https://www.youtube.com/user/gorillaz',
height: 270,
thumbnail_height: 360,
provider_name: 'YouTube',
title: 'Gorillaz - Humility (Official Video)',
provider_url: 'https://www.youtube.com/',
author_name: 'Gorillaz',
version: '1.0',
thumbnail_url: 'https://i.ytimg.com/vi/E5yFcdPAGv0/hqdefault.jpg',
type: 'video'
});

request.get(localUtils.API.getApiQuery('oembed/?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DE5yFcdPAGv0'))
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
return done(err);
}

requestMock.isDone().should.be.true();
should.exist(res.body.html);
done();
});
});
});
});

0 comments on commit 94b3735

Please sign in to comment.