Skip to content

show-or-create for pages#5115

Closed
cod3monk wants to merge 0 commit intoBookStackApp:developmentfrom
cod3monk:development
Closed

show-or-create for pages#5115
cod3monk wants to merge 0 commit intoBookStackApp:developmentfrom
cod3monk:development

Conversation

@cod3monk
Copy link

This PR adds two new routes:
/books/{bookSlug}/show-or-create?name={pageSlug} and
/books/{bookSlug}/chapter/{chapterSlug}/show-or-create?name={pageSlug}

The concept is, that with these URL a user will either drop into the edit view of a new Page, or -if the page already exists- be redirected to the page itself.

This solves the feature request mentioned in #5099.

@cod3monk cod3monk changed the title show-or-create for pages. implements a solution to #5099 show-or-create for pages Jul 11, 2024
@ssddanbrown
Copy link
Member

Thanks for offering this @cod3monk, but I'm really not keen on maintaining & supporting new endpoints that are built/intended for specific external business processes.

These kinds of additions would be a good use case of using the logical theme system to add your own endpoints as somewhat reflected here, which would allow you to add these custom endpoints to your own instance without altering core app code.

@cod3monk
Copy link
Author

Would you be willing to include a ?createIfNotFound property in the show endpoints to redirect to an edit view on NotFoundException?

I am working on porting the endpoint to the logical theme system, which turns out to be rather tedious. Due to a lack of understanding of the Facades and thus how to port my original showOrCreate PageController. Documentation seems to be very sparse or too abstract on bookstack and laravel side.

@ssddanbrown
Copy link
Member

ssddanbrown commented Jul 19, 2024

Would you be willing to include a ?createIfNotFound property in the show endpoints to redirect to an edit view on NotFoundException?

No.

Here's my take on a port of your changes to a logical theme function.php file (tested on my dev instance which is pretty much matching the current release in terms of back-end logic):

functions.php

<?php

use BookStack\Entities\Queries\EntityQueries;
use BookStack\Entities\Repos\PageRepo;
use BookStack\Exceptions\NotFoundException;
use BookStack\Facades\Theme;
use BookStack\Http\Controller;
use BookStack\Theming\ThemeEvents;
use Illuminate\Http\Request;
use Illuminate\Routing\Router;

class CustomPageActionsController extends Controller
{
    public function __construct(
        protected PageRepo $pageRepo,
        protected EntityQueries $entityQueries,
    ) {
    }

    /**
     * If page exists, redirect to show page, otherwise to create page
     */
    public function showOrCreate(Request $request, string $bookSlug, string $chapterSlug = null)
    {
        $data = $this->validate($request, [
            'name' => ['required', 'string', 'max:255'],
        ]);

        $pageName = $data['name'];

        try {
            // Redirect to the page if an existing page is found
            $page = $this->entityQueries->pages->findVisibleBySlugsOrFail($bookSlug, $pageName);
            return redirect($page->getUrl());
        } catch (NotFoundException $e) {
            // Otherwise create a new page and start editing it
            if ($chapterSlug) {
                $parent = $this->entityQueries->chapters->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
            } else {
                $parent = $this->entityQueries->books->findVisibleBySlugOrFail($bookSlug);
            }

            $this->checkOwnablePermission('page-create', $parent);

            $page = $this->pageRepo->getNewDraftPage($parent);
            $this->pageRepo->publishDraft($page, [
                'name' => $pageName,
            ]);

            return redirect($page->getUrl('/edit'));
        }
    }
}

// Register the routes for our custom controller & action
Theme::listen(ThemeEvents::ROUTES_REGISTER_WEB_AUTH, function (Router $router) {
    $router->get('/books/{bookSlug}/show-or-create', [CustomPageActionsController::class, 'showOrCreate']);
    $router->get('/books/{bookSlug}/chapter/{chapterSlug}/show-or-create', [CustomPageActionsController::class, 'showOrCreate']);
});

I've made changes to the method code but the general logic/routes/endpoints/request-data should be the same with the desired overall output.

@cod3monk
Copy link
Author

Thanks! Code-wise I had almost the same, but it was missing some of the use imports, thus running into using Facade versions of the same objects and not catching the correct NotFoundException.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants