mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-30 21:40:39 +03:00
837 lines
36 KiB
JavaScript
837 lines
36 KiB
JavaScript
const assert = require('assert/strict');
|
||
const fs = require('fs');
|
||
const sinon = require('sinon');
|
||
const nock = require('nock');
|
||
const path = require('path');
|
||
const loggingLib = require('@tryghost/logging');
|
||
const ExternalMediaInliner = require('../index');
|
||
|
||
describe('ExternalMediaInliner', function () {
|
||
let logging;
|
||
let ghostLogoPng;
|
||
let exeFile;
|
||
let GIF1x1;
|
||
let postModelStub;
|
||
let postMetaModelStub;
|
||
let tagModelStub;
|
||
let userModelStub;
|
||
|
||
beforeEach(function () {
|
||
// use a 1x1 gif in nock responses because it's really small and easy to work with
|
||
ghostLogoPng = fs.readFileSync(path.join(__dirname, 'fixtures', 'ghost-logo.png'));
|
||
exeFile = fs.readFileSync(path.join(__dirname, 'fixtures', 'fixture.exe'));
|
||
GIF1x1 = Buffer.from('R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==', 'base64');
|
||
logging = {
|
||
info: sinon.stub(loggingLib, 'info'),
|
||
error: sinon.stub(loggingLib, 'error'),
|
||
warn: sinon.stub(loggingLib, 'warn')
|
||
};
|
||
|
||
postModelStub = {
|
||
findPage: sinon.stub().resolves({
|
||
data: []
|
||
}),
|
||
edit: sinon.stub().resolves()
|
||
};
|
||
postMetaModelStub = {
|
||
findPage: sinon.stub().resolves({
|
||
data: []
|
||
}),
|
||
edit: sinon.stub().resolves()
|
||
};
|
||
tagModelStub = {
|
||
findPage: sinon.stub().resolves({
|
||
data: []
|
||
}),
|
||
edit: sinon.stub().resolves()
|
||
};
|
||
userModelStub = {
|
||
findPage: sinon.stub().resolves({
|
||
data: []
|
||
}),
|
||
edit: sinon.stub().resolves()
|
||
};
|
||
});
|
||
|
||
afterEach(function () {
|
||
sinon.restore();
|
||
nock.cleanAll();
|
||
});
|
||
|
||
it('Creates an External Media Inliner instance', function () {
|
||
assert.ok(new ExternalMediaInliner({}));
|
||
});
|
||
|
||
describe('inline', function () {
|
||
it('inlines image in the post\'s mobiledoc content', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/image.jpg';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/image.jpg')
|
||
.reply(200, GIF1x1);
|
||
|
||
const postStub = sinon.stub();
|
||
postStub.withArgs('mobiledoc').returns(`{"version":"0.3.1","atoms":[],"cards":[["image",{"src":"${imageURL}"}]]}`);
|
||
postStub.withArgs('lexical').returns(null);
|
||
|
||
const postModelInstanceStub = {
|
||
id: 'inlined-post-id',
|
||
get: postStub
|
||
};
|
||
postModelStub = {
|
||
findPage: sinon.stub().returns({
|
||
data: [postModelInstanceStub]
|
||
}),
|
||
edit: sinon.stub().resolves()
|
||
};
|
||
|
||
sinon.stub(path, 'relative')
|
||
.withArgs('/content/images', '/content/images/unique-image.jpg')
|
||
.returns('unique-image.jpg');
|
||
const inliner = new ExternalMediaInliner({
|
||
PostModel: postModelStub,
|
||
PostMetaModel: postMetaModelStub,
|
||
TagModel: tagModelStub,
|
||
UserModel: userModelStub,
|
||
getMediaStorage: sinon.stub().withArgs('.jpg').returns({
|
||
getTargetDir: () => '/content/images',
|
||
getUniqueFileName: () => '/content/images/unique-image.jpg',
|
||
saveRaw: () => '/content/images/unique-image.jpg'
|
||
})
|
||
});
|
||
|
||
await inliner.inline(['https://img.stockfresh.com']);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.ok(postModelStub.edit.calledOnce);
|
||
assert.ok(postModelStub.edit.calledWith({
|
||
mobiledoc: '{"version":"0.3.1","atoms":[],"cards":[["image",{"src":"__GHOST_URL__/content/images/unique-image.jpg"}]]}'
|
||
}, {
|
||
id: 'inlined-post-id',
|
||
context: {
|
||
internal: true
|
||
}
|
||
}));
|
||
});
|
||
|
||
it('inlines the image from post\'s mobiledoc containing html card', async function () {
|
||
const imageURL = 'https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/39719fcb-5af0-4764-bf8b-d375f37a09e5_1141x860';
|
||
const requestMock = nock('https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com')
|
||
.get('/public/images/39719fcb-5af0-4764-bf8b-d375f37a09e5_1141x860')
|
||
.reply(200, GIF1x1);
|
||
|
||
const postStub = sinon.stub();
|
||
postStub.withArgs('mobiledoc').returns(`{"version":"0.3.1","atoms":[],"cards":[["html",{"html":"<img src="${imageURL}" alt="Lorem ipsum">"}]],"markups":[],"sections":[[10,0],[1,"p",[]]],"ghostVersion":"4.0"}`);
|
||
postStub.withArgs('lexical').returns(null);
|
||
|
||
const postModelInstanceStub = {
|
||
id: 'inlined-post-with-htmlcard-id',
|
||
get: postStub
|
||
};
|
||
|
||
postModelStub = {
|
||
findPage: sinon.stub().returns({
|
||
data: [postModelInstanceStub]
|
||
}),
|
||
edit: sinon.stub().resolves()
|
||
};
|
||
|
||
sinon.stub(path, 'relative')
|
||
.withArgs('/content/images', '/content/images/unique-image.jpg')
|
||
.returns('unique-image.jpg');
|
||
const inliner = new ExternalMediaInliner({
|
||
PostModel: postModelStub,
|
||
PostMetaModel: postMetaModelStub,
|
||
TagModel: tagModelStub,
|
||
UserModel: userModelStub,
|
||
getMediaStorage: sinon.stub().withArgs('.jpg').returns({
|
||
getTargetDir: () => '/content/images',
|
||
getUniqueFileName: () => '/content/images/unique-image.jpg',
|
||
saveRaw: () => '/content/images/unique-image.jpg'
|
||
})
|
||
});
|
||
|
||
await inliner.inline(['https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com']);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.ok(postModelStub.edit.calledOnce);
|
||
assert.deepEqual(postModelStub.edit.args[0][0], {
|
||
mobiledoc: `{"version":"0.3.1","atoms":[],"cards":[["html",{"html":"<img src="__GHOST_URL__/content/images/unique-image.jpg" alt="Lorem ipsum">"}]],"markups":[],"sections":[[10,0],[1,"p",[]]],"ghostVersion":"4.0"}`
|
||
});
|
||
assert.deepEqual(postModelStub.edit.args[0][1], {
|
||
id: 'inlined-post-with-htmlcard-id',
|
||
context: {
|
||
internal: true
|
||
}
|
||
});
|
||
});
|
||
|
||
it('inlines image in the post\'s lexical content', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/image.jpg';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/image.jpg')
|
||
.reply(200, GIF1x1);
|
||
|
||
const postStub = sinon.stub();
|
||
postStub.withArgs('mobiledoc').returns(null);
|
||
postStub.withArgs('lexical').returns(`{"root":{"children":[{"type":"image","version":1,"src":"${imageURL}","width":1480,"height":486,"title":"","alt":"","caption":"","cardWidth":"regular","href":""}],"direction":null,"format":"","indent":0,"type":"root","version":1}}`);
|
||
|
||
const postModelInstanceStub = {
|
||
id: 'inlined-post-id',
|
||
get: postStub
|
||
};
|
||
postModelStub = {
|
||
findPage: sinon.stub().returns({
|
||
data: [postModelInstanceStub]
|
||
}),
|
||
edit: sinon.stub().resolves()
|
||
};
|
||
|
||
sinon.stub(path, 'relative')
|
||
.withArgs('/content/images', '/content/images/unique-image.jpg')
|
||
.returns('unique-image.jpg');
|
||
const inliner = new ExternalMediaInliner({
|
||
PostModel: postModelStub,
|
||
PostMetaModel: postMetaModelStub,
|
||
TagModel: tagModelStub,
|
||
UserModel: userModelStub,
|
||
getMediaStorage: sinon.stub().withArgs('.jpg').returns({
|
||
getTargetDir: () => '/content/images',
|
||
getUniqueFileName: () => '/content/images/unique-image.jpg',
|
||
saveRaw: () => '/content/images/unique-image.jpg'
|
||
})
|
||
});
|
||
|
||
await inliner.inline(['https://img.stockfresh.com']);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.ok(postModelStub.edit.calledOnce);
|
||
assert.ok(postModelStub.edit.calledWith({
|
||
lexical: '{"root":{"children":[{"type":"image","version":1,"src":"__GHOST_URL__/content/images/unique-image.jpg","width":1480,"height":486,"title":"","alt":"","caption":"","cardWidth":"regular","href":""}],"direction":null,"format":"","indent":0,"type":"root","version":1}}'
|
||
}, {
|
||
id: 'inlined-post-id',
|
||
context: {
|
||
internal: true
|
||
}
|
||
}));
|
||
});
|
||
|
||
it('inlines the image from post\'s lexical containing html card', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/image.jpg';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/image.jpg')
|
||
.reply(200, GIF1x1);
|
||
|
||
const postStub = sinon.stub();
|
||
postStub.withArgs('mobiledoc').returns(null);
|
||
postStub.withArgs('lexical').returns(`{"root":{"children":[{"type":"html","version":1,"html":"<img src="${imageURL}" alt="Lorem ipsum">"}],"direction":null,"format":"","indent":0,"type":"root","version":1}}`);
|
||
|
||
const postModelInstanceStub = {
|
||
id: 'inlined-post-with-htmlcard-id',
|
||
get: postStub
|
||
};
|
||
|
||
postModelStub = {
|
||
findPage: sinon.stub().returns({
|
||
data: [postModelInstanceStub]
|
||
}),
|
||
edit: sinon.stub().resolves()
|
||
};
|
||
|
||
sinon.stub(path, 'relative')
|
||
.withArgs('/content/images', '/content/images/unique-image.jpg')
|
||
.returns('unique-image.jpg');
|
||
const inliner = new ExternalMediaInliner({
|
||
PostModel: postModelStub,
|
||
PostMetaModel: postMetaModelStub,
|
||
TagModel: tagModelStub,
|
||
UserModel: userModelStub,
|
||
getMediaStorage: sinon.stub().withArgs('.jpg').returns({
|
||
getTargetDir: () => '/content/images',
|
||
getUniqueFileName: () => '/content/images/unique-image.jpg',
|
||
saveRaw: () => '/content/images/unique-image.jpg'
|
||
})
|
||
});
|
||
|
||
await inliner.inline(['https://img.stockfresh.com']);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.ok(postModelStub.edit.calledOnce);
|
||
assert.deepEqual(postModelStub.edit.args[0][0], {
|
||
lexical: `{"root":{"children":[{"type":"html","version":1,"html":"<img src="__GHOST_URL__/content/images/unique-image.jpg" alt="Lorem ipsum">"}],"direction":null,"format":"","indent":0,"type":"root","version":1}}`
|
||
});
|
||
assert.deepEqual(postModelStub.edit.args[0][1], {
|
||
id: 'inlined-post-with-htmlcard-id',
|
||
context: {
|
||
internal: true
|
||
}
|
||
});
|
||
});
|
||
|
||
it('inlines image in the post\'s mobiledoc & lexical content', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/image.jpg';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/image.jpg')
|
||
.reply(200, GIF1x1)
|
||
.get('/files/f/image.jpg')
|
||
.reply(200, GIF1x1);
|
||
|
||
const postStub = sinon.stub();
|
||
postStub.withArgs('mobiledoc').returns(`{"version":"0.3.1","atoms":[],"cards":[["image",{"src":"${imageURL}"}]]}`);
|
||
postStub.withArgs('lexical').returns(`{"root":{"children":[{"type":"image","version":1,"src":"${imageURL}","width":1480,"height":486,"title":"","alt":"","caption":"","cardWidth":"regular","href":""}],"direction":null,"format":"","indent":0,"type":"root","version":1}}`);
|
||
|
||
const postModelInstanceStub = {
|
||
id: 'inlined-post-id',
|
||
get: postStub
|
||
};
|
||
postModelStub = {
|
||
findPage: sinon.stub().returns({
|
||
data: [postModelInstanceStub]
|
||
}),
|
||
edit: sinon.stub().resolves()
|
||
};
|
||
|
||
sinon.stub(path, 'relative')
|
||
.withArgs('/content/images', '/content/images/unique-image.jpg')
|
||
.returns('unique-image.jpg');
|
||
const inliner = new ExternalMediaInliner({
|
||
PostModel: postModelStub,
|
||
PostMetaModel: postMetaModelStub,
|
||
TagModel: tagModelStub,
|
||
UserModel: userModelStub,
|
||
getMediaStorage: sinon.stub().withArgs('.jpg').returns({
|
||
getTargetDir: () => '/content/images',
|
||
getUniqueFileName: () => '/content/images/unique-image.jpg',
|
||
saveRaw: () => '/content/images/unique-image.jpg'
|
||
})
|
||
});
|
||
|
||
await inliner.inline(['https://img.stockfresh.com']);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.ok(postModelStub.edit.calledOnce);
|
||
assert.ok(postModelStub.edit.calledWith({
|
||
mobiledoc: '{"version":"0.3.1","atoms":[],"cards":[["image",{"src":"__GHOST_URL__/content/images/unique-image.jpg"}]]}',
|
||
lexical: '{"root":{"children":[{"type":"image","version":1,"src":"__GHOST_URL__/content/images/unique-image.jpg","width":1480,"height":486,"title":"","alt":"","caption":"","cardWidth":"regular","href":""}],"direction":null,"format":"","indent":0,"type":"root","version":1}}'
|
||
}, {
|
||
id: 'inlined-post-id',
|
||
context: {
|
||
internal: true
|
||
}
|
||
}));
|
||
});
|
||
|
||
it('logs an error when fetching an external media fails', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/image.jpg';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/image.jpg')
|
||
.reply(404);
|
||
const postModelInstanceStub = {
|
||
id: 'inlined-post-id',
|
||
get: sinon.stub()
|
||
.withArgs('mobiledoc')
|
||
.returns(`{"version":"0.3.1","atoms":[],"cards":[["image",{"src":"${imageURL}"}]]}`)
|
||
};
|
||
|
||
postModelStub = {
|
||
findPage: sinon.stub().returns({
|
||
data: [postModelInstanceStub]
|
||
})
|
||
};
|
||
|
||
const inliner = new ExternalMediaInliner({
|
||
PostModel: postModelStub,
|
||
PostMetaModel: postMetaModelStub,
|
||
TagModel: tagModelStub,
|
||
UserModel: userModelStub
|
||
});
|
||
|
||
await inliner.inline(['https://img.stockfresh.com']);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.equal(logging.error.args[0][0], 'Error downloading remote media: https://img.stockfresh.com/files/f/image.jpg');
|
||
});
|
||
|
||
it('logs an error when fetching an external media for simple fields fails', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/simple-image.jpg';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/simple-image.jpg')
|
||
.reply(500);
|
||
const userModelInstanceStub = {
|
||
id: 'inlined-user-id',
|
||
get: sinon.stub()
|
||
.withArgs('profile_image')
|
||
.returns(imageURL)
|
||
};
|
||
|
||
userModelStub = {
|
||
findPage: sinon.stub().returns({
|
||
data: [userModelInstanceStub]
|
||
})
|
||
};
|
||
|
||
const inliner = new ExternalMediaInliner({
|
||
PostModel: postModelStub,
|
||
PostMetaModel: postMetaModelStub,
|
||
TagModel: tagModelStub,
|
||
UserModel: userModelStub
|
||
});
|
||
|
||
await inliner.inline(['https://img.stockfresh.com']);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.equal(logging.error.args[0][0], 'Error downloading remote media: https://img.stockfresh.com/files/f/simple-image.jpg');
|
||
});
|
||
|
||
it('logs a warning when no suitable storage adapter found for inlined media extension', async function () {
|
||
const fileURL = 'https://img.stockfresh.com/files/f/inlined.exe';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/inlined.exe')
|
||
.reply(200, exeFile);
|
||
|
||
const postModelInstanceStub = {
|
||
id: 'inlined-post-id',
|
||
get: sinon.stub()
|
||
.withArgs('mobiledoc')
|
||
.returns(`{"version":"0.3.1","atoms":[],"cards":[["image",{"src":"${fileURL}"}]]}`)
|
||
};
|
||
postModelStub = {
|
||
findPage: sinon.stub().returns({
|
||
data: [postModelInstanceStub]
|
||
}),
|
||
edit: sinon.stub().resolves()
|
||
};
|
||
const inliner = new ExternalMediaInliner({
|
||
PostModel: postModelStub,
|
||
PostMetaModel: postMetaModelStub,
|
||
TagModel: tagModelStub,
|
||
UserModel: userModelStub,
|
||
getMediaStorage: sinon.stub().withArgs('.exe').returns(null)
|
||
});
|
||
|
||
await inliner.inline(['https://img.stockfresh.com']);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.ok(logging.warn.calledOnce);
|
||
assert.equal(logging.warn.args[0][0], 'No storage adapter found for file extension: .exe');
|
||
});
|
||
|
||
it('logs an error when handling post inlining throws an error', async function (){
|
||
const imageURL = 'https://img.stockfresh.com/files/f/image.jpg';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/image.jpg')
|
||
.reply(200, GIF1x1);
|
||
|
||
const postStub = sinon.stub();
|
||
postStub.withArgs('mobiledoc').returns(`{"version":"0.3.1","atoms":[],"cards":[["image",{"src":"${imageURL}"}]]}`);
|
||
postStub.withArgs('lexical').returns(null);
|
||
|
||
postModelStub = {
|
||
id: 'errored-post-id',
|
||
get: postStub
|
||
};
|
||
postModelStub = {
|
||
findPage: sinon.stub().returns({
|
||
data: [postModelStub]
|
||
}),
|
||
edit: sinon.stub().throws(new Error('Error saving the post'))
|
||
};
|
||
sinon.stub(path, 'relative')
|
||
.withArgs('/content/images', '/content/images/unique-image.jpg')
|
||
.returns('unique-image.jpg');
|
||
|
||
const inliner = new ExternalMediaInliner({
|
||
PostModel: postModelStub,
|
||
PostMetaModel: postMetaModelStub,
|
||
TagModel: tagModelStub,
|
||
UserModel: userModelStub,
|
||
getMediaStorage: sinon.stub().withArgs('.jpg').returns({
|
||
getTargetDir: () => '/content/images',
|
||
getUniqueFileName: () => '/content/images/unique-image.jpg',
|
||
saveRaw: () => '/content/images/unique-image.jpg'
|
||
})
|
||
});
|
||
|
||
await inliner.inline(['https://img.stockfresh.com']);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.ok(postModelStub.edit.calledOnce);
|
||
assert.equal(logging.error.args[0][0], 'Error inlining media for post: errored-post-id');
|
||
});
|
||
|
||
it('logs an error when handling tag simple fields inlining throws an error', async function (){
|
||
const imageURL = 'https://img.stockfresh.com/files/f/simple-image.jpg';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/simple-image.jpg')
|
||
.reply(200, GIF1x1);
|
||
|
||
const getMethodStub = sinon.stub();
|
||
getMethodStub.withArgs('feature_image').returns(imageURL);
|
||
getMethodStub.withArgs('og_image').returns(null);
|
||
getMethodStub.withArgs('twitter_image').returns(null);
|
||
|
||
const tagModelInstanceStub = {
|
||
id: 'errored-tag-id',
|
||
get: getMethodStub
|
||
};
|
||
tagModelStub.findPage = sinon.stub().returns({
|
||
data: [tagModelInstanceStub]
|
||
});
|
||
tagModelStub.edit = sinon.stub().throws(new Error('Error saving the tag'));
|
||
sinon.stub(path, 'relative')
|
||
.withArgs('/content/images', '/content/images/unique-image.jpg')
|
||
.returns('unique-image.jpg');
|
||
|
||
const inliner = new ExternalMediaInliner({
|
||
PostModel: postModelStub,
|
||
PostMetaModel: postMetaModelStub,
|
||
TagModel: tagModelStub,
|
||
UserModel: userModelStub,
|
||
getMediaStorage: sinon.stub().withArgs('.jpg').returns({
|
||
getTargetDir: () => '/content/images',
|
||
getUniqueFileName: () => '/content/images/unique-image.jpg',
|
||
saveRaw: () => '/content/images/unique-image.jpg'
|
||
})
|
||
});
|
||
|
||
await inliner.inline(['https://img.stockfresh.com']);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.ok(tagModelStub.edit.calledOnce);
|
||
assert.equal(logging.error.args[0][0], 'Error inlining media for: errored-tag-id');
|
||
});
|
||
|
||
it('inlines image in the post\'s feature_image field', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/posts_feature_image.jpg';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/posts_feature_image.jpg')
|
||
.reply(200, GIF1x1);
|
||
|
||
postModelStub = {
|
||
id: 'inlined-post-id',
|
||
get: sinon.stub()
|
||
.withArgs('feature_image')
|
||
.returns(imageURL)
|
||
};
|
||
const postModelMock = {
|
||
findPage: sinon.stub().returns({
|
||
data: [postModelStub]
|
||
}),
|
||
edit: sinon.stub().resolves()
|
||
};
|
||
sinon.stub(path, 'relative')
|
||
.withArgs('/content/images', '/content/images/unique-feature-image.jpg')
|
||
.returns('unique-feature-image.jpg');
|
||
|
||
const inliner = new ExternalMediaInliner({
|
||
PostModel: postModelMock,
|
||
PostMetaModel: postMetaModelStub,
|
||
TagModel: tagModelStub,
|
||
UserModel: userModelStub,
|
||
getMediaStorage: sinon.stub().withArgs('.jpg').returns({
|
||
getTargetDir: () => '/content/images',
|
||
getUniqueFileName: () => '/content/images/unique-feature-image.jpg',
|
||
saveRaw: () => '/content/images/unique-feature-image.jpg'
|
||
})
|
||
});
|
||
|
||
await inliner.inline(['https://img.stockfresh.com']);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.ok(postModelMock.edit.calledOnce);
|
||
assert.ok(postModelMock.edit.calledWith({
|
||
feature_image: '__GHOST_URL__/content/images/unique-feature-image.jpg'
|
||
}, {
|
||
id: 'inlined-post-id',
|
||
context: {
|
||
internal: true
|
||
}
|
||
}));
|
||
});
|
||
|
||
it('inlines og_image image in posts_meta table', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/posts_meta_image.jpg';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/posts_meta_image.jpg')
|
||
.reply(200, GIF1x1);
|
||
|
||
const getMethodStub = sinon.stub();
|
||
getMethodStub.withArgs('og_image').returns(imageURL);
|
||
getMethodStub.withArgs('twitter_image').returns(null);
|
||
const postsMetaModelInstanceStub = {
|
||
id: 'inlined-post-meta-id',
|
||
get: getMethodStub
|
||
};
|
||
|
||
postMetaModelStub.findPage = sinon.stub().resolves({
|
||
data: [postsMetaModelInstanceStub]
|
||
});
|
||
sinon.stub(path, 'relative')
|
||
.withArgs('/content/images', '/content/images/unique-feature-image.jpg')
|
||
.returns('unique-feature-image.jpg');
|
||
|
||
const inliner = new ExternalMediaInliner({
|
||
PostModel: postModelStub,
|
||
PostMetaModel: postMetaModelStub,
|
||
TagModel: tagModelStub,
|
||
UserModel: userModelStub,
|
||
getMediaStorage: sinon.stub().withArgs('.jpg').returns({
|
||
getTargetDir: () => '/content/images',
|
||
getUniqueFileName: () => '/content/images/unique-posts-meta-image.jpg',
|
||
saveRaw: () => '/content/images/unique-posts-meta-image.jpg'
|
||
})
|
||
});
|
||
|
||
await inliner.inline(['https://img.stockfresh.com']);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.ok(postMetaModelStub.edit.calledOnce);
|
||
assert.deepEqual(postMetaModelStub.edit.args[0][0], {
|
||
og_image: '__GHOST_URL__/content/images/unique-posts-meta-image.jpg'
|
||
});
|
||
assert.deepEqual(postMetaModelStub.edit.args[0][1], {
|
||
id: 'inlined-post-meta-id',
|
||
context: {
|
||
internal: true
|
||
}
|
||
});
|
||
});
|
||
|
||
it('inlines twitter_image image in tags table', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/tag_twitter_image.jpg';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/tag_twitter_image.jpg')
|
||
.reply(200, GIF1x1);
|
||
|
||
const getMethodStub = sinon.stub();
|
||
getMethodStub.withArgs('twitter_image').returns(imageURL);
|
||
getMethodStub.returns(null);
|
||
const tagModelInstanceStub = {
|
||
id: 'inlined-tag-id',
|
||
get: getMethodStub
|
||
};
|
||
|
||
tagModelStub.findPage = sinon.stub().resolves({
|
||
data: [tagModelInstanceStub]
|
||
});
|
||
sinon.stub(path, 'relative')
|
||
.withArgs('/content/images', '/content/images/unique-tag-twitter-image.jpg')
|
||
.returns('unique-tag-twitter-image.jpg');
|
||
|
||
const inliner = new ExternalMediaInliner({
|
||
PostModel: postModelStub,
|
||
PostMetaModel: postMetaModelStub,
|
||
TagModel: tagModelStub,
|
||
UserModel: userModelStub,
|
||
getMediaStorage: sinon.stub().withArgs('.jpg').returns({
|
||
getTargetDir: () => '/content/images',
|
||
getUniqueFileName: () => '/content/images/unique-tag-twitter-image.jpg',
|
||
saveRaw: () => '/content/images/unique-tag-twitter-image.jpg'
|
||
})
|
||
});
|
||
|
||
await inliner.inline(['https://img.stockfresh.com']);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.ok(tagModelStub.edit.calledOnce);
|
||
assert.deepEqual(tagModelStub.edit.args[0][0], {
|
||
twitter_image: '__GHOST_URL__/content/images/unique-tag-twitter-image.jpg'
|
||
});
|
||
assert.deepEqual(tagModelStub.edit.args[0][1], {
|
||
id: 'inlined-tag-id',
|
||
context: {
|
||
internal: true
|
||
}
|
||
});
|
||
});
|
||
|
||
it('inlines cover_image image in users table', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/user_cover_image.jpg';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/user_cover_image.jpg')
|
||
.reply(200, GIF1x1);
|
||
|
||
const getMethodStub = sinon.stub();
|
||
getMethodStub.withArgs('cover_image').returns(imageURL);
|
||
getMethodStub.returns(null);
|
||
const userModelInstanceStub = {
|
||
id: 'inlined-user-id',
|
||
get: getMethodStub
|
||
};
|
||
|
||
userModelStub.findPage = sinon.stub().resolves({
|
||
data: [userModelInstanceStub]
|
||
});
|
||
sinon.stub(path, 'relative')
|
||
.withArgs('/content/images', '/content/images/user-cover-image.jpg')
|
||
.returns('user-cover-image.jpg');
|
||
|
||
const inliner = new ExternalMediaInliner({
|
||
PostModel: postModelStub,
|
||
PostMetaModel: postMetaModelStub,
|
||
TagModel: tagModelStub,
|
||
UserModel: userModelStub,
|
||
getMediaStorage: sinon.stub().withArgs('.jpg').returns({
|
||
getTargetDir: () => '/content/images',
|
||
getUniqueFileName: () => '/content/images/user-cover-image.jpg',
|
||
saveRaw: () => '/content/images/user-cover-image.jpg'
|
||
})
|
||
});
|
||
|
||
await inliner.inline(['https://img.stockfresh.com']);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.ok(userModelStub.edit.calledOnce);
|
||
assert.deepEqual(userModelStub.edit.args[0][0], {
|
||
cover_image: '__GHOST_URL__/content/images/user-cover-image.jpg'
|
||
});
|
||
assert.deepEqual(userModelStub.edit.args[0][1], {
|
||
id: 'inlined-user-id',
|
||
context: {
|
||
internal: true
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
describe('Special URL & file type handling', function () {
|
||
it('Handles URLs with quotes', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/ghost-logo’s-cool.png';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get(encodeURI('/files/f/ghost-logo’s-cool.png'))
|
||
.reply(200, ghostLogoPng);
|
||
|
||
const inliner = new ExternalMediaInliner({});
|
||
const response = await inliner.getRemoteMedia(imageURL);
|
||
const fileData = await inliner.extractFileDataFromResponse(imageURL, response);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.equal(fileData.filename, 'ghost-logos-cool.png');
|
||
assert.equal(fileData.extension, '.png');
|
||
});
|
||
|
||
it('Handles URLs with spaces', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/ghost logo with spaces.png';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get(encodeURI('/files/f/ghost logo with spaces.png'))
|
||
.reply(200, ghostLogoPng);
|
||
|
||
const inliner = new ExternalMediaInliner({});
|
||
const response = await inliner.getRemoteMedia(imageURL);
|
||
const fileData = await inliner.extractFileDataFromResponse(imageURL, response);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.equal(fileData.filename, 'ghost-logo-with-spaces.png');
|
||
assert.equal(fileData.extension, '.png');
|
||
});
|
||
|
||
it('Handles URLs with no extension', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/ghost-logo';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/ghost-logo')
|
||
.reply(200, ghostLogoPng);
|
||
|
||
const inliner = new ExternalMediaInliner({});
|
||
const response = await inliner.getRemoteMedia(imageURL);
|
||
const fileData = await inliner.extractFileDataFromResponse(imageURL, response);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.equal(fileData.filename, 'ghost-logo.png');
|
||
assert.equal(fileData.extension, '.png');
|
||
});
|
||
|
||
it('Handles URLs with unicode characters', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/你好.png';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get(encodeURI('/files/f/你好.png'))
|
||
.reply(200, ghostLogoPng);
|
||
|
||
const inliner = new ExternalMediaInliner({});
|
||
const response = await inliner.getRemoteMedia(imageURL);
|
||
const fileData = await inliner.extractFileDataFromResponse(imageURL, response);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.equal(fileData.filename, 'ni-hao.png');
|
||
assert.equal(fileData.extension, '.png');
|
||
});
|
||
|
||
it('Handles URLs with no scheme', async function () {
|
||
const imageURL = '//img.stockfresh.com/files/f/ghost-logo.png';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/ghost-logo.png')
|
||
.reply(200, ghostLogoPng);
|
||
|
||
const inliner = new ExternalMediaInliner({});
|
||
const response = await inliner.getRemoteMedia(imageURL);
|
||
const fileData = await inliner.extractFileDataFromResponse(imageURL, response);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.equal(fileData.filename, 'ghost-logo.png');
|
||
assert.equal(fileData.extension, '.png');
|
||
});
|
||
|
||
it('Handles URLs with query params', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/ghost-logo.png?version=1&size=large';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/ghost-logo.png?version=1&size=large')
|
||
.reply(200, ghostLogoPng);
|
||
|
||
const inliner = new ExternalMediaInliner({});
|
||
const response = await inliner.getRemoteMedia(imageURL);
|
||
const fileData = await inliner.extractFileDataFromResponse(imageURL, response);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.equal(fileData.filename, 'ghost-logo-version-1-size-large.png');
|
||
assert.equal(fileData.extension, '.png');
|
||
});
|
||
|
||
it('Handles URLs with duplicated characters', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/ghost---logo.png';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/ghost---logo.png')
|
||
.reply(200, ghostLogoPng);
|
||
|
||
const inliner = new ExternalMediaInliner({});
|
||
const response = await inliner.getRemoteMedia(imageURL);
|
||
const fileData = await inliner.extractFileDataFromResponse(imageURL, response);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.equal(fileData.filename, 'ghost---logo.png');
|
||
assert.equal(fileData.extension, '.png');
|
||
});
|
||
|
||
it('Handles falling back to `content-type` for type', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/photo.gif?v=1&s=2';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.defaultReplyHeaders({
|
||
'content-type': 'image/gif'
|
||
})
|
||
.get('/files/f/photo.gif?v=1&s=2')
|
||
.reply(200);
|
||
|
||
const inliner = new ExternalMediaInliner({});
|
||
const response = await inliner.getRemoteMedia(imageURL);
|
||
const fileData = await inliner.extractFileDataFromResponse(imageURL, response);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.equal(fileData.filename, 'photo-v-1-s-2.gif');
|
||
assert.equal(fileData.extension, '.gif');
|
||
});
|
||
|
||
it('Handles falling back to file path for type', async function () {
|
||
const imageURL = 'https://img.stockfresh.com/files/f/photo.gif?v=1&s=2';
|
||
const requestMock = nock('https://img.stockfresh.com')
|
||
.get('/files/f/photo.gif?v=1&s=2')
|
||
.reply(200);
|
||
|
||
const inliner = new ExternalMediaInliner({});
|
||
const response = await inliner.getRemoteMedia(imageURL);
|
||
const fileData = await inliner.extractFileDataFromResponse(imageURL, response);
|
||
|
||
assert.ok(requestMock.isDone());
|
||
assert.equal(fileData.filename, 'photo-v-1-s-2.gif');
|
||
assert.equal(fileData.extension, '.gif');
|
||
});
|
||
});
|
||
});
|
||
|