mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 14:03:48 +03:00
Removed id
restriction for posts relations in Admin API v2 (#10489)
refs #10438 - we now try to match by slug or id or email - fallback to owner - you cannot create a user via post endpoint - Ghost uses the invite flow to add users - get rid of `id` restriction on API level
This commit is contained in:
parent
6bdeeaba10
commit
c2b3520652
@ -134,9 +134,21 @@
|
|||||||
"id": {
|
"id": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 24
|
"maxLength": 24
|
||||||
|
},
|
||||||
|
"slug": {
|
||||||
|
"type": "string",
|
||||||
|
"maxLength": 191
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string",
|
||||||
|
"maxLength": 191
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["id"]
|
"anyOf": [
|
||||||
|
{"required": ["id"]},
|
||||||
|
{"required": ["slug"]},
|
||||||
|
{"required": ["email"]}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"post-tags": {
|
"post-tags": {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
const _ = require('lodash'),
|
const _ = require('lodash');
|
||||||
Promise = require('bluebird'),
|
const Promise = require('bluebird');
|
||||||
common = require('../../lib/common');
|
const common = require('../../lib/common');
|
||||||
|
const sequence = require('../../lib/promise/sequence');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Why and when do we have to fetch `authors` by default?
|
* Why and when do we have to fetch `authors` by default?
|
||||||
@ -100,10 +101,13 @@ module.exports.extendModel = function extendModel(Post, Posts, ghostBookshelf) {
|
|||||||
return this._handleOptions('onUpdating')(model, attrs, options);
|
return this._handleOptions('onUpdating')(model, attrs, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
// NOTE: `post.author` was always ignored [unsupported]
|
// @NOTE: `post.author` was always ignored [unsupported]
|
||||||
|
// @NOTE: triggered before creating and before updating
|
||||||
onSaving: function (model, attrs, options) {
|
onSaving: function (model, attrs, options) {
|
||||||
|
const ops = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated: `author`, will be removed in Ghost 3.0
|
* @deprecated: `author`, will be removed in Ghost 3.0, drop v0.1
|
||||||
*/
|
*/
|
||||||
model.unset('author');
|
model.unset('author');
|
||||||
|
|
||||||
@ -114,11 +118,47 @@ module.exports.extendModel = function extendModel(Post, Posts, ghostBookshelf) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// CASE: `post.author_id` has changed
|
/**
|
||||||
if (model.hasChanged('author_id')) {
|
* @NOTE:
|
||||||
// CASE: you don't send `post.authors`
|
*
|
||||||
// SOLUTION: we have to update the primary author
|
* Try to find a user with either id, slug or email if "authors" is present.
|
||||||
if (!model.get('authors')) {
|
* Otherwise fallback to owner user.
|
||||||
|
*
|
||||||
|
* You cannot create an author via posts!
|
||||||
|
* Ghost uses the invite flow to create users.
|
||||||
|
*/
|
||||||
|
if (model.get('authors')) {
|
||||||
|
ops.push(() => {
|
||||||
|
return this.matchAuthors(model, options);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ops.push(() => {
|
||||||
|
// CASE: `post.author_id` has changed
|
||||||
|
if (model.hasChanged('author_id')) {
|
||||||
|
// CASE: you don't send `post.authors`
|
||||||
|
// SOLUTION: we have to update the primary author
|
||||||
|
if (!model.get('authors')) {
|
||||||
|
let existingAuthors = model.related('authors').toJSON();
|
||||||
|
|
||||||
|
// CASE: override primary author
|
||||||
|
existingAuthors[0] = {
|
||||||
|
id: model.get('author_id')
|
||||||
|
};
|
||||||
|
|
||||||
|
model.set('authors', existingAuthors);
|
||||||
|
} else {
|
||||||
|
// CASE: you send `post.authors` next to `post.author_id`
|
||||||
|
if (model.get('authors')[0].id !== model.get('author_id')) {
|
||||||
|
model.set('author_id', model.get('authors')[0].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CASE: if you change `post.author_id`, we have to update the primary author
|
||||||
|
// CASE: if the `author_id` has change and you pass `posts.authors`, we already check above that
|
||||||
|
// the primary author id must be equal
|
||||||
|
if (model.hasChanged('author_id') && !model.get('authors')) {
|
||||||
let existingAuthors = model.related('authors').toJSON();
|
let existingAuthors = model.related('authors').toJSON();
|
||||||
|
|
||||||
// CASE: override primary author
|
// CASE: override primary author
|
||||||
@ -127,32 +167,15 @@ module.exports.extendModel = function extendModel(Post, Posts, ghostBookshelf) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
model.set('authors', existingAuthors);
|
model.set('authors', existingAuthors);
|
||||||
} else {
|
} else if (model.get('authors') && model.get('authors').length) {
|
||||||
// CASE: you send `post.authors` next to `post.author_id`
|
// ensure we update the primary author id
|
||||||
if (model.get('authors')[0].id !== model.get('author_id')) {
|
model.set('author_id', model.get('authors')[0].id);
|
||||||
model.set('author_id', model.get('authors')[0].id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// CASE: if you change `post.author_id`, we have to update the primary author
|
return proto.onSaving.call(this, model, attrs, options);
|
||||||
// CASE: if the `author_id` has change and you pass `posts.authors`, we already check above that
|
});
|
||||||
// the primary author id must be equal
|
|
||||||
if (model.hasChanged('author_id') && !model.get('authors')) {
|
|
||||||
let existingAuthors = model.related('authors').toJSON();
|
|
||||||
|
|
||||||
// CASE: override primary author
|
return sequence(ops);
|
||||||
existingAuthors[0] = {
|
|
||||||
id: model.get('author_id')
|
|
||||||
};
|
|
||||||
|
|
||||||
model.set('authors', existingAuthors);
|
|
||||||
} else if (model.get('authors') && model.get('authors').length) {
|
|
||||||
// ensure we update the primary author id
|
|
||||||
model.set('author_id', model.get('authors')[0].id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return proto.onSaving.call(this, model, attrs, options);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
serialize: function serialize(options) {
|
serialize: function serialize(options) {
|
||||||
@ -203,6 +226,54 @@ module.exports.extendModel = function extendModel(Post, Posts, ghostBookshelf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return attrs;
|
return attrs;
|
||||||
|
},
|
||||||
|
|
||||||
|
matchAuthors(model, options) {
|
||||||
|
let ownerUser;
|
||||||
|
const ops = [];
|
||||||
|
|
||||||
|
ops.push(() => {
|
||||||
|
return ghostBookshelf
|
||||||
|
.model('User')
|
||||||
|
.getOwnerUser(Object.assign({columns: ['id']}, _.pick(options, 'transacting')))
|
||||||
|
.then((_ownerUser) => {
|
||||||
|
ownerUser = _ownerUser;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ops.push(() => {
|
||||||
|
const authors = model.get('authors');
|
||||||
|
|
||||||
|
return Promise.each(authors, (author, index) => {
|
||||||
|
const query = {};
|
||||||
|
|
||||||
|
if (author.id) {
|
||||||
|
query.id = author.id;
|
||||||
|
} else if (author.slug) {
|
||||||
|
query.slug = author.slug;
|
||||||
|
} else if (author.email) {
|
||||||
|
query.email = author.email;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ghostBookshelf
|
||||||
|
.model('User')
|
||||||
|
.where(query)
|
||||||
|
.fetch(Object.assign({columns: ['id']}, _.pick(options, 'transacting')))
|
||||||
|
.then((user) => {
|
||||||
|
authors[index] = {};
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
authors[index].id = ownerUser.id;
|
||||||
|
} else {
|
||||||
|
authors[index].id = user.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
model.set('authors', authors);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return sequence(ops);
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
/**
|
/**
|
||||||
|
@ -20,7 +20,7 @@ describe('Authors Content API', function () {
|
|||||||
request = supertest.agent(config.get('url'));
|
request = supertest.agent(config.get('url'));
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return testUtils.initFixtures('users:no-owner', 'user:inactive', 'posts', 'api_keys');
|
return testUtils.initFixtures('owner:post', 'users:no-owner', 'user:inactive', 'posts', 'api_keys');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ describe('Posts Content API', function () {
|
|||||||
request = supertest.agent(config.get('url'));
|
request = supertest.agent(config.get('url'));
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return testUtils.initFixtures('users:no-owner', 'user:inactive', 'posts', 'tags:extra', 'api_keys');
|
return testUtils.initFixtures('owner:post', 'users:no-owner', 'user:inactive', 'posts', 'tags:extra', 'api_keys');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user