Commit 8492702
Check if existing base path is associated with same content ID
WHAT
This commit adds logic at the point of saving a draft to
Publishing API. The logic checks whether the base path being
saved to already has a live document at the end of it, and if
so, if that document's content ID matches what we're sending.
If it doesn't match, then that indicates that a different
document (in Whitehall, or originating from another app) already
owns the route and we've ended up in the not great situation of
having allocated a slug that already exists. We raise an
exception in this case, which is better than proceeding and
letting the document silently overwrite an existing one.
The lookup only checks for _published_ documents, as we haven't
passed the `with_drafts: true` keyword arg. This is deliberate
as we wouldn't want a situation of a publisher creating a draft
document Foo, deleting it, then going and creating another draft
document Foo and seeing an error on save. We only care about
base paths that are already live. This does mean there could
be an edge case where two draft documents have the same slug
and we only get the exception when trying to save the second
one after publishing the first one, but that seems a very low
likelihood edge case.
Note also that this logic change depends on Whitehall always
saving drafts via the `Whitehall::PublishingApi` helper module.
There are a few cases where Whitehall updates Publishing API
outside of this module (by making calls to
`Services.publishing_api.save_draft` instead), but these all
seem to be for index pages and the like, where the content ID
is always fixed, so refactoring the Publishing API calls to
all go through the helper module is outside of the scope of this
change.
WHY
It has long been possible for Whitehall to create a draft which
has the same base path (`/government/foo`) as an already live
page that was published by another publishing app. The draft has
been previewable, and it's even been possible to schedule the
draft for publication. Only at the point of Whitehall making a
'publish' call to Publishing API - either manually via the UI, or
via the scheduled publishing worker - would Publishing API then
raise an exception and cause Whitehall to raise a
`Whitehall::UnpublishableInstanceError`.
Historically this hasn't caused too many issues, except for
occasional news article clashes with the now retired Content
Publisher application. Most publishing apps publish different
content types with different base path prefixes, thus there is
never usually a conflict.
_Internal_ base path conflicts - where Whitehall alone is responsible
for producing two different documents under the same base path -
have so far been avoided by a uniqueness constraint on the
Document table, ensuring that every slug is unique amongst other
slugs of the same document type:
https://github.com/alphagov/whitehall/blob/e024e2eea25ca9cb48a8a98d2298aaea1df13b92/db/schema.rb#L241
This uniqueness constraint only works on the assumption that every
document type has a distinct base path prefix (e.g.
`/government/news` for NewsArticle, `/government/consultations`
for Consultation, and so on). That assumption no longer holds true
as we are gradually migrating content types to use the same shared
StandardEdition model (with a dynamic base path prefix based on the
`configurable_document_type` of the Edition).
The consequence of this is that one may have a legacy NewsArticle
with generated base path `/government/news/foo` and a StandardEdition
document with generated base path `/government/news/foo`, and the
uniqueness constraint passes because both are of different document
types.
There are several problems to solve here:
1. A newer StandardEdition document might silently overwrite an
older legacy Edition which has the same base path.
2. Our slug enumeration logic (that automatically appends `--1`
in the event of a clash) does not apply across document types.
3. Even if the slug enumeration logic DID apply, that wouldn't be
desirable. It should be allowable to have a stanard-edition
flavoured news article of path `/government/news/foo` alongside
a standard-edition flavoured consultation of path
`/government/consultations/foo` without one of them being relegated
the slug `foo--1`.
The first and most important problem is the silent overwriting.
These cases are (currently) very few and far between, and the best
approach is to capture it as an exception where we can help the
user out as a support task. Further down the line we can capture
the exception and give the user an actionable error message instead
(i.e. to change their title), or potentially explore enumerating the
slug to avoid conflicts automatically.
We'll need to think about whether the uniqueness constraint index
is still valuable or whether this dynamic lookup of Publishing API
content items is a sufficient replacement.
Jira: https://gov-uk.atlassian.net/browse/WHIT-18421 parent bc083e1 commit 8492702
4 files changed
Lines changed: 44 additions & 1 deletion
File tree
- features/support
- lib/whitehall
- test
- unit/lib/whitehall
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| 22 | + | |
| 23 | + | |
22 | 24 | | |
23 | 25 | | |
24 | 26 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
69 | 69 | | |
70 | 70 | | |
71 | 71 | | |
| 72 | + | |
| 73 | + | |
72 | 74 | | |
73 | 75 | | |
74 | 76 | | |
| |||
178 | 180 | | |
179 | 181 | | |
180 | 182 | | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
181 | 190 | | |
182 | 191 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
| 79 | + | |
| 80 | + | |
79 | 81 | | |
80 | 82 | | |
81 | 83 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
274 | 274 | | |
275 | 275 | | |
276 | 276 | | |
277 | | - | |
| 277 | + | |
278 | 278 | | |
279 | 279 | | |
280 | 280 | | |
| 281 | + | |
| 282 | + | |
281 | 283 | | |
282 | 284 | | |
283 | 285 | | |
284 | 286 | | |
285 | 287 | | |
286 | 288 | | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
287 | 317 | | |
288 | 318 | | |
289 | 319 | | |
| |||
0 commit comments