Update existing draft articles instead of erroring on a repeat Micropub post

If a Micropub h-entry post's title matches an existing article that's
still a draft, update that article in place rather than trying to
insert a duplicate. If it matches one that's already published,
reject the request with a clear error instead of silently colliding.

Also set includeTrashed on Article's slug config as a safety net: this
model soft-deletes, and Sluggable's uniqueness check ignores trashed
rows by default, so a previously-deleted article's title could crash
new inserts with a raw unique constraint violation (this is exactly
what surfaced in Flare as a UniqueConstraintViolationException on
articles_titleurl_unique once the prior swallowed-exception fix
shipped).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Jonny Barnes 2026-09-19 17:16:11 +01:00
commit eb35a0aa2d
Signed by: jonny
SSH key fingerprint: SHA256:CTuSlns5U7qlD9jqHvtnVmfYV3Zwl2Z7WnJ4/dqOaL8
4 changed files with 92 additions and 2 deletions

View file

@ -8,12 +8,29 @@ use App\Models\Article;
class ArticleService
{
/**
* @throws \InvalidArgumentException if a published article already has this title
*/
public function create(array $data): Article
{
return Article::create([
$attributes = [
'title' => $data['name'],
'main' => $data['content'],
'published' => ($data['post-status'] ?? null) !== 'draft',
]);
];
$existing = Article::where('title', $data['name'])->first();
if ($existing !== null) {
if ($existing->published) {
throw new \InvalidArgumentException("An article titled \"{$data['name']}\" has already been published");
}
$existing->update($attributes);
return $existing;
}
return Article::create($attributes);
}
}