Review, publish, preview and undo changes through the API

Revisions now call publishing only what publishes: a project's status is
whether the work is active, and a service is published by its flag.

The fake identity server answers by token, so a test can sign in a second
person.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 08:29:48 +02:00
parent 4c4a2b3299
commit 5b46436641
18 changed files with 1899 additions and 13 deletions

View File

@@ -20,9 +20,12 @@ use App\Http\Controllers\Api\V1\MediaController;
use App\Http\Controllers\Api\V1\MemberController;
use App\Http\Controllers\Api\V1\MissingUrlController;
use App\Http\Controllers\Api\V1\PageController;
use App\Http\Controllers\Api\V1\PreviewController;
use App\Http\Controllers\Api\V1\ProjectController;
use App\Http\Controllers\Api\V1\RedirectController;
use App\Http\Controllers\Api\V1\RepositoryController;
use App\Http\Controllers\Api\V1\ReviewController;
use App\Http\Controllers\Api\V1\RevisionController;
use App\Http\Controllers\Api\V1\RoleController;
use App\Http\Controllers\Api\V1\ServiceController;
use App\Http\Controllers\Api\V1\SettingController;
@@ -31,6 +34,7 @@ use App\Http\Controllers\Api\V1\TechnologyController;
use App\Http\Controllers\Api\V1\TestimonialController;
use App\Http\Controllers\Api\V1\TokenController;
use App\Http\Controllers\Api\V1\UserController;
use App\Support\AdminContent;
use Illuminate\Support\Facades\Route;
/*
@@ -226,6 +230,44 @@ Route::prefix('v1')->name('api.v1.')->group(function () {
Route::put('maintenance', [MaintenanceController::class, 'update'])->name('maintenance.update');
Route::apiResource('settings', SettingController::class)->only(['index', 'show', 'update']);
// History, review and preview, for the kinds of content that have
// them. Each route says which kind through `content`, so one
// controller serves them all and the specification still names each.
foreach (AdminContent::WITH_HISTORY as $resource => [, $parameter]) {
Route::get("{$resource}/{{$parameter}}/revisions", [RevisionController::class, 'index'])
->defaults('content', $resource)
->name("{$resource}.revisions");
}
Route::post('revisions/{revision}/restore', [RevisionController::class, 'restore'])->name('revisions.restore');
Route::get('reviews', [ReviewController::class, 'queue'])->name('reviews.queue');
foreach (array_keys(AdminContent::REVIEWABLE) as $resource) {
$parameter = AdminContent::parameter($resource);
foreach ([
['get', 'reviews', 'thread'],
['post', 'comments', 'comment'],
['post', 'review', 'request'],
['post', 'return', 'return'],
['post', 'publish', 'publish'],
['post', 'unpublish', 'unpublish'],
] as [$method, $suffix, $action]) {
Route::{$method}("{$resource}/{{$parameter}}/{$suffix}", [ReviewController::class, $action])
->defaults('content', $resource)
->name("{$resource}.review.{$action}");
}
}
foreach (array_keys(AdminContent::PREVIEWABLE) as $resource) {
$parameter = AdminContent::parameter($resource);
Route::post("{$resource}/{{$parameter}}/preview", [PreviewController::class, 'store'])
->defaults('content', $resource)
->name("{$resource}.preview");
}
// The library. A file is uploaded here and then referenced from a
// record by its path; it is never edited, only processed again.
Route::get('media', [MediaController::class, 'index'])->name('media.index');