Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
Add v2.7.0
Browse files Browse the repository at this point in the history
  • Loading branch information
YannickRe committed Dec 26, 2018
1 parent 78dd55e commit 7a1008b
Show file tree
Hide file tree
Showing 31 changed files with 226 additions and 111 deletions.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion core/built/assets/icons/store.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions core/built/assets/img/mailchimp.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 67 additions & 0 deletions core/server/api/v2/configuration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const Promise = require('bluebird');
const {isPlainObject} = require('lodash');
const urlService = require('../../services/url');
const models = require('../../models');
const config = require('../../config');
const labs = require('../../services/labs');
const settingsCache = require('../../services/settings/cache');
const ghostVersion = require('../../lib/ghost-version');

function fetchAvailableTimezones() {
const timezones = require('../../data/timezones.json');
return timezones;
}

function getAboutConfig() {
return {
version: ghostVersion.full,
environment: config.get('env'),
database: config.get('database').client,
mail: isPlainObject(config.get('mail')) ? config.get('mail').transport : ''
};
}

function getBaseConfig() {
return {
useGravatar: !config.isPrivacyDisabled('useGravatar'),
publicAPI: labs.isSet('publicAPI'),
blogUrl: urlService.utils.urlFor('home', true),
blogTitle: settingsCache.get('title'),
clientExtensions: config.get('clientExtensions'),
enableDeveloperExperiments: config.get('enableDeveloperExperiments')
};
}

module.exports = {
docName: 'configuration',
read: {
permissions: false,
data: [
'key'
],
query({data}) {
if (!data.key) {
return models.Client.findOne({slug: 'ghost-admin'})
.then((ghostAdmin) => {
const configuration = getBaseConfig();

configuration.clientId = ghostAdmin.get('slug');
configuration.clientSecret = ghostAdmin.get('secret');

return configuration;
});
}

if (data.key === 'about') {
return Promise.resolve(getAboutConfig());
}

// Timezone endpoint
if (data.key === 'timezones') {
return Promise.resolve(fetchAvailableTimezones());
}

return Promise.resolve();
}
}
};
4 changes: 4 additions & 0 deletions core/server/api/v2/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,9 @@ module.exports = {

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

get configuration() {
return shared.pipeline(require('./configuration'), localUtils);
}
};
11 changes: 11 additions & 0 deletions core/server/api/v2/utils/serializers/output/configuration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const debug = require('ghost-ignition').debug('api:v2:utils:serializers:output:configuration');

