Backend Pagebuilder Controller + Request Classes
Some checks are pending
linter / quality (push) Waiting to run
tests / ci (push) Waiting to run

This commit is contained in:
Helge-Mikael Nordgård 2025-05-05 15:30:43 +02:00
parent 60dc53b7ca
commit b1e031376f
7 changed files with 540 additions and 0 deletions

View File

@ -0,0 +1,341 @@
<?php
namespace App\Http\Controllers\Backend;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Inertia\Inertia;
use App\Http\Requests\Backend\PageBuilder\IndexRequest;
use App\Http\Requests\Backend\PageBuilder\CreateRequest;
use App\Http\Requests\Backend\PageBuilder\EditRequest;
use App\Http\Requests\Backend\PageBuilder\DeleteRequest;
use App\Http\Requests\Backend\PageBuilder\PreviewRequest;
use App\Http\Requests\Backend\PageBuilder\SetActiveRequest;
use App\Models\PageRevision;
use App\Models\ImageNode;
use App\Models\Page;
use App\Helpers\PageBlocksHelper;
class PageBuilder extends Controller
{
public function index(IndexRequest $request) {
$pages = Page::with(['author', 'activeRevision'])->withCount('revisions')->get();
return Inertia::render('Backend/PageBuilder/Index', [
'builtPages' => $pages->map(function ($page) {
return [
'id' => $page->id,
'uuid' => $page->uuid,
'title' => $page->title,
'slug' => $page->slug,
'content' => $page->content,
'revisions_count' => $page->revisions_count,
'author' => [
'id' => $page->author->id,
'name' => $page->author->name,
],
'activeRevision' => $page->activeRevision ? [
'uuid' => $page->activeRevision->uuid,
'version' => $page->activeRevision->version,
] : null
];
}),
]);
}
public function createLandingPage(CreateRequest $request) {
$imagesNodes = ImageNode::all();
return Inertia::render('Backend/PageBuilder/Create', [
'images' => $imagesNodes
]);
}
public function storeLandingPage(CreateRequest $request) {
$data = $request->validated();
// Initiate slug duplication detection
$baseSlug = Str::slug($data['title']);
$slug = $baseSlug;
$suffix = 1;
while (Page::where('slug', $slug)->exists()) {
$slug = $baseSlug . '-' . $suffix++;
}
// If this page should be the main page, unset main on others
if ($data['mainpage']) {
Page::where('main', true)->update(['main' => false]);
}
// Check if user has permission to publish a page
$publish = false;
$user = Auth::user();
if ($user->hasRole('supervisor') || $user->hasRole('board')) {
$publish = $data['publish'];
}
$page = Page::create([
'uuid' => Str::uuid(),
'user_id' => Auth::id(),
'title' => $data['title'],
'slug' => $slug,
'content' => $data['content'],
'is_published' => $publish,
'main' => $data['mainpage'],
'linked' => $data['linked'],
'linkorder' => $data['linkorder'],
'visibility' => $data['visibility'],
]);
$rev = PageRevision::create([
'page_id' => $page->id,
'user_id' => Auth::id(),
'title' => $page->title,
'slug' => $page->slug,
'content' => $page->content,
'label' => $page->is_published ? 'published' : 'manual-save',
'active' => true
]);
return to_route('page-builder.builder.edit', ['pageVersion' => $rev->uuid]);
}
public function deleteLandingPage(DeleteRequest $request) {
$page = Page::findOrFail($request->id);
// Check if the user is the owner of the page
if (!Auth::user()->hasRole('supervisor') || !Auth::user()->hasRole('board')) {
if (Auth::user()->id != $page->user_id) {
return to_route('page-builder.index')
->with('error', "Du er ikke forfatteren av denne siden og kan derfor ikke slette den.");
}
}
$page->delete();
return to_route('page-builder.index')->with('warning', 'Siden ble slettet.');
}
public function editLandingPage(EditRequest $request, PageRevision $pageVersion) {
$revision = $pageVersion->load(['page.revisions.editor', 'editor']);
$images = ImageNode::all();
$pageRevisions = $revision->page->revisions->map(function ($rev) {
return [
'id' => $rev->id,
'title' => $rev->title,
'uuid' => $rev->uuid,
'version' => $rev->version,
'active' => $rev->active,
'created_at'=> $rev->created_at,
'updated_at'=> $rev->updated_at,
'author' => [
'name' => $rev->editor->name,
'email' => $rev->editor->email
]
];
});
return Inertia::render('Backend/PageBuilder/Edit', [
'revision' => [
'id' => $revision->id,
'uuid' => $revision->uuid,
'version' => $revision->version,
'title' => $revision->title,
'slug' => $revision->slug,
'label' => $revision->label,
'active' => $revision->active,
'content' => $revision->content,
'page' => [
'id' => $revision->page->id,
'uuid' => $revision->page->uuid,
'is_published'=> $revision->page->is_published,
'main' => $revision->page->main,
'linked' => $revision->page->linked,
'linkorder' => $revision->page->linkorder,
'visibility' => $revision->page->visibility,
]
],
'images' => $images,
'revisions' => $pageRevisions
]);
}
public function patchLandingPage(EditRequest $request) {
$data = $request->validated();
// Load the revision by uuid
$revision = PageRevision::where('uuid', $request->input('revision_uuid'))
->with('page')
->firstOrFail();
// Check if the user is the owner of the current revision
if (!Auth::user()->hasRole('supervisor') || !Auth::user()->hasRole('board')) {
if (Auth::user()->id != $revision->user_id) {
return to_route('page-builder.builder.edit', ['pageVersion' => $revision->uuid])
->with('info', "Du er ikke forfatteren av denne revisjonen og kan derfor ikke gjøre endringer til den. Hvis du ønsker å gjøre endringer, lagre denne revisjonen som en ny versjon.");
}
}
// If this page should be the main page, unset main on others
if ($data['mainpage']) {
Page::where('main', true)->where('id', '!=', $revision->page_id)->update(['main' => false]);
}
// Check if user can publish
$canPublish = Auth::user()->hasRole('supervisor') || Auth::user()->hasRole('board');
$publish = $canPublish ? $data['publish'] : false;
if ($revision->active) {
// Initiate slug duplication detection
$baseSlug = Str::slug($data['title']);
$slug = $baseSlug;
$suffix = 1;
// ONly update slug if it has changed
if ($baseSlug !== $revision->page->slug) {
while (Page::where('slug', $slug)->where('id', '!=', $revision->page_id)->exists()) {
$slug = $baseSlug . '-' . $suffix++;
}
} else {
$slug = $revision->page->slug;
}
// Update the base page model if the current revision is set to active
$revision->page->update([
'title' => $data['title'],
'slug' => $slug,
'content' => $data['content'],
'is_published' => $publish,
'main' => $data['mainpage'],
'linked' => $data['linked'],
'linkorder' => $data['linkorder'],
'visibility' => $data['visibility'],
]);
}
// Update the current revision directly
$revision->update([
'title' => $data['title'],
'slug' => Str::slug($data['title']),
'content' => $data['content'],
'label' => $publish ? 'published' : 'manual-save',
]);
if ($request->has('autosave') && $request->input('autosave')) {
return to_route('page-builder.builder.edit', ['pageVersion' => $revision->uuid])
->with('info', 'Endringer lagret automatisk.');
}
return to_route('page-builder.builder.edit', ['pageVersion' => $revision->uuid])
->with('success', 'Endringer ble lagret i nåværende revisjon.');
}
public function saveAsLandingPage(CreateRequest $request) {
$data = $request->validated();
$page = Page::findOrFail($request->page_id);
$revision = PageRevision::create([
'page_id' => $page->id,
'user_id' => Auth::id(),
'title' => $data['title'],
'slug' => Str::slug($data['title']),
'content' => $data['content'],
'label' => 'manual-save',
'active' => false
]);
return to_route('page-builder.builder.edit', ['pageVersion' => $revision->uuid])
->with('success', "Ny versjon (v. {$revision->version}) opprettet.");
}
public function setLandingPageRevisionActive(SetActiveRequest $request) {
$revision = PageRevision::where('uuid', $request->input('revision_uuid'))->firstOrFail();
if (!Auth::user()->hasRole('supervisor')) {
if (!Auth::user()->hasRole('board')) {
return to_route('page-builder.builder.edit', ['pageVersion' => $revision->uuid])
->with('error', "Du mangler tillatelse til å sette denne revisjonen som aktiv");
}
}
$data = $request->validated();
$page = $revision->page;
PageRevision::where('active', true)->where('page_id', '=', $page->id)->update(['active' => false]);
$revision->active = true;
$revision->save();
// Initiate slug duplication detection
$baseSlug = Str::slug($data['title']);
$slug = $baseSlug;
$suffix = 1;
while (Page::where('slug', $slug)->exists()) {
$slug = $baseSlug . '-' . $suffix++;
}
$page->title = $data['title'];
$page->slug = $slug;
$page->content = $data['content'];
$page->is_published = false;
$page->save;
return to_route('page-builder.builder.edit', ['pageVersion' => $revision->uuid])
->with('success', "Versjon {$revision->version} satt som innhold til siden.");
}
public function preview(PreviewRequest $request, PageRevision $pageVersion) {
$revision = $pageVersion->load(['page', 'editor']);
$images = ImageNode::all();
$neededFetchers = collect();
$blocks = json_decode($revision->content, true);
foreach ($blocks as $block) {
if (!empty($block['needs'])) {
$neededFetchers = $neededFetchers->merge($block['needs']);
}
}
$neededFetchers = $neededFetchers->unique();
$blockData = [];
foreach ($neededFetchers as $fetcher) {
if (method_exists(PageBlocksHelper::class, $fetcher)) {
$blockData[$fetcher] = PageBlocksHelper::$fetcher();
}
}
return Inertia::render('Backend/PageBuilder/Preview', [
'revision' => [
'id' => $revision->id,
'uuid' => $revision->uuid,
'version' => $revision->version,
'title' => $revision->title,
'slug' => $revision->slug,
'label' => $revision->label,
'active' => $revision->active,
'content' => json_decode($revision->content, true),
'page' => [
'id' => $revision->page->id,
'uuid' => $revision->page->uuid,
'is_published'=> $revision->page->is_published,
'main' => $revision->page->main,
'visibility' => $revision->page->visibility,
]
],
'images' => $images,
'blockData' => $blockData,
'menuLinks' => PageBlocksHelper::mainMenuLinks()
]);
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Http\Requests\Backend\PageBuilder;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class CreateRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool {
if (Auth::check())
return true;
return false;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array {
if ($this->isMethod('get'))
return [];
return [
'title' => ['required', 'string', 'max:255'],
'content' => ['required', 'json'],
'publish' => ['required', 'boolean'],
'mainpage' => ['required', 'boolean'],
'linked' => ['required', 'boolean'],
'linkorder' => ['required', 'between:0,20'],
'visibility' => ['required', 'in:public,private'],
];
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Backend\PageBuilder;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class DeleteRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool {
if (Auth::check())
return true;
return false;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array {
return [
//
];
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Http\Requests\Backend\PageBuilder;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class EditRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool {
if (Auth::check())
return true;
return false;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array {
if ($this->isMethod('get'))
return [];
return [
'title' => ['required', 'string', 'max:255'],
'content' => ['required', 'json'],
'publish' => ['required', 'boolean'],
'mainpage' => ['required', 'boolean'],
'linked' => ['required', 'boolean'],
'linkorder' => ['required', 'between:0,20'],
'visibility' => ['required', 'in:public,private'],
];
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Backend\PageBuilder;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class IndexRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool {
if (Auth::check())
return true;
return false;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array {
return [
//
];
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Backend\PageBuilder;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class PreviewRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool {
if (Auth::check())
return true;
return false;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array {
return [
//
];
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Backend\PageBuilder;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class SetActiveRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool {
if (Auth::check())
return true;
return false;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array {
return [
'title' => ['required', 'string', 'max:255'],
'content' => ['required', 'json']
];
}
}