diff --git a/ghost/core/core/server/api/endpoints/users.js b/ghost/core/core/server/api/endpoints/users.js index 451a609eac..5fd7625d3e 100644 --- a/ghost/core/core/server/api/endpoints/users.js +++ b/ghost/core/core/server/api/endpoints/users.js @@ -40,6 +40,39 @@ async function fetchOrCreatePersonalToken(userId) { return token; } +function shouldInvalidateCacheAfterChange(model) { + // Model attributes that should trigger cache invalidation when changed + // (because they affect the frontend) + const publicAttrs = [ + 'name', + 'slug', + 'profile_image', + 'cover_image', + 'bio', + 'website', + 'location', + 'facebook', + 'twitter', + 'status', + 'visibility', + 'meta_title', + 'meta_description' + ]; + + if (model.wasChanged() === false) { + return false; + } + + // Check if any of the changed attributes are public + for (const attr of Object.keys(model._changed)) { + if (publicAttrs.includes(attr) === true) { + return true; + } + } + + return false; +} + module.exports = { docName: 'users', @@ -137,11 +170,7 @@ module.exports = { })); } - if (model.wasChanged()) { - this.headers.cacheInvalidate = true; - } else { - this.headers.cacheInvalidate = false; - } + this.headers.cacheInvalidate = shouldInvalidateCacheAfterChange(model); return model; }); diff --git a/ghost/core/test/e2e-api/admin/users.test.js b/ghost/core/test/e2e-api/admin/users.test.js index f4de80a390..bc12b02a5a 100644 --- a/ghost/core/test/e2e-api/admin/users.test.js +++ b/ghost/core/test/e2e-api/admin/users.test.js @@ -274,6 +274,36 @@ describe('User API', function () { jsonResponse.users[0].roles[0].name.should.equal('Administrator'); }); + it('Does not trigger cache invalidation when a private attribute on a user has been changed', async function () { + const res = await request.put(localUtils.API.getApiQuery('users/me/')) + .set('Origin', config.get('url')) + .send({ + users: [{ + comment_notifications: false + }] + }) + .expect('Content-Type', /json/) + .expect('Cache-Control', testUtils.cacheRules.private) + .expect(200); + + should.equal(res.headers['x-cache-invalidate'], undefined); + }); + + it('Does not trigger cache invalidation when no attribute on a user has been changed', async function () { + const res = await request.put(localUtils.API.getApiQuery('users/me/')) + .set('Origin', config.get('url')) + .send({ + users: [{ + facebook: null + }] + }) + .expect('Content-Type', /json/) + .expect('Cache-Control', testUtils.cacheRules.private) + .expect(200); + + should.equal(res.headers['x-cache-invalidate'], undefined); + }); + it('Can destroy an active user and transfer posts to the owner', async function () { const userId = testUtils.getExistingData().users[1].id; const userSlug = testUtils.getExistingData().users[1].slug;