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:
74
app/Http/Controllers/Api/V1/RevisionController.php
Normal file
74
app/Http/Controllers/Api/V1/RevisionController.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Concerns\ResolvesContent;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\RevisionResource;
|
||||
use App\Models\Revision;
|
||||
use App\Support\AdminContent;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
/**
|
||||
* A record's history: who changed what and when, and undoing one change.
|
||||
*/
|
||||
class RevisionController extends Controller
|
||||
{
|
||||
use ResolvesContent;
|
||||
|
||||
/**
|
||||
* Newest first. Filter: event.
|
||||
*/
|
||||
public function index(Request $request): AnonymousResourceCollection
|
||||
{
|
||||
$record = $this->record($request);
|
||||
|
||||
$this->authorize('view', $record);
|
||||
|
||||
$revisions = $record->revisions()
|
||||
->with('user')
|
||||
->when($request->filled('event'), fn ($q) => $q->where('event', $request->string('event')))
|
||||
->paginate(perPage: min($request->integer('per_page', 25), 100))
|
||||
->withQueryString();
|
||||
|
||||
return RevisionResource::collection($revisions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put back what one revision changed, as the panel's history does.
|
||||
* Restoring is itself a change, so it lands in the history too — the way
|
||||
* back is never lost.
|
||||
*/
|
||||
public function restore(Request $request, Revision $revision): RevisionResource
|
||||
{
|
||||
$model = Relation::getMorphedModel($revision->revisionable_type) ?? $revision->revisionable_type;
|
||||
$record = AdminContent::findOf($model, $revision->revisionable_id);
|
||||
|
||||
$this->authorize('update', $record);
|
||||
|
||||
$values = $revision->previousValues();
|
||||
|
||||
if ($values === []) {
|
||||
throw ValidationException::withMessages(['revision' => [__('rules.revisions.nothing_to_restore')]]);
|
||||
}
|
||||
|
||||
// Undoing a change can publish or unpublish, and that stays with whoever
|
||||
// may publish.
|
||||
$guarded = array_intersect(array_keys($values), AdminContent::publicationFields($record));
|
||||
|
||||
if ($guarded !== [] && $request->user()->cannot($record->getTable().'.publish')) {
|
||||
throw ValidationException::withMessages(['revision' => [__('rules.publication.forbidden')]]);
|
||||
}
|
||||
|
||||
// Only what the model lets a form write: a revision may mention
|
||||
// bookkeeping columns, and those are not anybody's to put back.
|
||||
$record->forceFill(array_intersect_key($values, array_flip($record->getFillable())))->save();
|
||||
|
||||
return RevisionResource::make($record->revisions()->with('user')->first());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user