--- /dev/null
+<?php
+
+namespace BookStack\Http\Controllers;
+
+use BookStack\Auth\Permissions\PermissionApplicator;
+use BookStack\Entities\Models\Page;
+use Illuminate\Database\Eloquent\Relations\Relation;
+
+class ReferenceController extends Controller
+{
+
+ protected PermissionApplicator $permissions;
+
+ public function __construct(PermissionApplicator $permissions)
+ {
+ $this->permissions = $permissions;
+ }
+
+ /**
+ * Display the references to a given page.
+ */
+ public function page(string $bookSlug, string $pageSlug)
+ {
+ /** @var Page $page */
+ $page = Page::visible()->whereSlugs($bookSlug, $pageSlug)->firstOrFail();
+
+ $baseQuery = $page->referencesTo()
+ ->where('from_type', '=', (new Page())->getMorphClass())
+ ->with([
+ 'from' => fn(Relation $query) => $query->select(Page::$listAttributes),
+ 'from.book' => fn(Relation $query) => $query->scopes('visible'),
+ 'from.chapter' => fn(Relation $query) => $query->scopes('visible')
+ ]);
+
+ $references = $this->permissions->restrictEntityRelationQuery(
+ $baseQuery,
+ 'references',
+ 'from_id',
+ 'from_type'
+ )->get();
+
+ return view('pages.references', [
+ 'page' => $page,
+ 'references' => $references,
+ ]);
+ }
+}
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5.67s.74 2.65.74 4.8c0 2.06-1.35 3.73-3.41 3.73-2.07 0-3.63-1.67-3.63-3.73l.03-.36C5.21 7.51 4 10.62 4 14c0 4.42 3.58 8 8 8s8-3.58 8-8C20 8.61 17.41 3.8 13.5.67zM11.71 19c-1.78 0-3.22-1.4-3.22-3.14 0-1.62 1.05-2.76 2.81-3.12 1.77-.36 3.6-1.21 4.62-2.58.39 1.29.59 2.65.59 4.04 0 2.65-2.15 4.8-4.8 4.8z"/>
- <path d="M0 0h24v24H0z" fill="none"/>
</svg>
\ No newline at end of file
--- /dev/null
+<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
+ <path d="m24 44.15c-0.4 0-0.79167-0.06667-1.175-0.2-0.38333-0.13333-0.70833-0.33333-0.975-0.6l-17.2-17.2c-0.26667-0.26667-0.46667-0.59167-0.6-0.975s-0.2-0.775-0.2-1.175 0.066667-0.79167 0.2-1.175c0.13333-0.38333 0.33333-0.70833 0.6-0.975l17.2-17.2c0.26667-0.26667 0.59167-0.46667 0.975-0.6s0.775-0.2 1.175-0.2 0.79167 0.066667 1.175 0.2c0.38333 0.13333 0.70833 0.33333 0.975 0.6l17.2 17.2c0.26667 0.26667 0.46667 0.59167 0.6 0.975s0.2 0.775 0.2 1.175-0.06667 0.79167-0.2 1.175c-0.13333 0.38333-0.33333 0.70833-0.6 0.975l-17.2 17.2c-0.26667 0.26667-0.59167 0.46667-0.975 0.6s-0.775 0.2-1.175 0.2zm4.05-18.65-5.15 5.15c-0.3 0.3-0.44167 0.65-0.425 1.05 0.01667 0.4 0.175 0.75 0.475 1.05s0.65833 0.45 1.075 0.45 0.775-0.15 1.075-0.45l7.7-7.7c0.3-0.3 0.45-0.65 0.45-1.05s-0.15-0.75-0.45-1.05l-7.75-7.75c-0.3-0.3-0.65-0.45-1.05-0.45s-0.75 0.15-1.05 0.45-0.45 0.65833-0.45 1.075 0.15 0.775 0.45 1.075l5.1 5.15h-12.4c-0.43333 0-0.79167 0.14167-1.075 0.425s-0.425 0.64167-0.425 1.075 0.14167 0.79167 0.425 1.075 0.64167 0.425 1.075 0.425z"/>
+</svg>
'convert_to_book_desc' => 'You can convert this chapter to a new book with the same contents. Any permissions set on this chapter will be copied to the new book but any inherited permissions, from the parent book, will not be copied which could lead to a change of access control.',
'convert_chapter' => 'Convert Chapter',
'convert_chapter_confirm' => 'Are you sure you want to convert this chapter?',
+
+ // References
+ 'references' => 'References',
+ 'references_none' => 'There are no tracked references to this item.',
+ 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.',
];
--- /dev/null
+@extends('layouts.simple')
+
+@section('body')
+
+ <div class="container small">
+
+ <div class="my-s">
+ @include('entities.breadcrumbs', ['crumbs' => [
+ $page->book,
+ $page->chapter,
+ $page,
+ $page->getUrl('/references') => [
+ 'text' => trans('entities.references'),
+ 'icon' => 'reference',
+ ]
+ ]])
+ </div>
+
+ <main class="card content-wrap">
+ <h1 class="list-heading">{{ trans('entities.references') }}</h1>
+ <p>{{ trans('entities.references_to_desc') }}</p>
+
+ @if(count($references) > 0)
+ <div class="book-contents">
+ @include('entities.list', ['entities' => $references->pluck('from'), 'showPath' => true])
+ </div>
+ @else
+ <p class="text-muted italic">{{ trans('entities.references_none') }}</p>
+ @endif
+
+ </main>
+ </div>
+
+@stop
use BookStack\Http\Controllers\PageRevisionController;
use BookStack\Http\Controllers\PageTemplateController;
use BookStack\Http\Controllers\RecycleBinController;
+use BookStack\Http\Controllers\ReferenceController;
use BookStack\Http\Controllers\RoleController;
use BookStack\Http\Controllers\SearchController;
use BookStack\Http\Controllers\SettingController;
Route::get('/books/{bookSlug}/draft/{pageId}/delete', [PageController::class, 'showDeleteDraft']);
Route::get('/books/{bookSlug}/page/{pageSlug}/permissions', [PageController::class, 'showPermissions']);
Route::put('/books/{bookSlug}/page/{pageSlug}/permissions', [PageController::class, 'permissions']);
+ Route::get('/books/{bookSlug}/page/{pageSlug}/references', [ReferenceController::class, 'page']);
Route::put('/books/{bookSlug}/page/{pageSlug}', [PageController::class, 'update']);
Route::delete('/books/{bookSlug}/page/{pageSlug}', [PageController::class, 'destroy']);
Route::delete('/books/{bookSlug}/draft/{pageId}', [PageController::class, 'destroyDraft']);