0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00
ghost/test/regression/api/canary/admin/settings.test.js
Naz 8dd33c5034 Removed "ghost = testUtils.startGhost" pattern
refs https://github.com/TryGhost/Toolbox/issues/138

- Having the "ghost" alias only added cognitive load when reading through the test code and didn't provide any additional value. Removed the pattern to keep things simpler and more explicit
2021-11-25 03:20:47 +13:00

1414 lines
50 KiB
JavaScript

const _ = require('lodash');
const should = require('should');
const supertest = require('supertest');
const config = require('../../../../../core/shared/config');
const testUtils = require('../../../../utils');
const localUtils = require('./utils');
const db = require('../../../../../core/server/data/db');
// NOTE: in future iterations these fields should be fetched from a central module.
// Have put a list as is here for the lack of better place for it.
const defaultSettingsKeyTypes = [
{
key: 'title',
type: 'string',
group: 'site'
},
{
key: 'description',
type: 'string',
group: 'site'
},
{
key: 'logo',
type: 'string',
group: 'site'
},
{
key: 'cover_image',
type: 'string',
group: 'site'
},
{
key: 'icon',
type: 'string',
group: 'site'
},
{
key: 'lang',
type: 'string',
group: 'site'
},
{
key: 'locale',
type: 'string',
group: 'site'
},
{
key: 'timezone',
type: 'string',
group: 'site'
},
{
key: 'codeinjection_head',
type: 'string',
group: 'site'
},
{
key: 'codeinjection_foot',
type: 'string',
group: 'site'
},
{
key: 'facebook',
type: 'string',
group: 'site'
},
{
key: 'twitter',
type: 'string',
group: 'site'
},
{
key: 'navigation',
type: 'array',
group: 'site'
},
{
key: 'secondary_navigation',
type: 'array',
group: 'site'
},
{
key: 'meta_title',
type: 'string',
group: 'site'
},
{
key: 'meta_description',
type: 'string',
group: 'site'
},
{
key: 'og_image',
type: 'string',
group: 'site'
},
{
key: 'og_title',
type: 'string',
group: 'site'
},
{
key: 'og_description',
type: 'string',
group: 'site'
},
{
key: 'twitter_image',
type: 'string',
group: 'site'
},
{
key: 'twitter_title',
type: 'string',
group: 'site'
},
{
key: 'twitter_description',
type: 'string',
group: 'site'
},
{
key: 'active_theme',
type: 'string',
group: 'theme'
},
{
key: 'is_private',
type: 'boolean',
group: 'private'
},
{
key: 'password',
type: 'string',
group: 'private'
},
{
key: 'public_hash',
type: 'string',
group: 'private'
},
{
key: 'default_content_visibility',
type: 'string',
group: 'members'
},
{
key: 'members_signup_access',
type: 'string',
group: 'members'
},
{
key: 'members_from_address',
type: 'string',
group: 'members'
},
{
key: 'members_support_address',
type: 'string',
group: 'members'
},
{
key: 'members_reply_address',
type: 'string',
group: 'members'
},
{
key: 'members_paid_signup_redirect',
type: 'string',
group: 'members'
},
{
key: 'members_free_signup_redirect',
type: 'string',
group: 'members'
},
{
key: 'members_free_price_name',
type: 'string',
group: 'members'
},
{
key: 'members_free_price_description',
type: 'string',
group: 'members'
},
{
key: 'members_monthly_price_id',
type: 'string',
group: 'members'
},
{
key: 'members_yearly_price_id',
type: 'string',
group: 'members'
},
{
key: 'stripe_product_name',
type: 'string',
group: 'members'
},
{
key: 'stripe_plans',
type: 'array',
group: 'members'
},
{
key: 'stripe_secret_key',
type: 'string',
group: 'members'
},
{
key: 'stripe_publishable_key',
type: 'string',
group: 'members'
},
{
key: 'stripe_connect_secret_key',
type: 'string',
group: 'members'
},
{
key: 'stripe_connect_publishable_key',
type: 'string',
group: 'members'
},
{
key: 'stripe_connect_account_id',
type: 'string',
group: 'members'
},
{
key: 'stripe_connect_display_name',
type: 'string',
group: 'members'
},
{
key: 'stripe_connect_livemode',
type: 'boolean',
group: 'members'
},
{
key: 'portal_name',
type: 'boolean',
group: 'portal'
},
{
key: 'portal_button',
type: 'boolean',
group: 'portal'
},
{
key: 'portal_plans',
type: 'array',
group: 'portal'
},
{
key: 'portal_products',
type: 'array',
group: 'portal'
},
{
key: 'portal_button_style',
type: 'string',
group: 'portal'
},
{
key: 'portal_button_icon',
type: 'string',
group: 'portal'
},
{
key: 'portal_button_signup_text',
type: 'string',
group: 'portal'
},
{
key: 'mailgun_api_key',
type: 'string',
group: 'email'
},
{
key: 'mailgun_domain',
type: 'string',
group: 'email'
},
{
key: 'mailgun_base_url',
type: 'string',
group: 'email'
},
{
key: 'email_track_opens',
type: 'boolean',
group: 'email'
},
{
key: 'email_verification_required',
type: 'boolean',
group: 'email'
},
{
key: 'amp',
type: 'boolean',
group: 'amp'
},
{
key: 'amp_gtag_id',
type: 'string',
group: 'amp'
},
{
key: 'slack',
type: 'string',
group: 'slack'
},
{
key: 'slack_url',
type: 'string',
group: 'slack'
},
{
key: 'slack_username',
type: 'string',
group: 'slack'
},
{
key: 'unsplash',
type: 'boolean',
group: 'unsplash'
},
{
key: 'shared_views',
type: 'array',
group: 'views'
},
{
key: 'active_timezone',
type: 'string',
group: 'site'
},
{
key: 'default_locale',
type: 'string',
group: 'site'
},
{
key: 'accent_color',
type: 'string',
group: 'site'
},
{
key: 'newsletter_show_badge',
type: 'boolean',
group: 'newsletter'
},
{
key: 'newsletter_header_image',
type: 'string',
group: 'newsletter'
},
{
key: 'newsletter_show_header_icon',
type: 'boolean',
group: 'newsletter'
},
{
key: 'newsletter_show_header_title',
type: 'boolean',
group: 'newsletter'
},
{
key: 'newsletter_title_alignment',
type: 'string',
group: 'newsletter'
},
{
key: 'newsletter_title_font_category',
type: 'string',
group: 'newsletter'
},
{
key: 'newsletter_show_feature_image',
type: 'boolean',
group: 'newsletter'
},
{
key: 'newsletter_body_font_category',
type: 'string',
group: 'newsletter'
},
{
key: 'newsletter_footer_content',
type: 'string',
group: 'newsletter'
},
{
key: 'firstpromoter',
type: 'boolean',
group: 'firstpromoter'
},
{
key: 'firstpromoter_id',
type: 'string',
group: 'firstpromoter'
},
{
key: 'oauth_client_id',
type: 'string',
group: 'oauth'
},
{
key: 'oauth_client_secret',
type: 'string',
group: 'oauth'
},
{
key: 'editor_default_email_recipients',
type: 'string',
group: 'editor'
},
{
key: 'editor_default_email_recipients_filter',
type: 'string',
group: 'editor'
},
{
key: 'editor_is_launch_complete',
type: 'boolean',
group: 'editor'
},
{
key: 'labs',
type: 'object',
group: 'labs'
}
];
describe('Settings API (canary)', function () {
let ghostServer;
let request;
describe('As Owner', function () {
before(function () {
return testUtils.startGhost()
.then(function (_ghostServer) {
ghostServer = _ghostServer;
request = supertest.agent(config.get('url'));
})
.then(function () {
return localUtils.doAuth(request);
});
});
it('Can request all settings', function () {
return request.get(localUtils.API.getApiQuery(`settings/`))
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.then((res) => {
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse.settings);
should.exist(jsonResponse.meta);
jsonResponse.settings.should.be.an.Object();
const settings = jsonResponse.settings;
should.equal(settings.length, defaultSettingsKeyTypes.length);
for (const defaultSetting of defaultSettingsKeyTypes) {
should.exist(settings.find((setting) => {
return (setting.key === defaultSetting.key)
&& (setting.type === defaultSetting.type)
&& (setting.group === defaultSetting.group);
}), `Expected to find a setting with key ${defaultSetting.key}, type ${defaultSetting.type}, and group ${defaultSetting.group}`);
}
const unsplash = settings.find(s => s.key === 'unsplash');
should.exist(unsplash);
unsplash.value.should.equal(true);
localUtils.API.checkResponse(jsonResponse, 'settings');
});
});
it('Ignores the deprecated type filter', function () {
return request.get(localUtils.API.getApiQuery(`settings/?type=theme`))
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.then((res) => {
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse.settings);
should.exist(jsonResponse.meta);
jsonResponse.settings.should.be.an.Object();
const settings = jsonResponse.settings;
// Returns all settings
should.equal(settings.length, defaultSettingsKeyTypes.length);
for (const defaultSetting of defaultSettingsKeyTypes) {
should.exist(settings.find((setting) => {
return setting.key === defaultSetting.key && setting.type === defaultSetting.type;
}), `Expected to find a setting with key ${defaultSetting.key} and type ${defaultSetting.type}`);
}
localUtils.API.checkResponse(jsonResponse, 'settings');
});
});
it('Can request settings by group', function () {
return request.get(localUtils.API.getApiQuery(`settings/?group=theme`))
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.then((res) => {
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse.settings);
should.exist(jsonResponse.meta);
jsonResponse.settings.should.be.an.Object();
const settings = jsonResponse.settings;
Object.keys(settings).length.should.equal(1);
settings[0].key.should.equal('active_theme');
settings[0].value.should.equal('casper');
settings[0].type.should.equal('string');
settings[0].group.should.equal('theme');
localUtils.API.checkResponse(jsonResponse, 'settings');
});
});
it('Requesting core settings type ignores the parameter and returns all settings', function () {
return request.get(localUtils.API.getApiQuery(`settings/?type=core`))
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.then((res) => {
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse.settings);
should.exist(jsonResponse.meta);
jsonResponse.settings.should.be.an.Object();
const settings = jsonResponse.settings;
Object.keys(settings).length.should.equal(defaultSettingsKeyTypes.length);
localUtils.API.checkResponse(jsonResponse, 'settings');
});
});
it('Can\'t read core setting', function () {
return request
.get(localUtils.API.getApiQuery('settings/db_hash/'))
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(403);
});
it('Can\'t read secret setting', function (done) {
const key = 'stripe_secret_key';
request
.get(localUtils.API.getApiQuery(`settings/${key}/`))
.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);
}
const json = res.body;
should.exist(json);
should.exist(json.settings);
json.settings.length.should.eql(1);
json.settings[0].key.should.eql('stripe_secret_key');
should(json.settings[0].value).be.null();
done();
});
});
it('Can\'t read secret setting', function (done) {
const key = 'stripe_secret_key';
request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send({
settings: [{
key,
value: 'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
}]
})
.then(() => {
request
.get(localUtils.API.getApiQuery(`settings/${key}/`))
.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);
}
const json = res.body;
should.exist(json);
should.exist(json.settings);
json.settings.length.should.eql(1);
json.settings[0].key.should.eql('stripe_secret_key');
json.settings[0].value.should.eql('••••••••');
done();
});
});
});
it('Can\'t read permalinks', function (done) {
request.get(localUtils.API.getApiQuery('settings/permalinks/'))
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {
return done(err);
}
done();
});
});
it('Can read slack_url introduced in v4', function (done) {
request.get(localUtils.API.getApiQuery('settings/slack_url/'))
.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);
}
if (err) {
return done(err);
}
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings.length.should.eql(1);
jsonResponse.settings[0].key.should.eql('slack_url');
done();
});
});
it('Can read labs', async function () {
const res = await request.get(localUtils.API.getApiQuery('settings/labs/'))
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200);
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
const jsonObjectRegex = /^\{.*\}$/; // '{...}'
jsonResponse.settings[0].key.should.eql('labs');
jsonResponse.settings[0].value.should.match(jsonObjectRegex);
});
it('Can read deprecated default_locale', function (done) {
request.get(localUtils.API.getApiQuery('settings/default_locale/'))
.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);
}
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
jsonResponse.settings[0].key.should.eql('default_locale');
done();
});
});
it('Can edit deprecated default_locale setting', function () {
return request.get(localUtils.API.getApiQuery('settings/default_locale/'))
.set('Origin', config.get('url'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.then(function (res) {
let jsonResponse = res.body;
const newValue = 'new value';
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings = [{key: 'default_locale', value: 'ua'}];
return jsonResponse;
})
.then((editedSetting) => {
return request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send(editedSetting)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.then(function (res) {
should.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
jsonResponse.settings[0].key.should.eql('default_locale');
jsonResponse.settings[0].value.should.eql('ua');
});
});
});
it('Can edit deprecated lang setting', function () {
return request.get(localUtils.API.getApiQuery('settings/lang/'))
.set('Origin', config.get('url'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.then(function (res) {
let jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings = [{key: 'lang', value: 'ua'}];
return jsonResponse;
})
.then((editedSetting) => {
return request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send(editedSetting)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.then(function (res) {
should.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
jsonResponse.settings[0].key.should.eql('lang');
jsonResponse.settings[0].value.should.eql('ua');
});
});
});
it('Can edit newly introduced locale setting', function () {
return request.get(localUtils.API.getApiQuery('settings/locale/'))
.set('Origin', config.get('url'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.then(function (res) {
let jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings = [{key: 'locale', value: 'ge'}];
return jsonResponse;
})
.then((editedSetting) => {
return request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send(editedSetting)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.then(function (res) {
should.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
jsonResponse.settings[0].key.should.eql('locale');
jsonResponse.settings[0].value.should.eql('ge');
});
});
});
it('Can read timezone', function (done) {
request.get(localUtils.API.getApiQuery('settings/timezone/'))
.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);
}
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
jsonResponse.settings[0].key.should.eql('timezone');
done();
});
});
it('Can read active_timezone', function (done) {
request.get(localUtils.API.getApiQuery('settings/active_timezone/'))
.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);
}
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
jsonResponse.settings[0].key.should.eql('active_timezone');
done();
});
});
it('Can read deprecated active_timezone', function (done) {
request.get(localUtils.API.getApiQuery('settings/active_timezone/'))
.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);
}
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
jsonResponse.settings[0].key.should.eql('active_timezone');
done();
});
});
it('Can read slack renamed&reformatted in v4', function (done) {
request.get(localUtils.API.getApiQuery('settings/slack/'))
.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);
}
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
jsonResponse.settings[0].key.should.eql('slack');
done();
});
});
it('Format of unsplash is boolean as introduced with v4', function (done) {
request.get(localUtils.API.getApiQuery('settings/unsplash/'))
.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);
}
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
jsonResponse.settings[0].key.should.eql('unsplash');
JSON.parse(jsonResponse.settings[0].value).should.eql(true);
done();
});
});
it('Can\'t read non existent setting', function (done) {
request.get(localUtils.API.getApiQuery('settings/testsetting/'))
.set('Origin', config.get('url'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {
return done(err);
}
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.errors);
testUtils.API.checkResponseValue(jsonResponse.errors[0], [
'message',
'context',
'type',
'details',
'property',
'help',
'code',
'id'
]);
done();
});
});
it('Can\'t edit permalinks', function (done) {
const settingToChange = {
settings: [{key: 'permalinks', value: '/:primary_author/:slug/'}]
};
request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send(settingToChange)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {
return done(err);
}
done();
});
});
it('Can edit only allowed labs keys', async function () {
const settingToChange = {
settings: [{
key: 'labs',
value: JSON.stringify({
activitypub: true,
gibberish: true
})
}]
};
const res = await request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send(settingToChange)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings.length.should.eql(1);
testUtils.API.checkResponseValue(jsonResponse.settings[0], ['id', 'group', 'key', 'value', 'type', 'flags', 'created_at', 'updated_at']);
jsonResponse.settings[0].key.should.eql('labs');
const responseObj = JSON.parse(jsonResponse.settings[0].value);
should.not.exist(responseObj.gibberish);
});
it('Can\'t edit non existent setting', function () {
return request.get(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.then(function (res) {
let jsonResponse = res.body;
const newValue = 'new value';
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings = [{key: 'testvalue', value: newValue}];
return request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send(jsonResponse)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.then(function ({body, headers}) {
jsonResponse = body;
should.not.exist(headers['x-cache-invalidate']);
should.exist(jsonResponse.errors);
testUtils.API.checkResponseValue(jsonResponse.errors[0], [
'message',
'context',
'type',
'details',
'property',
'help',
'code',
'id'
]);
});
});
});
it('Will transform "1"', function () {
return request.get(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.then(function (res) {
const jsonResponse = res.body;
const settingToChange = {
settings: [
{
key: 'is_private',
value: '1'
}
]
};
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
return request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send(settingToChange)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.then(function ({body, headers}) {
const putBody = body;
headers['x-cache-invalidate'].should.eql('/*');
should.exist(putBody);
putBody.settings[0].key.should.eql('is_private');
putBody.settings[0].value.should.eql(true);
localUtils.API.checkResponse(putBody, 'settings');
});
});
});
it('Can edit multiple setting along with a deprecated one from v4', async function () {
const settingToChange = {
settings: [
{
key: 'slack',
value: JSON.stringify([{
url: 'https://newurl.tld/slack',
username: 'New Slack Username'
}])
}, {
key: 'unsplash',
value: true
}, {
key: 'title',
value: 'New Value'
}
]
};
const {body, headers} = await request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send(settingToChange)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200);
const putBody = body;
headers['x-cache-invalidate'].should.eql('/*');
should.exist(putBody);
putBody.settings.length.should.equal(3);
putBody.settings[0].key.should.eql('unsplash');
should.equal(putBody.settings[0].value, true);
putBody.settings[1].key.should.eql('title');
should.equal(putBody.settings[1].value, 'New Value');
putBody.settings[2].key.should.eql('slack');
should.equal(putBody.settings[2].value, JSON.stringify([{
url: 'https://newurl.tld/slack',
username: 'New Slack Username'
}]));
localUtils.API.checkResponse(putBody, 'settings');
});
it('Can edit a setting introduced in v4', async function () {
const settingToChange = {
settings: [
{
key: 'slack_username',
value: 'can edit me'
}
]
};
const {body, headers} = await request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send(settingToChange)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200);
const putBody = body;
headers['x-cache-invalidate'].should.eql('/*');
should.exist(putBody);
putBody.settings.length.should.equal(1);
localUtils.API.checkResponse(putBody, 'settings');
putBody.settings[0].key.should.eql('slack_username');
putBody.settings[0].value.should.eql('can edit me');
});
it('Can edit URLs without internal storage format leaking', async function () {
const settingsToChange = {
settings: [
{key: 'cover_image', value: `${config.get('url')}/content/images/cover_image.png`},
{key: 'logo', value: `${config.get('url')}/content/images/logo.png`},
{key: 'icon', value: `${config.get('url')}/content/images/icon.png`},
{key: 'portal_button_icon', value: `${config.get('url')}/content/images/portal_button_icon.png`},
{key: 'og_image', value: `${config.get('url')}/content/images/og_image.png`},
{key: 'twitter_image', value: `${config.get('url')}/content/images/twitter_image.png`}
]
};
const {body} = await request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send(settingsToChange)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200);
const responseSettings = body.settings.reduce((acc, setting) => {
acc[setting.key] = setting.value;
return acc;
}, {});
responseSettings.should.have.property('cover_image', `${config.get('url')}/content/images/cover_image.png`);
responseSettings.should.have.property('logo', `${config.get('url')}/content/images/logo.png`);
responseSettings.should.have.property('icon', `${config.get('url')}/content/images/icon.png`);
responseSettings.should.have.property('portal_button_icon', `${config.get('url')}/content/images/portal_button_icon.png`);
responseSettings.should.have.property('og_image', `${config.get('url')}/content/images/og_image.png`);
responseSettings.should.have.property('twitter_image', `${config.get('url')}/content/images/twitter_image.png`);
const dbSettingsRows = await db.knex('settings')
.select('key', 'value')
.whereIn('key', ['cover_image', 'logo', 'icon', 'portal_button_icon', 'og_image', 'twitter_image']);
const dbSettings = dbSettingsRows.reduce((acc, setting) => {
acc[setting.key] = setting.value;
return acc;
}, {});
dbSettings.should.have.property('cover_image', '__GHOST_URL__/content/images/cover_image.png');
dbSettings.should.have.property('logo', '__GHOST_URL__/content/images/logo.png');
dbSettings.should.have.property('icon', '__GHOST_URL__/content/images/icon.png');
dbSettings.should.have.property('portal_button_icon', '__GHOST_URL__/content/images/portal_button_icon.png');
dbSettings.should.have.property('og_image', '__GHOST_URL__/content/images/og_image.png');
dbSettings.should.have.property('twitter_image', '__GHOST_URL__/content/images/twitter_image.png');
});
it('Can only send array values for keys defined with array type', async function () {
const settingsToChange = {
settings: [
{key: 'navigation', value: 'not an array'}
]
};
await request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send(settingsToChange)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(422);
});
it('Cannot edit notifications key through API', async function () {
const settingsToChange = {
settings: [
{key: 'notifications', value: JSON.stringify(['do not touch me'])}
]
};
await request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send(settingsToChange)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(403);
});
});
describe('As Admin', function () {
before(function () {
return testUtils.startGhost()
.then(function (_ghostServer) {
ghostServer = _ghostServer;
request = supertest.agent(config.get('url'));
})
.then(function () {
// create admin
return testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'admin+1@ghost.org'}),
role: testUtils.DataGenerator.Content.roles[0].name
});
})
.then(function (admin) {
request.user = admin;
// by default we login with the owner
return localUtils.doAuth(request);
});
});
});
describe('As Editor', function () {
let editor;
before(function () {
return testUtils.startGhost()
.then(function (_ghostServer) {
ghostServer = _ghostServer;
request = supertest.agent(config.get('url'));
})
.then(function () {
// create editor
return testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'test+1@ghost.org'}),
role: testUtils.DataGenerator.Content.roles[1].name
});
})
.then(function (_user1) {
editor = _user1;
request.user = editor;
// by default we login with the owner
return localUtils.doAuth(request);
});
});
it('should not be able to edit settings', function () {
return request.get(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.then(function (res) {
let jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings = [{key: 'visibility', value: 'public'}];
return request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send(jsonResponse)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(403)
.then(function ({body, headers}) {
jsonResponse = body;
should.not.exist(headers['x-cache-invalidate']);
should.exist(jsonResponse.errors);
testUtils.API.checkResponseValue(jsonResponse.errors[0], [
'message',
'context',
'type',
'details',
'property',
'help',
'code',
'id'
]);
});
});
});
});
describe('As Author', function () {
before(function () {
return testUtils.startGhost()
.then(function (_ghostServer) {
ghostServer = _ghostServer;
request = supertest.agent(config.get('url'));
})
.then(function () {
// create author
return testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'test+2@ghost.org'}),
role: testUtils.DataGenerator.Content.roles[2].name
});
})
.then(function (author) {
request.user = author;
// by default we login with the owner
return localUtils.doAuth(request);
});
});
it('should not be able to edit settings', function () {
return request.get(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.then(function (res) {
let jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.settings);
jsonResponse.settings = [{key: 'visibility', value: 'public'}];
return request.put(localUtils.API.getApiQuery('settings/'))
.set('Origin', config.get('url'))
.send(jsonResponse)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(403)
.then(function ({body, headers}) {
jsonResponse = body;
should.not.exist(headers['x-cache-invalidate']);
should.exist(jsonResponse.errors);
testUtils.API.checkResponseValue(jsonResponse.errors[0], [
'message',
'context',
'type',
'details',
'property',
'help',
'code',
'id'
]);
});
});
});
});
});