Skip to content

Commit aa49f77

Browse files
authored
🐛 Fixed url not being immediately available after post publish (#10361)
🐛 Fixed URL not being immediately available after post publish closes #10360 - This change makes sure posts and pages URLs are populated in synchronous manner - Further cleanup and restructuring of this hacky solution is planned to be done in #10360
1 parent be4eb57 commit aa49f77

File tree

2 files changed

+136
-41
lines changed

2 files changed

+136
-41
lines changed

core/server/services/url/Resources.js

Lines changed: 128 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -126,30 +126,94 @@ class Resources {
126126
return models.Base.Model.raw_knex.fetchAll(modelOptions);
127127
}
128128

129+
_prepareModelSync(model, resourceConfig) {
130+
const exclude = resourceConfig.modelOptions.exclude;
131+
const withRelatedFields = resourceConfig.modelOptions.withRelatedFields;
132+
const obj = _.omit(model.toJSON(), exclude);
133+
134+
if (withRelatedFields) {
135+
_.each(withRelatedFields, (fields, key) => {
136+
if (!obj[key]) {
137+
return;
138+
}
139+
140+
obj[key] = _.map(obj[key], (relation) => {
141+
const relationToReturn = {};
142+
143+
_.each(fields, (field) => {
144+
const fieldSanitized = field.replace(/^\w+./, '');
145+
relationToReturn[fieldSanitized] = relation[fieldSanitized];
146+
});
147+
148+
return relationToReturn;
149+
});
150+
});
151+
152+
const withRelatedPrimary = resourceConfig.modelOptions.withRelatedPrimary;
153+
154+
if (withRelatedPrimary) {
155+
_.each(withRelatedPrimary, (relation, primaryKey) => {
156+
if (!obj[primaryKey] || !obj[relation]) {
157+
return;
158+
}
159+
160+
const targetTagKeys = Object.keys(obj[relation].find((item) => {
161+
return item.id === obj[primaryKey].id;
162+
}));
163+
obj[primaryKey] = _.pick(obj[primaryKey], targetTagKeys);
164+
});
165+
}
166+
}
167+
168+
return obj;
169+
}
170+
129171
_onResourceAdded(type, model) {
172+
debug('_onResourceAdded', type);
173+
130174
const resourceConfig = _.find(this.resourcesConfig, {type: type});
131175

132-
return Promise.resolve()
133-
.then(() => {
134-
return this._fetchSingle(resourceConfig, model.id);
135-
})
136-
.then(([dbResource]) => {
137-
if (dbResource) {
138-
const resource = new Resource(type, dbResource);
139-
140-
debug('_onResourceAdded', type);
141-
this.data[type].push(resource);
142-
143-
this.queue.start({
144-
event: 'added',
145-
action: 'added:' + model.id,
146-
eventData: {
147-
id: model.id,
148-
type: type
149-
}
150-
});
176+
// NOTE: synchronous handling for post and pages so that their URL is available without a delay
177+
// for more context and future improvements check https://github.com/TryGhost/Ghost/issues/10360
178+
if (['posts', 'pages'].includes(type)) {
179+
const obj = this._prepareModelSync(model, resourceConfig);
180+
181+
const resource = new Resource(type, obj);
182+
183+
debug('_onResourceAdded', type);
184+
this.data[type].push(resource);
185+
186+
this.queue.start({
187+
event: 'added',
188+
action: 'added:' + model.id,
189+
eventData: {
190+
id: model.id,
191+
type: type
151192
}
152193
});
194+
} else {
195+
return Promise.resolve()
196+
.then(() => {
197+
return this._fetchSingle(resourceConfig, model.id);
198+
})
199+
.then(([dbResource]) => {
200+
if (dbResource) {
201+
const resource = new Resource(type, dbResource);
202+
203+
debug('_onResourceAdded', type);
204+
this.data[type].push(resource);
205+
206+
this.queue.start({
207+
event: 'added',
208+
action: 'added:' + model.id,
209+
eventData: {
210+
id: model.id,
211+
type: type
212+
}
213+
});
214+
}
215+
});
216+
}
153217
}
154218

155219
/**
@@ -171,36 +235,67 @@ class Resources {
171235

172236
const resourceConfig = _.find(this.resourcesConfig, {type: type});
173237

174-
return Promise.resolve()
175-
.then(() => {
176-
return this._fetchSingle(resourceConfig, model.id);
177-
})
178-
.then(([dbResource]) => {
179-
const resource = this.data[type].find(resource => (resource.data.id === model.id));
238+
// NOTE: synchronous handling for post and pages so that their URL is available without a delay
239+
// for more context and future improvements check https://github.com/TryGhost/Ghost/issues/10360
240+
if (['posts', 'pages'].includes(type)) {
241+
this.data[type].every((resource) => {
242+
if (resource.data.id === model.id) {
243+
const obj = this._prepareModelSync(model, resourceConfig);
180244

181-
if (resource && dbResource) {
182-
resource.update(dbResource);
245+
resource.update(obj);
183246

184247
// CASE: pretend it was added
185248
if (!resource.isReserved()) {
186249
this.queue.start({
187250
event: 'added',
188-
action: 'added:' + dbResource.id,
251+
action: 'added:' + model.id,
189252
eventData: {
190-
id: dbResource.id,
253+
id: model.id,
191254
type: type
192255
}
193256
});
194257
}
195-
} else if (!resource && dbResource) {
196-
this._onResourceAdded(type, model);
197-
} else if (resource && !dbResource) {
198-
this._onResourceRemoved(type, model);
258+
259+
// break!
260+
return false;
199261
}
262+
263+
return true;
200264
});
265+
} else {
266+
return Promise.resolve()
267+
.then(() => {
268+
return this._fetchSingle(resourceConfig, model.id);
269+
})
270+
.then(([dbResource]) => {
271+
const resource = this.data[type].find(resource => (resource.data.id === model.id));
272+
273+
if (resource && dbResource) {
274+
resource.update(dbResource);
275+
276+
// CASE: pretend it was added
277+
if (!resource.isReserved()) {
278+
this.queue.start({
279+
event: 'added',
280+
action: 'added:' + dbResource.id,
281+
eventData: {
282+
id: dbResource.id,
283+
type: type
284+
}
285+
});
286+
}
287+
} else if (!resource && dbResource) {
288+
this._onResourceAdded(type, model);
289+
} else if (resource && !dbResource) {
290+
this._onResourceRemoved(type, model);
291+
}
292+
});
293+
}
201294
}
202295

203296
_onResourceRemoved(type, model) {
297+
debug('_onResourceRemoved', type);
298+
204299
let index = null;
205300
let resource;
206301

core/test/unit/services/url/Resources_spec.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,13 @@ describe('Unit: services/url/Resources', function () {
114114
obj.tags.length.should.eql(1);
115115

116116
// FIXME: these fields should correspond to configuration values in withRelatedFields
117-
Object.keys(obj.tags[0]).sort().should.eql(['id', 'post_id', 'slug', 'visibility'].sort());
117+
Object.keys(obj.tags[0]).sort().should.eql(['id', 'slug'].sort());
118118
obj.authors.length.should.eql(1);
119-
Object.keys(obj.authors[0]).sort().should.eql(['id', 'post_id', 'slug'].sort());
119+
Object.keys(obj.authors[0]).sort().should.eql(['id', 'slug'].sort());
120120
should.exist(obj.primary_author);
121-
Object.keys(obj.primary_author).sort().should.eql(['id', 'post_id', 'slug'].sort());
121+
Object.keys(obj.primary_author).sort().should.eql(['id', 'slug'].sort());
122122
should.exist(obj.primary_tag);
123-
Object.keys(obj.primary_tag).sort().should.eql(['id', 'post_id', 'slug', 'visibility'].sort());
123+
Object.keys(obj.primary_tag).sort().should.eql(['id', 'slug'].sort());
124124
done();
125125
});
126126

@@ -211,13 +211,13 @@ describe('Unit: services/url/Resources', function () {
211211
].sort());
212212

213213
should.exist(obj.tags);
214-
Object.keys(obj.tags[0]).sort().should.eql(['id', 'post_id', 'slug', 'visibility'].sort());
214+
Object.keys(obj.tags[0]).sort().should.eql(['id', 'slug'].sort());
215215
should.exist(obj.authors);
216-
Object.keys(obj.authors[0]).sort().should.eql(['id', 'post_id', 'slug'].sort());
216+
Object.keys(obj.authors[0]).sort().should.eql(['id', 'slug'].sort());
217217
should.exist(obj.primary_author);
218-
Object.keys(obj.primary_author).sort().should.eql(['id', 'post_id', 'slug'].sort());
218+
Object.keys(obj.primary_author).sort().should.eql(['id', 'slug'].sort());
219219
should.exist(obj.primary_tag);
220-
Object.keys(obj.primary_tag).sort().should.eql(['id', 'post_id', 'slug', 'visibility'].sort());
220+
Object.keys(obj.primary_tag).sort().should.eql(['id', 'slug'].sort());
221221

222222
done();
223223
});

0 commit comments

Comments
 (0)