mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 05:37:34 +03:00
🙇 Blog icon utils and publisher.logo for JSON-LD (#8297)
refs #8221, closes #7688, refs #7558 🙇 Improve meta data publisher logo behaviour This is a follow-up PR for #8285. Reasons: The code changes of #8285 caused error messages when falling back to the default `favicon.ico`, as the `image-size` tool doesn't support `ico` files. This PR takes the logic to decide which logo needs to be listed in our schema into a new fn `blog_logo.js`. There we have now three decisions: 1. If we have a publication **logo**, we'll take that one 2. If we have no publication logo, but an **icon** we'll use this one. 3. If we have none of the above things, we fall back to our default `favicon.ico` Additional, we're hard coding image dimensions for whenever the logo is an `.ico` file and built and extra decision to not call `image-size` when the dimension are already given. I will create another follow-up PR, which checks the extension type for the file and offers it as a util. 🛠 Blog icon util refs #7688 Serve functionality around the blog icon in its own util: - getIconDimensions -> async function that takes the filepath of on ico file and returns its dimensions - isIcoImageType -> returns true if file has `.ico` extension - getIconType -> returns icon-type (`x-icon` or `png`) - getIconUrl -> returns the absolut or relativ URL for the favicon: `[subdirectory or not]favicon.[ico or png]` 📖 Get .ico sizes for meta data & logo improvement refs #7558 refs #8221 Use the new `blogIconUtil` in meta data to fetch the dimensions of `.ico` files. Improvements for `publisher.logo`: We're now returning a hard-coded 'faked' image dimensions value to render an `imageObject` and prevent error our schema (Google structured data). As soon as an image (`.ico` or non-`.ico`) is too large, but - in case of non-`.ico` - a square format, be set the image-dimensions to 60px width and height. This reduces the chances of getting constantly error messages from Googles' webmaster tools. - add getIconPath util
This commit is contained in:
parent
049b6d9874
commit
e19e91044d
@ -1,5 +1,5 @@
|
||||
var config = require('../../config'),
|
||||
settingsCache = require('../../settings/cache'),
|
||||
blogIconUtils = require('../../utils/blog-icon'),
|
||||
utils = require('../../utils');
|
||||
|
||||
/**
|
||||
@ -7,11 +7,7 @@ var config = require('../../config'),
|
||||
* @return {string}
|
||||
*/
|
||||
function getFaviconUrl() {
|
||||
if (settingsCache.get('icon')) {
|
||||
return settingsCache.get('icon').match(/\.ico$/i) ? utils.url.urlJoin(utils.url.getSubdir(), '/favicon.ico') : utils.url.urlJoin(utils.url.getSubdir(), '/favicon.png');
|
||||
}
|
||||
|
||||
return utils.url.urlJoin(utils.url.getSubdir(), '/favicon.ico');
|
||||
return blogIconUtils.getIconUrl();
|
||||
}
|
||||
|
||||
function getAssetUrl(path, hasMinFile) {
|
||||
|
46
core/server/data/meta/blog_logo.js
Normal file
46
core/server/data/meta/blog_logo.js
Normal file
@ -0,0 +1,46 @@
|
||||
var utils = require('../../utils'),
|
||||
settingsCache = require('../../settings/cache'),
|
||||
blogIconUtils = require('../../utils/blog-icon'),
|
||||
Promise = require('bluebird'),
|
||||
config = require('../../config'),
|
||||
path = require('path');
|
||||
|
||||
function getBlogLogo() {
|
||||
return new Promise(function getIconSize(resolve, reject) {
|
||||
var logo = {},
|
||||
filePath;
|
||||
|
||||
if (settingsCache.get('logo')) {
|
||||
logo.url = utils.url.urlFor('image', {image: settingsCache.get('logo')}, true);
|
||||
} else {
|
||||
// CASE: no publication logo is updated. We can try to use either an uploaded publication icon
|
||||
// or use the default one to make
|
||||
// Google happy with it. See https://github.com/TryGhost/Ghost/issues/7558
|
||||
logo.url = blogIconUtils.getIconUrl(true);
|
||||
|
||||
if (blogIconUtils.isIcoImageType(logo.url)) {
|
||||
filePath = blogIconUtils.getIconPath();
|
||||
// getIconDimensions needs the physical path of the ico file
|
||||
if (settingsCache.get('icon')) {
|
||||
// CASE: custom uploaded icon
|
||||
filePath = path.join(config.getContentPath('images'), filePath);
|
||||
}
|
||||
|
||||
return blogIconUtils.getIconDimensions(filePath).then(function (response) {
|
||||
logo.dimensions = {
|
||||
width: response.width,
|
||||
height: response.height
|
||||
};
|
||||
|
||||
return resolve(logo);
|
||||
}).catch(function (err) {
|
||||
return reject(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return resolve(logo);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = getBlogLogo;
|
@ -13,7 +13,9 @@ function getImageDimensions(metaData) {
|
||||
var fetch = {
|
||||
coverImage: getCachedImageSizeFromUrl(metaData.coverImage.url),
|
||||
authorImage: getCachedImageSizeFromUrl(metaData.authorImage.url),
|
||||
logo: getCachedImageSizeFromUrl(metaData.blog.logo.url)
|
||||
// CASE: check if logo has hard coded image dimension. In that case it's an `ico` file, which
|
||||
// is not supported by `image-size` and would produce an error
|
||||
logo: metaData.blog.logo && metaData.blog.logo.dimensions ? metaData.blog.logo.dimensions : getCachedImageSizeFromUrl(metaData.blog.logo.url)
|
||||
};
|
||||
|
||||
return Promise.props(fetch).then(function (resolve) {
|
||||
@ -30,7 +32,7 @@ function getImageDimensions(metaData) {
|
||||
// We have some restrictions for publisher.logo:
|
||||
// The image needs to be <=600px wide and <=60px high (ideally exactly 600px x 60px).
|
||||
// Unless we have proper image-handling (see https://github.com/TryGhost/Ghost/issues/4453),
|
||||
// we will not output an ImageObject if the logo doesn't fit in the dimensions.
|
||||
// we will fake it in some cases or not produce an imageObject at all.
|
||||
if (value === 'logo') {
|
||||
if (key.height <= 60 && key.width <= 600) {
|
||||
_.assign(metaData.blog[value], {
|
||||
@ -39,6 +41,17 @@ function getImageDimensions(metaData) {
|
||||
height: key.height
|
||||
}
|
||||
});
|
||||
} else if ((metaData.blog.logo && metaData.blog.logo.dimensions) || key.width === key.height) {
|
||||
// CASES:
|
||||
// 1. .ico files have image dimensions assigned already. If they're not
|
||||
// within the requirements of Google, we fake them...
|
||||
// 2. the logo (non-ico) is too large, but it is a square. We fake it as well...
|
||||
_.assign(metaData.blog[value], {
|
||||
dimensions: {
|
||||
width: 60,
|
||||
height: 60
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
_.assign(metaData[value], {
|
||||
|
@ -1,12 +1,14 @@
|
||||
var Promise = require('bluebird'),
|
||||
settingsCache = require('../../settings/cache'),
|
||||
utils = require('../../utils'),
|
||||
logging = require('../../logging'),
|
||||
getUrl = require('./url'),
|
||||
getImageDimensions = require('./image-dimensions'),
|
||||
getCanonicalUrl = require('./canonical_url'),
|
||||
getAmpUrl = require('./amp_url'),
|
||||
getPaginatedUrl = require('./paginated_url'),
|
||||
getAuthorUrl = require('./author_url'),
|
||||
getBlogLogo = require('./blog_logo'),
|
||||
getRssUrl = require('./rss_url'),
|
||||
getTitle = require('./title'),
|
||||
getDescription = require('./description'),
|
||||
@ -61,33 +63,26 @@ function getMetaData(data, root) {
|
||||
}
|
||||
};
|
||||
|
||||
metaData.blog.logo = {};
|
||||
return Promise.props(getBlogLogo()).then(function (result) {
|
||||
metaData.blog.logo = result;
|
||||
|
||||
if (settingsCache.get('logo')) {
|
||||
metaData.blog.logo.url = utils.url.urlFor('image', {image: settingsCache.get('logo')}, true);
|
||||
} else {
|
||||
metaData.blog.logo.url = utils.url.urlFor({relativeUrl: 'favicon.ico'}, true);
|
||||
// Setting image dimensions to force the default logo to be an `ImageObject` and make
|
||||
// Google happy with it. See https://github.com/TryGhost/Ghost/issues/7558
|
||||
metaData.blog.logo.dimensions = {
|
||||
width: 60,
|
||||
height: 60
|
||||
};
|
||||
}
|
||||
// TODO: cleanup these if statements
|
||||
if (data.post && data.post.html) {
|
||||
metaData.excerpt = getExcerpt(data.post.html, {words: 50});
|
||||
}
|
||||
|
||||
// TODO: cleanup these if statements
|
||||
if (data.post && data.post.html) {
|
||||
metaData.excerpt = getExcerpt(data.post.html, {words: 50});
|
||||
}
|
||||
if (data.post && data.post.author && data.post.author.name) {
|
||||
metaData.authorName = data.post.author.name;
|
||||
}
|
||||
|
||||
if (data.post && data.post.author && data.post.author.name) {
|
||||
metaData.authorName = data.post.author.name;
|
||||
}
|
||||
|
||||
return Promise.props(getImageDimensions(metaData)).then(function () {
|
||||
metaData.structuredData = getStructuredData(metaData);
|
||||
metaData.schema = getSchema(metaData, data);
|
||||
return Promise.props(getImageDimensions(metaData)).then(function () {
|
||||
metaData.structuredData = getStructuredData(metaData);
|
||||
metaData.schema = getSchema(metaData, data);
|
||||
|
||||
return metaData;
|
||||
});
|
||||
}).catch(function (err) {
|
||||
logging.error(err);
|
||||
return metaData;
|
||||
});
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ var https = require('https'),
|
||||
errors = require('../../errors'),
|
||||
logging = require('../../logging'),
|
||||
utils = require('../../utils'),
|
||||
blogIconUtils = require('../../utils/blog-icon'),
|
||||
events = require('../../events'),
|
||||
api = require('../../api/settings'),
|
||||
i18n = require('../../i18n'),
|
||||
@ -73,7 +74,7 @@ function ping(post) {
|
||||
slackData = {
|
||||
text: message,
|
||||
unfurl_links: true,
|
||||
icon_url: utils.url.urlFor({relativeUrl: 'favicon.ico'}, true),
|
||||
icon_url: blogIconUtils.getIconUrl(true),
|
||||
username: 'Ghost'
|
||||
};
|
||||
|
||||
|
@ -19,7 +19,7 @@ var proxy = require('./proxy'),
|
||||
api = proxy.api,
|
||||
settingsCache = proxy.settingsCache,
|
||||
config = proxy.config,
|
||||
url = proxy.url;
|
||||
blogIconUtils = proxy.blogIcon;
|
||||
|
||||
function getClient() {
|
||||
if (labs.isSet('publicAPI') === true) {
|
||||
@ -96,11 +96,8 @@ module.exports = function ghost_head(options) {
|
||||
metaData: getMetaData(this, options.data.root),
|
||||
client: getClient()
|
||||
},
|
||||
blogIcon = settingsCache.get('icon'),
|
||||
// CASE: blog icon is not set in config, we serve the default
|
||||
iconType = !blogIcon ? 'x-icon' : blogIcon.match(/\.ico$/i) ? 'x-icon' : 'png',
|
||||
favicon = !blogIcon ? url.urlFor({relativeUrl: '/favicon.ico'}) :
|
||||
blogIcon.match(/\.ico$/i) ? url.urlFor({relativeUrl: '/favicon.ico'}) : url.urlFor({relativeUrl: '/favicon.png'});
|
||||
favicon = blogIconUtils.getIconUrl(),
|
||||
iconType = blogIconUtils.getIconType(favicon);
|
||||
|
||||
return Promise.props(fetch).then(function (response) {
|
||||
client = response.client;
|
||||
|
@ -62,6 +62,7 @@ module.exports = {
|
||||
|
||||
// Various utils, needs cleaning up / simplifying
|
||||
socialUrls: require('../utils/social-urls'),
|
||||
blogIcon: require('../utils/blog-icon'),
|
||||
url: require('../utils').url,
|
||||
utils: {
|
||||
findKey: function findKey(key /* ...objects... */) {
|
||||
|
@ -1,10 +1,10 @@
|
||||
var fs = require('fs'),
|
||||
path = require('path'),
|
||||
crypto = require('crypto'),
|
||||
config = require('../config'),
|
||||
storage = require('../storage'),
|
||||
utils = require('../utils'),
|
||||
settingsCache = require('../settings/cache'),
|
||||
blogIconUtils = require('../utils/blog-icon'),
|
||||
buildContentResponse,
|
||||
content;
|
||||
|
||||
@ -36,7 +36,7 @@ function serveFavicon() {
|
||||
// we are using an express route to skip /content/images and the result is a image path
|
||||
// based on config.getContentPath('images') + req.path
|
||||
// in this case we don't use path rewrite, that's why we have to make it manually
|
||||
filePath = settingsCache.get('icon').replace(new RegExp(utils.url.STATIC_IMAGE_URL_PREFIX), '');
|
||||
filePath = blogIconUtils.getIconPath();
|
||||
|
||||
var originalExtension = path.extname(filePath).toLowerCase(),
|
||||
requestedExtension = path.extname(req.path).toLowerCase();
|
||||
@ -51,7 +51,7 @@ function serveFavicon() {
|
||||
storage.getStorage()
|
||||
.read({path: filePath})
|
||||
.then(function readFile(buf) {
|
||||
iconType = settingsCache.get('icon').match(/\.ico$/i) ? 'x-icon' : 'png';
|
||||
iconType = blogIconUtils.getIconType();
|
||||
content = buildContentResponse(iconType, buf);
|
||||
|
||||
res.writeHead(200, content.headers);
|
||||
@ -61,7 +61,6 @@ function serveFavicon() {
|
||||
next(err);
|
||||
});
|
||||
} else {
|
||||
filePath = path.join(config.get('paths:publicFilePath'), 'favicon.ico');
|
||||
originalExtension = path.extname(filePath).toLowerCase();
|
||||
|
||||
// CASE: always redirect to .ico for default icon
|
||||
|
@ -1,10 +1,9 @@
|
||||
var errors = require('../../errors'),
|
||||
config = require('../../config'),
|
||||
fs = require('fs'),
|
||||
Promise = require('bluebird'),
|
||||
sizeOf = require('image-size'),
|
||||
i18n = require('../../i18n'),
|
||||
_ = require('lodash'),
|
||||
blogIconUtils = require('../../utils/blog-icon'),
|
||||
validIconSize,
|
||||
getIconDimensions;
|
||||
|
||||
@ -14,40 +13,24 @@ validIconSize = function validIconSize(size) {
|
||||
|
||||
getIconDimensions = function getIconDimensions(icon) {
|
||||
return new Promise(function getImageSize(resolve, reject) {
|
||||
var arrayBuffer,
|
||||
ICO = require('icojs');
|
||||
|
||||
// image-size doesn't support .ico files
|
||||
if (icon.name.match(/.ico$/i)) {
|
||||
arrayBuffer = new Uint8Array(fs.readFileSync(icon.path)).buffer;
|
||||
ICO.parse(arrayBuffer).then(function (result, error) {
|
||||
if (error) {
|
||||
return reject(new errors.ValidationError({message: i18n.t('errors.api.icons.couldNotGetSize', {file: icon.name, error: error.message})}));
|
||||
}
|
||||
|
||||
// CASE: ico file contains only one size
|
||||
if (result.length === 1) {
|
||||
return resolve({
|
||||
width: result[0].width,
|
||||
height: result[0].height
|
||||
});
|
||||
} else {
|
||||
// CASE: ico file contains multiple sizes, return only the max size
|
||||
return resolve({
|
||||
width: _.maxBy(result, function (w) {return w.width;}).width,
|
||||
height: _.maxBy(result, function (h) {return h.height;}).height
|
||||
});
|
||||
}
|
||||
if (blogIconUtils.isIcoImageType(icon.name)) {
|
||||
blogIconUtils.getIconDimensions(icon.path).then(function (response) {
|
||||
return resolve({
|
||||
width: response.width,
|
||||
height: response.height
|
||||
});
|
||||
}).catch(function (err) {
|
||||
return reject(err);
|
||||
});
|
||||
} else {
|
||||
sizeOf(icon.path, function (err, dimensions) {
|
||||
sizeOf(icon.path, function (err, response) {
|
||||
if (err) {
|
||||
return reject(new errors.ValidationError({message: i18n.t('errors.api.icons.couldNotGetSize', {file: icon.name, error: err.message})}));
|
||||
}
|
||||
|
||||
return resolve({
|
||||
width: dimensions.width,
|
||||
height: dimensions.height
|
||||
width: response.width,
|
||||
height: response.height
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -64,9 +47,9 @@ module.exports = function blogIcon() {
|
||||
return next(new errors.ValidationError({message: i18n.t('errors.api.icons.invalidFile', {extensions: iconExtensions})}));
|
||||
}
|
||||
|
||||
return getIconDimensions(req.file).then(function (dimensions) {
|
||||
return getIconDimensions(req.file).then(function (response) {
|
||||
// save the image dimensions in new property for file
|
||||
req.file.dimensions = dimensions;
|
||||
req.file.dimensions = response;
|
||||
|
||||
// CASE: file needs to be a square
|
||||
if (req.file.dimensions.width !== req.file.dimensions.height) {
|
||||
@ -85,6 +68,8 @@ module.exports = function blogIcon() {
|
||||
}
|
||||
|
||||
next();
|
||||
}).catch(function (err) {
|
||||
next(err);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
@ -115,6 +115,9 @@
|
||||
"nameOrVersionMissing": "\"name\" or \"version\" is missing from theme package.json file.",
|
||||
"willBeRequired": "This will be required in future. Please see {url}",
|
||||
"themeFileIsMalformed": "Theme package.json file is malformed"
|
||||
},
|
||||
"blogIcon": {
|
||||
"error": "Could not fetch icon dimensions."
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
|
128
core/server/utils/blog-icon.js
Normal file
128
core/server/utils/blog-icon.js
Normal file
@ -0,0 +1,128 @@
|
||||
var ICO = require('icojs'),
|
||||
errors = require('../errors'),
|
||||
url = require('./url'),
|
||||
Promise = require('bluebird'),
|
||||
i18n = require('../i18n'),
|
||||
settingsCache = require('../settings/cache'),
|
||||
fs = require('fs'),
|
||||
_ = require('lodash'),
|
||||
path = require('path'),
|
||||
config = require('../config'),
|
||||
utils = require('../utils'),
|
||||
getIconDimensions,
|
||||
isIcoImageType,
|
||||
getIconType,
|
||||
getIconUrl,
|
||||
getIconPath;
|
||||
|
||||
/**
|
||||
* Get dimensions for ico file from its real file storage path
|
||||
* Always returns {object} getIconDimensions
|
||||
* @param {string} path
|
||||
* @returns {Promise<Object>} getIconDimensions
|
||||
* @description Takes a file path and returns ico width and height.
|
||||
*/
|
||||
getIconDimensions = function getIconDimensions(path) {
|
||||
return new Promise(function getIconSize(resolve, reject) {
|
||||
var arrayBuffer;
|
||||
|
||||
try {
|
||||
arrayBuffer = new Uint8Array(fs.readFileSync(path)).buffer;
|
||||
} catch (error) {
|
||||
return reject(error);
|
||||
}
|
||||
|
||||
ICO.parse(arrayBuffer).then(function (response) {
|
||||
// CASE: ico file contains only one size
|
||||
if (response.length === 1) {
|
||||
return resolve({
|
||||
width: response[0].width,
|
||||
height: response[0].height
|
||||
});
|
||||
} else {
|
||||
// CASE: ico file contains multiple sizes, return only the max size
|
||||
return resolve({
|
||||
width: _.maxBy(response, function (w) {return w.width;}).width,
|
||||
height: _.maxBy(response, function (h) {return h.height;}).height
|
||||
});
|
||||
}
|
||||
}).catch(function (err) {
|
||||
return reject(new errors.ValidationError({message: i18n.t('errors.utils.blogIcon.error', {file: path, error: err.message})}));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if file is `.ico` extension
|
||||
* Always returns {object} isIcoImageType
|
||||
* @param {string} icon
|
||||
* @returns {Boolean} true if submitted path is .ico file
|
||||
* @description Takes a path and returns boolean value.
|
||||
*/
|
||||
isIcoImageType = function isIcoImageType(icon) {
|
||||
var blogIcon = icon || settingsCache.get('icon');
|
||||
|
||||
return blogIcon.match(/.ico$/i) ? true : false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if file is `.ico` extension
|
||||
* Always returns {object} isIcoImageType
|
||||
* @param {string} icon
|
||||
* @returns {Boolean} true if submitted path is .ico file
|
||||
* @description Takes a path and returns boolean value.
|
||||
*/
|
||||
getIconType = function getIconType(icon) {
|
||||
var blogIcon = icon || settingsCache.get('icon');
|
||||
|
||||
return isIcoImageType(blogIcon) ? 'x-icon' : 'png';
|
||||
};
|
||||
|
||||
/**
|
||||
* Return URL for Blog icon: [subdirectory or not]favicon.[ico or png]
|
||||
* Always returns {string} getIconUrl
|
||||
* @returns {string} [subdirectory or not]favicon.[ico or png]
|
||||
* @description Checks if we have a custom uploaded icon and the extension of it. If no custom uploaded icon
|
||||
* exists, we're returning the default `favicon.ico`
|
||||
*/
|
||||
getIconUrl = function getIconUrl(absolut) {
|
||||
var blogIcon = settingsCache.get('icon');
|
||||
|
||||
if (absolut) {
|
||||
if (blogIcon) {
|
||||
return isIcoImageType(blogIcon) ? url.urlFor({relativeUrl: '/favicon.ico'}, true) : url.urlFor({relativeUrl: '/favicon.png'}, true);
|
||||
} else {
|
||||
return url.urlFor({relativeUrl: '/favicon.ico'}, true);
|
||||
}
|
||||
} else {
|
||||
if (blogIcon) {
|
||||
return isIcoImageType(blogIcon) ? url.urlFor({relativeUrl: '/favicon.ico'}) : url.urlFor({relativeUrl: '/favicon.png'});
|
||||
} else {
|
||||
return url.urlFor({relativeUrl: '/favicon.ico'});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return path for Blog icon without [subdirectory]/content/image prefix
|
||||
* Always returns {string} getIconPath
|
||||
* @returns {string} physical storage path of icon
|
||||
* @description Checks if we have a custom uploaded icon. If no custom uploaded icon
|
||||
* exists, we're returning the default `favicon.ico`
|
||||
*/
|
||||
getIconPath = function getIconPath() {
|
||||
var blogIcon = settingsCache.get('icon');
|
||||
|
||||
if (blogIcon) {
|
||||
// The '/' in urlJoin is necessary to add the '/' to `content/images`, if no subdirectory is setup
|
||||
return blogIcon.replace(new RegExp('^' + utils.url.urlJoin(utils.url.getSubdir(), '/', utils.url.STATIC_IMAGE_URL_PREFIX)), '');
|
||||
} else {
|
||||
return path.join(config.get('paths:publicFilePath'), 'favicon.ico');
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.getIconDimensions = getIconDimensions;
|
||||
module.exports.isIcoImageType = isIcoImageType;
|
||||
module.exports.getIconUrl = getIconUrl;
|
||||
module.exports.getIconPath = getIconPath;
|
||||
module.exports.getIconType = getIconType;
|
98
core/test/unit/metadata/blog_logo_spec.js
Normal file
98
core/test/unit/metadata/blog_logo_spec.js
Normal file
@ -0,0 +1,98 @@
|
||||
var should = require('should'),
|
||||
getBlogLogo = require('../../../server/data/meta/blog_logo'),
|
||||
sinon = require('sinon'),
|
||||
Promise = require('bluebird'),
|
||||
settingsCache = require('../../../server/settings/cache'),
|
||||
blogIconUtils = require('../../../server/utils/blog-icon'),
|
||||
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
describe('getBlogLogo', function () {
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('should return logo if uploaded', function (done) {
|
||||
sandbox.stub(settingsCache, 'get', function (key) {
|
||||
return {
|
||||
logo: '/content/images/logo.png',
|
||||
icon: null
|
||||
}[key];
|
||||
});
|
||||
|
||||
getBlogLogo().then(function (blogLogo) {
|
||||
should.exist(blogLogo);
|
||||
blogLogo.should.have.property('url', 'http://127.0.0.1:2369/content/images/logo.png');
|
||||
}).catch(done);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should return custom uploaded png icon if no logo given', function (done) {
|
||||
sandbox.stub(settingsCache, 'get', function (key) {
|
||||
return {
|
||||
logo: null,
|
||||
icon: '/content/images/favicon.png'
|
||||
}[key];
|
||||
});
|
||||
|
||||
getBlogLogo().then(function (blogLogo) {
|
||||
should.exist(blogLogo);
|
||||
blogLogo.should.have.property('url', 'http://127.0.0.1:2369/favicon.png');
|
||||
}).catch(done);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should return custom uploaded ico icon incl. dimensions if no logo given', function (done) {
|
||||
sandbox.stub(settingsCache, 'get', function (key) {
|
||||
return {
|
||||
logo: null,
|
||||
icon: '/content/images/myicon.ico'
|
||||
}[key];
|
||||
});
|
||||
|
||||
sandbox.stub(blogIconUtils, 'getIconDimensions').returns(Promise.resolve({width: 48, height: 48}));
|
||||
|
||||
getBlogLogo().then(function (blogLogo) {
|
||||
should.exist(blogLogo);
|
||||
blogLogo.should.have.property('url', 'http://127.0.0.1:2369/favicon.ico');
|
||||
blogLogo.should.have.property('dimensions');
|
||||
blogLogo.dimensions.should.have.property('width', 48);
|
||||
blogLogo.dimensions.should.have.property('height', 48);
|
||||
}).catch(done);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should return default favicon with dimensions if no logo or icon uploaded', function (done) {
|
||||
getBlogLogo().then(function (blogLogo) {
|
||||
should.exist(blogLogo);
|
||||
blogLogo.should.have.property('url', 'http://127.0.0.1:2369/favicon.ico');
|
||||
blogLogo.should.have.property('dimensions');
|
||||
blogLogo.dimensions.should.have.property('width', 64);
|
||||
blogLogo.dimensions.should.have.property('height', 64);
|
||||
}).catch(done);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it.skip('[failure] can handle errors', function (done) {
|
||||
sandbox.stub(settingsCache, 'get', function (key) {
|
||||
return {
|
||||
logo: null,
|
||||
icon: '/content/images/myicon.ico'
|
||||
}[key];
|
||||
});
|
||||
|
||||
sandbox.stub(blogIconUtils, 'getIconDimensions').returns(Promise.reject(new Error({message: 'could not fetch icon size'})));
|
||||
|
||||
getBlogLogo().then(function (blogLogo) {
|
||||
should.not.exist(blogLogo);
|
||||
done(new Error('should not resolve'));
|
||||
}).catch(function (err) {
|
||||
err.message.should.equal('could not fetch icon size');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
@ -51,6 +51,14 @@ describe('getImageDimensions', function () {
|
||||
result.coverImage.should.have.property('dimensions');
|
||||
result.coverImage.should.have.property('url');
|
||||
result.blog.logo.should.have.property('dimensions');
|
||||
result.coverImage.dimensions.should.have.property('height', 50);
|
||||
result.coverImage.dimensions.should.have.property('width', 50);
|
||||
result.blog.logo.should.have.property('dimensions');
|
||||
result.blog.logo.dimensions.should.have.property('height', 50);
|
||||
result.blog.logo.dimensions.should.have.property('width', 50);
|
||||
result.authorImage.should.have.property('dimensions');
|
||||
result.authorImage.dimensions.should.have.property('height', 50);
|
||||
result.authorImage.dimensions.should.have.property('width', 50);
|
||||
result.blog.logo.should.have.property('url');
|
||||
result.authorImage.should.have.property('dimensions');
|
||||
result.authorImage.should.have.property('url');
|
||||
@ -92,7 +100,7 @@ describe('getImageDimensions', function () {
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('should not return dimension for publisher.logo only if logo is too big', function (done) {
|
||||
it('should not try to fetch image dimensions for logo if already set', function (done) {
|
||||
var metaData = {
|
||||
coverImage: {
|
||||
url: 'http://mysite.com/content/image/mypostcoverimage.jpg'
|
||||
@ -102,7 +110,11 @@ describe('getImageDimensions', function () {
|
||||
},
|
||||
blog: {
|
||||
logo: {
|
||||
url: 'http://mysite.com/author/image/url/logo.jpg'
|
||||
url: 'http://mysite.com/author/image/url/favicon.ico',
|
||||
dimensions: {
|
||||
width: 60,
|
||||
height: 60
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -115,14 +127,154 @@ describe('getImageDimensions', function () {
|
||||
|
||||
getImageDimensions.__set__('getCachedImageSizeFromUrl', sizeOfStub);
|
||||
|
||||
getImageDimensions(metaData).then(function (result) {
|
||||
should.exist(result);
|
||||
sizeOfStub.calledWith(metaData.coverImage.url).should.be.true();
|
||||
sizeOfStub.calledWith(metaData.authorImage.url).should.be.true();
|
||||
sizeOfStub.calledWith(metaData.blog.logo.url).should.be.false();
|
||||
result.coverImage.should.have.property('dimensions');
|
||||
result.coverImage.dimensions.should.have.property('height', 80);
|
||||
result.coverImage.dimensions.should.have.property('width', 480);
|
||||
result.blog.logo.should.have.property('dimensions');
|
||||
result.blog.logo.dimensions.should.have.property('height', 60);
|
||||
result.blog.logo.dimensions.should.have.property('width', 60);
|
||||
result.authorImage.should.have.property('dimensions');
|
||||
result.authorImage.dimensions.should.have.property('height', 80);
|
||||
result.authorImage.dimensions.should.have.property('width', 480);
|
||||
result.coverImage.should.have.property('url');
|
||||
result.blog.logo.should.have.property('url');
|
||||
result.authorImage.should.have.property('url');
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('should fake image dimension for publisher.logo if .ico file is too big', function (done) {
|
||||
var metaData = {
|
||||
coverImage: {
|
||||
url: 'http://mysite.com/content/image/mypostcoverimage.jpg'
|
||||
},
|
||||
authorImage: {
|
||||
url: 'http://mysite.com/author/image/url/me.jpg'
|
||||
},
|
||||
blog: {
|
||||
logo: {
|
||||
url: 'http://mysite.com/author/image/url/favicon.ico',
|
||||
dimensions: {
|
||||
width: 128,
|
||||
height: 128
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sizeOfStub.returns({
|
||||
width: 480,
|
||||
height: 480,
|
||||
type: 'jpg'
|
||||
});
|
||||
|
||||
getImageDimensions.__set__('getCachedImageSizeFromUrl', sizeOfStub);
|
||||
|
||||
getImageDimensions(metaData).then(function (result) {
|
||||
should.exist(result);
|
||||
sizeOfStub.calledWith(metaData.coverImage.url).should.be.true();
|
||||
sizeOfStub.calledWith(metaData.authorImage.url).should.be.true();
|
||||
sizeOfStub.calledWith(metaData.blog.logo.url).should.be.false();
|
||||
result.coverImage.should.have.property('dimensions');
|
||||
result.coverImage.dimensions.should.have.property('height', 480);
|
||||
result.coverImage.dimensions.should.have.property('width', 480);
|
||||
result.blog.logo.should.have.property('dimensions');
|
||||
result.blog.logo.dimensions.should.have.property('height', 60);
|
||||
result.blog.logo.dimensions.should.have.property('width', 60);
|
||||
result.authorImage.should.have.property('dimensions');
|
||||
result.authorImage.dimensions.should.have.property('height', 480);
|
||||
result.authorImage.dimensions.should.have.property('width', 480);
|
||||
result.coverImage.should.have.property('url');
|
||||
result.blog.logo.should.have.property('url');
|
||||
result.authorImage.should.have.property('url');
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('should fake image dimension for publisher.logo if non-.ico file is too big and square', function (done) {
|
||||
var metaData = {
|
||||
coverImage: {
|
||||
url: 'http://mysite.com/content/image/mypostcoverimage.jpg'
|
||||
},
|
||||
authorImage: {
|
||||
url: 'http://mysite.com/author/image/url/me.jpg'
|
||||
},
|
||||
blog: {
|
||||
logo: {
|
||||
url: 'http://mysite.com/author/image/url/favicon.png'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sizeOfStub.returns({
|
||||
width: 480,
|
||||
height: 480,
|
||||
type: 'jpg'
|
||||
});
|
||||
|
||||
getImageDimensions.__set__('getCachedImageSizeFromUrl', sizeOfStub);
|
||||
|
||||
getImageDimensions(metaData).then(function (result) {
|
||||
should.exist(result);
|
||||
sizeOfStub.calledWith(metaData.coverImage.url).should.be.true();
|
||||
sizeOfStub.calledWith(metaData.authorImage.url).should.be.true();
|
||||
sizeOfStub.calledWith(metaData.blog.logo.url).should.be.true();
|
||||
result.coverImage.should.have.property('dimensions');
|
||||
result.coverImage.dimensions.should.have.property('height', 480);
|
||||
result.coverImage.dimensions.should.have.property('width', 480);
|
||||
result.blog.logo.should.have.property('dimensions');
|
||||
result.blog.logo.dimensions.should.have.property('height', 60);
|
||||
result.blog.logo.dimensions.should.have.property('width', 60);
|
||||
result.authorImage.should.have.property('dimensions');
|
||||
result.authorImage.dimensions.should.have.property('height', 480);
|
||||
result.authorImage.dimensions.should.have.property('width', 480);
|
||||
result.coverImage.should.have.property('url');
|
||||
result.blog.logo.should.have.property('url');
|
||||
result.authorImage.should.have.property('url');
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('should not fake dimension for publisher.logo if a logo is too big but not square', function (done) {
|
||||
var metaData = {
|
||||
coverImage: {
|
||||
url: 'http://mysite.com/content/image/mypostcoverimage.jpg'
|
||||
},
|
||||
authorImage: {
|
||||
url: 'http://mysite.com/author/image/url/me.jpg'
|
||||
},
|
||||
blog: {
|
||||
logo: {
|
||||
url: 'http://mysite.com/author/image/url/logo.jpg'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sizeOfStub.returns({
|
||||
width: 80,
|
||||
height: 480,
|
||||
type: 'jpg'
|
||||
});
|
||||
|
||||
getImageDimensions.__set__('getCachedImageSizeFromUrl', sizeOfStub);
|
||||
|
||||
getImageDimensions(metaData).then(function (result) {
|
||||
should.exist(result);
|
||||
sizeOfStub.calledWith(metaData.coverImage.url).should.be.true();
|
||||
sizeOfStub.calledWith(metaData.authorImage.url).should.be.true();
|
||||
sizeOfStub.calledWith(metaData.blog.logo.url).should.be.true();
|
||||
result.coverImage.should.have.property('dimensions');
|
||||
result.coverImage.dimensions.should.have.property('height', 480);
|
||||
result.coverImage.dimensions.should.have.property('width', 80);
|
||||
result.blog.logo.should.not.have.property('dimensions');
|
||||
result.authorImage.should.have.property('dimensions');
|
||||
result.authorImage.dimensions.should.have.property('height', 480);
|
||||
result.authorImage.dimensions.should.have.property('width', 80);
|
||||
result.coverImage.should.have.property('url');
|
||||
result.blog.logo.should.have.property('url');
|
||||
result.authorImage.should.have.property('url');
|
||||
|
@ -166,7 +166,7 @@ describe('Serve Favicon', function () {
|
||||
var middleware = serveFavicon();
|
||||
req.path = '/favicon.png';
|
||||
|
||||
configUtils.set('paths:corePath', path.join(__dirname, '../../../test/utils/fixtures/'));
|
||||
configUtils.set('paths:publicFilePath', path.join(__dirname, '../../../test/utils/fixtures/'));
|
||||
localSettingsCache.icon = '';
|
||||
|
||||
res = {
|
||||
|
147
core/test/unit/utils/blog-icon-spec.js
Normal file
147
core/test/unit/utils/blog-icon-spec.js
Normal file
@ -0,0 +1,147 @@
|
||||
// jshint unused: false
|
||||
var should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
_ = require('lodash'),
|
||||
settingsCache = require('../../../server/settings/cache'),
|
||||
configUtils = require('../../utils/configUtils'),
|
||||
testUtils = require('../../utils'),
|
||||
config = configUtils.config,
|
||||
path = require('path'),
|
||||
|
||||
// stuff we are testing
|
||||
blogIcon = require('../../../server/utils/blog-icon'),
|
||||
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
describe('Blog Icon', function () {
|
||||
before(function () {
|
||||
configUtils.restore();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
configUtils.restore();
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('getIconUrl', function () {
|
||||
it('custom uploaded ico blog icon', function () {
|
||||
sandbox.stub(settingsCache, 'get').withArgs('icon').returns('/content/images/2017/04/my-icon.ico');
|
||||
blogIcon.getIconUrl().should.eql('/favicon.ico');
|
||||
});
|
||||
|
||||
it('custom uploaded png blog icon', function () {
|
||||
sandbox.stub(settingsCache, 'get').withArgs('icon').returns('/content/images/2017/04/my-icon.png');
|
||||
blogIcon.getIconUrl().should.eql('/favicon.png');
|
||||
});
|
||||
|
||||
it('default ico blog icon', function () {
|
||||
blogIcon.getIconUrl().should.eql('/favicon.ico');
|
||||
});
|
||||
describe('absolute URL', function () {
|
||||
it('custom uploaded ico blog icon', function () {
|
||||
configUtils.set({url: 'http://my-ghost-blog.com/'});
|
||||
sandbox.stub(settingsCache, 'get').withArgs('icon').returns('/content/images/2017/04/my-icon.ico');
|
||||
blogIcon.getIconUrl(true).should.eql('http://my-ghost-blog.com/favicon.ico');
|
||||
});
|
||||
|
||||
it('custom uploaded png blog icon', function () {
|
||||
configUtils.set({url: 'http://my-ghost-blog.com/'});
|
||||
sandbox.stub(settingsCache, 'get').withArgs('icon').returns('/content/images/2017/04/my-icon.png');
|
||||
blogIcon.getIconUrl(true).should.eql('http://my-ghost-blog.com/favicon.png');
|
||||
});
|
||||
|
||||
it('default ico blog icon', function () {
|
||||
configUtils.set({url: 'http://my-ghost-blog.com/'});
|
||||
blogIcon.getIconUrl(true).should.eql('http://my-ghost-blog.com/favicon.ico');
|
||||
});
|
||||
});
|
||||
|
||||
describe('with subdirectory', function () {
|
||||
it('custom uploaded ico blog icon', function () {
|
||||
sandbox.stub(settingsCache, 'get').withArgs('icon').returns('/content/images/2017/04/my-icon.ico');
|
||||
configUtils.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
|
||||
blogIcon.getIconUrl().should.eql('/blog/favicon.ico');
|
||||
});
|
||||
|
||||
it('custom uploaded png blog icon', function () {
|
||||
sandbox.stub(settingsCache, 'get').withArgs('icon').returns('/content/images/2017/04/my-icon.png');
|
||||
configUtils.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
|
||||
blogIcon.getIconUrl().should.eql('/blog/favicon.png');
|
||||
});
|
||||
|
||||
it('default ico blog icon', function () {
|
||||
configUtils.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
blogIcon.getIconUrl().should.eql('/blog/favicon.ico');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getIconPath', function () {
|
||||
it('custom uploaded ico blog icon', function () {
|
||||
sandbox.stub(settingsCache, 'get').withArgs('icon').returns('/content/images/2017/04/my-icon.ico');
|
||||
blogIcon.getIconPath().should.eql('/2017/04/my-icon.ico');
|
||||
});
|
||||
|
||||
it('custom uploaded png blog icon', function () {
|
||||
sandbox.stub(settingsCache, 'get').withArgs('icon').returns('/content/images/2017/04/my-icon.png');
|
||||
blogIcon.getIconPath().should.eql('/2017/04/my-icon.png');
|
||||
});
|
||||
|
||||
it('default ico blog icon', function () {
|
||||
blogIcon.getIconPath().should.eql(path.join(__dirname, '../../../server/public/favicon.ico'));
|
||||
});
|
||||
|
||||
describe('with subdirectory', function () {
|
||||
it('custom uploaded ico blog icon', function () {
|
||||
sandbox.stub(settingsCache, 'get').withArgs('icon').returns('/blog/content/images/2017/04/my-icon.ico');
|
||||
configUtils.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
|
||||
blogIcon.getIconPath().should.eql('/2017/04/my-icon.ico');
|
||||
});
|
||||
|
||||
it('custom uploaded png blog icon', function () {
|
||||
sandbox.stub(settingsCache, 'get').withArgs('icon').returns('/blog/content/images/2017/04/my-icon.png');
|
||||
configUtils.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
|
||||
blogIcon.getIconPath().should.eql('/2017/04/my-icon.png');
|
||||
});
|
||||
|
||||
it('default ico blog icon', function () {
|
||||
configUtils.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
blogIcon.getIconPath().should.eql(path.join(__dirname, '../../../server/public/favicon.ico'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isIcoImageType', function () {
|
||||
it('returns true, if icon is .ico filetype', function () {
|
||||
blogIcon.isIcoImageType('icon.ico').should.be.true();
|
||||
});
|
||||
|
||||
it('returns false, if icon is not .ico filetype', function () {
|
||||
blogIcon.isIcoImageType('icon.png').should.be.false();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getIconType', function () {
|
||||
it('returns x-icon for ico icons', function () {
|
||||
blogIcon.getIconType('favicon.ico').should.eql('x-icon');
|
||||
});
|
||||
|
||||
it('returns png for png icon', function () {
|
||||
blogIcon.getIconType('favicon.png').should.eql('png');
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip('getIconDimensions', function () {
|
||||
it('[success] returns icon dimensions', function (done) {
|
||||
done();
|
||||
});
|
||||
|
||||
it('[failure] return error message', function (done) {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user