module.exports = {
all(configuration, apiConfig, frame) {
frame.response = {
configuration: configuration ? [configuration] : []
};

debug(frame.response);
}
};
4 changes: 4 additions & 0 deletions core/server/api/v2/utils/serializers/output/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,9 @@ module.exports = {

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

get configuration() {
return require('./configuration');
}
};
5 changes: 5 additions & 0 deletions core/server/data/importer/importers/data/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ class Base {

// CASE: you import null, fallback to owner
if (!obj[key]) {
// Exception: If the imported post is a draft published_by will be null. Not a userReferenceProblem.
if (key === 'published_by' && obj.status === 'draft') {
return;
}

if (!userReferenceProblems[obj.id]) {
userReferenceProblems[obj.id] = {obj: _.cloneDeep(obj), keys: []};
}
Expand Down
5 changes: 0 additions & 5 deletions core/server/lib/fs/read-csv.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ module.exports = function readCSV(options) {
result[columnsToExtract[0].name] = value[headers[0]];
return result;
});

// Add first row
result = {};
result[columnsToExtract[0].name] = headers[0];
results = [result].concat(results);
} else {
// If there are multiple columns in csv file
// try to match headers using lookup value
Expand Down
16 changes: 10 additions & 6 deletions core/server/models/relations/authors.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,22 +314,26 @@ module.exports.extendModel = function extendModel(Post, Posts, ghostBookshelf) {
return isCorrectOwner;
}

function isCurrentOwner() {
return context.user === postModel.related('authors').models[0].id;
function isPrimaryAuthor() {
return (context.user === postModel.related('authors').models[0].id);
}

function isCoAuthor() {
return postModel.related('authors').models.map(author => author.id).includes(context.user);
}

if (isContributor && isEdit) {
hasUserPermission = !isChanging('author_id') && !isChangingAuthors() && isCurrentOwner();
hasUserPermission = !isChanging('author_id') && !isChangingAuthors() && isCoAuthor();
} else if (isContributor && isAdd) {
hasUserPermission = isOwner();
} else if (isContributor && isDestroy) {
hasUserPermission = isCurrentOwner();
hasUserPermission = isPrimaryAuthor();
} else if (isAuthor && isEdit) {
hasUserPermission = isCurrentOwner() && !isChanging('author_id') && !isChangingAuthors();
hasUserPermission = isCoAuthor() && !isChanging('author_id') && !isChangingAuthors();
} else if (isAuthor && isAdd) {
hasUserPermission = isOwner();
} else if (postModel) {
hasUserPermission = hasUserPermission || isCurrentOwner();
hasUserPermission = hasUserPermission || isPrimaryAuthor();
}

if (hasUserPermission && hasAppPermission) {
Expand Down
2 changes: 1 addition & 1 deletion core/server/services/auth/authenticate.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const authenticate = {
},

// ### v2 API auth middleware
authenticateAdminAPI: [session.safeGetSession, session.getUser],
authenticateAdminApi: [session.safeGetSession, session.getUser],
authenticateContentApi: [apiKeyAuth.content.authenticateContentApiKey, members.authenticateMembersToken]
};

Expand Down
2 changes: 1 addition & 1 deletion core/server/services/auth/authorize.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const authorize = {
};
},

authorizeAdminAPI: [session.ensureUser],
authorizeAdminApi: [session.ensureUser],
authorizeContentApi(req, res, next) {
const hasApiKey = req.api_key && req.api_key.id;
const hasMember = req.member;
Expand Down
3 changes: 3 additions & 0 deletions core/server/services/routing/CollectionRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ class CollectionRouter extends ParentRouter {
// REGISTER: context middleware for entries
this.router().use(this._prepareEntryContext.bind(this));

// REGISTER: page/post resource redirects
this.router().param('slug', this._respectDominantRouter.bind(this));

// REGISTER: permalinks e.g. /:slug/, /podcast/:slug
this.mountRoute(this.permalinks.getValue({withUrlOptions: true}), controllers.entry);

Expand Down
5 changes: 4 additions & 1 deletion core/server/services/routing/ParentRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ class ParentRouter extends EventEmitter {
if (targetRoute) {
debug('_respectDominantRouter');

const matchPath = this.permalinks.getValue().replace(':slug', '[a-zA-Z0-9-_]+');
// CASE: transform /tag/:slug/ -> /tag/[a-zA-Z0-9-_]+/ to able to find url pieces to append
// e.g. /tag/bacon/page/2/ -> 'page/2' (to append)
// e.g. /bacon/welcome/ -> '' (nothing to append)
const matchPath = this.permalinks.getValue().replace(/:\w+/g, '[a-zA-Z0-9-_]+');
const toAppend = req.url.replace(new RegExp(matchPath), '');

return urlService.utils.redirect301(res, url.format({
Expand Down
10 changes: 10 additions & 0 deletions core/server/services/routing/controllers/static.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ function processQuery(query, locals) {
const api = require('../../../api')[locals.apiVersion];
query = _.cloneDeep(query);

// CASE: If you define a single data key for a static route (e.g. data: page.team), this static route will represent
// the target resource. That means this static route has to behave the same way than the original resource url.
// e.g. the meta data package needs access to the full resource including relations.
// We override the `include` property for now, because the full data set is required anyway.
if (_.get(query, 'resource') === 'posts') {
_.extend(query.options, {
include: 'author,authors,tags'
});
}

// Return a promise for the api query
return (api[query.alias] || api[query.resource])[query.type](query.options);
}
Expand Down
11 changes: 8 additions & 3 deletions core/server/services/settings/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ _private.validateData = function validateData(object) {
const requiredQueryFields = ['type', 'resource'];
const allowedQueryValues = {
type: ['read', 'browse'],
resource: _.map(RESOURCE_CONFIG.QUERY, 'resource')
resource: _.union(_.map(RESOURCE_CONFIG.QUERY, 'resource'), _.map(RESOURCE_CONFIG.QUERY, 'alias'))
};
const allowedQueryOptions = ['limit', 'order', 'filter', 'include', 'slug', 'visibility', 'status'];
const allowedQueryOptions = ['limit', 'order', 'filter', 'include', 'slug', 'visibility', 'status', 'page'];
const allowedRouterOptions = ['redirect', 'slug'];
const defaultRouterOptions = {
redirect: true
Expand Down Expand Up @@ -146,7 +146,12 @@ _private.validateData = function validateData(object) {
data.query[key][option] = object.data[key][option];
});

const DEFAULT_RESOURCE = _.find(RESOURCE_CONFIG.QUERY, {resource: data.query[key].resource});
const DEFAULT_RESOURCE = _.find(RESOURCE_CONFIG.QUERY, {alias: data.query[key].resource}) || _.find(RESOURCE_CONFIG.QUERY, {resource: data.query[key].resource});

// CASE: you define resource:pages and the alias is "pages". We need to load the internal alias/resource structure, otherwise we break api versions.
data.query[key].alias = DEFAULT_RESOURCE.alias;
data.query[key].resource = DEFAULT_RESOURCE.resource;

data.query[key] = _.defaults(data.query[key], _.omit(DEFAULT_RESOURCE, 'options'));

data.query[key].options = _.pick(object.data[key], allowedQueryOptions);
Expand Down
6 changes: 3 additions & 3 deletions core/server/web/admin/views/default-prod.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<title>Ghost Admin</title>


<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22/%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Atrue%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%7D%2C%22APP%22%3A%7B%22version%22%3A%222.6%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22/%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Atrue%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%7D%2C%22APP%22%3A%7B%22version%22%3A%222.7%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />

<meta name="HandheldFriendly" content="True" />
<meta name="MobileOptimized" content="320" />
Expand All @@ -34,7 +34,7 @@


<link rel="stylesheet" href="assets/vendor.min-e71cb5c677f51d517625c8c87005a74a.css">
<link rel="stylesheet" href="assets/ghost.min-1b13c62f5c1d56fd1d1f0ebc951a3d26.css" title="light">
<link rel="stylesheet" href="assets/ghost.min-60c6f40170e0422153cd017eb77d10a7.css" title="light">



Expand All @@ -53,7 +53,7 @@


<script src="assets/vendor.min-a282d655f9b0929434826d02f2158e38.js"></script>
<script src="assets/ghost.min-2faf9f5c52906b91112aade6dd90ca58.js"></script>
<script src="assets/ghost.min-96bc2e85ece023413226dfd3e4856109.js"></script>

</body>
</html>
Loading

0 comments on commit 7a1008b

Please sign in to comment.