mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-04-23 04:10:22 +00:00
Added reference handling on page actions
Page update/create/restore/clone/delete. Added a couple of tests to cover a couple of those.
This commit is contained in:
parent
3290ab3ac9
commit
bbe504c559
4 changed files with 81 additions and 3 deletions
app
tests/References
|
@ -16,20 +16,23 @@ use BookStack\Exceptions\MoveOperationException;
|
||||||
use BookStack\Exceptions\NotFoundException;
|
use BookStack\Exceptions\NotFoundException;
|
||||||
use BookStack\Exceptions\PermissionsException;
|
use BookStack\Exceptions\PermissionsException;
|
||||||
use BookStack\Facades\Activity;
|
use BookStack\Facades\Activity;
|
||||||
|
use BookStack\References\ReferenceService;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
|
|
||||||
class PageRepo
|
class PageRepo
|
||||||
{
|
{
|
||||||
protected $baseRepo;
|
protected BaseRepo $baseRepo;
|
||||||
|
protected ReferenceService $references;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PageRepo constructor.
|
* PageRepo constructor.
|
||||||
*/
|
*/
|
||||||
public function __construct(BaseRepo $baseRepo)
|
public function __construct(BaseRepo $baseRepo, ReferenceService $references)
|
||||||
{
|
{
|
||||||
$this->baseRepo = $baseRepo;
|
$this->baseRepo = $baseRepo;
|
||||||
|
$this->references = $references;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,7 +115,7 @@ class PageRepo
|
||||||
public function getParentFromSlugs(string $bookSlug, string $chapterSlug = null): Entity
|
public function getParentFromSlugs(string $bookSlug, string $chapterSlug = null): Entity
|
||||||
{
|
{
|
||||||
if ($chapterSlug !== null) {
|
if ($chapterSlug !== null) {
|
||||||
return $chapter = Chapter::visible()->whereSlugs($bookSlug, $chapterSlug)->firstOrFail();
|
return Chapter::visible()->whereSlugs($bookSlug, $chapterSlug)->firstOrFail();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Book::visible()->where('slug', '=', $bookSlug)->firstOrFail();
|
return Book::visible()->where('slug', '=', $bookSlug)->firstOrFail();
|
||||||
|
@ -170,6 +173,7 @@ class PageRepo
|
||||||
|
|
||||||
$this->savePageRevision($draft, trans('entities.pages_initial_revision'));
|
$this->savePageRevision($draft, trans('entities.pages_initial_revision'));
|
||||||
$draft->indexForSearch();
|
$draft->indexForSearch();
|
||||||
|
$this->references->updateForPage($draft);
|
||||||
$draft->refresh();
|
$draft->refresh();
|
||||||
|
|
||||||
Activity::add(ActivityType::PAGE_CREATE, $draft);
|
Activity::add(ActivityType::PAGE_CREATE, $draft);
|
||||||
|
@ -189,6 +193,7 @@ class PageRepo
|
||||||
|
|
||||||
$this->updateTemplateStatusAndContentFromInput($page, $input);
|
$this->updateTemplateStatusAndContentFromInput($page, $input);
|
||||||
$this->baseRepo->update($page, $input);
|
$this->baseRepo->update($page, $input);
|
||||||
|
$this->references->updateForPage($page);
|
||||||
|
|
||||||
// Update with new details
|
// Update with new details
|
||||||
$page->revision_count++;
|
$page->revision_count++;
|
||||||
|
@ -332,6 +337,7 @@ class PageRepo
|
||||||
$page->refreshSlug();
|
$page->refreshSlug();
|
||||||
$page->save();
|
$page->save();
|
||||||
$page->indexForSearch();
|
$page->indexForSearch();
|
||||||
|
$this->references->updateForPage($page);
|
||||||
|
|
||||||
$summary = trans('entities.pages_revision_restored_from', ['id' => strval($revisionId), 'summary' => $revision->summary]);
|
$summary = trans('entities.pages_revision_restored_from', ['id' => strval($revisionId), 'summary' => $revision->summary]);
|
||||||
$this->savePageRevision($page, $summary);
|
$this->savePageRevision($page, $summary);
|
||||||
|
@ -430,6 +436,7 @@ class PageRepo
|
||||||
->skip(intval($revisionLimit))
|
->skip(intval($revisionLimit))
|
||||||
->take(10)
|
->take(10)
|
||||||
->get(['id']);
|
->get(['id']);
|
||||||
|
|
||||||
if ($revisionsToDelete->count() > 0) {
|
if ($revisionsToDelete->count() > 0) {
|
||||||
PageRevision::query()->whereIn('id', $revisionsToDelete->pluck('id'))->delete();
|
PageRevision::query()->whereIn('id', $revisionsToDelete->pluck('id'))->delete();
|
||||||
}
|
}
|
||||||
|
|
|
@ -376,6 +376,8 @@ class TrashCan
|
||||||
$entity->searchTerms()->delete();
|
$entity->searchTerms()->delete();
|
||||||
$entity->deletions()->delete();
|
$entity->deletions()->delete();
|
||||||
$entity->favourites()->delete();
|
$entity->favourites()->delete();
|
||||||
|
$entity->referencesTo()->delete();
|
||||||
|
$entity->referencesFrom()->delete();
|
||||||
|
|
||||||
if ($entity instanceof HasCoverImage && $entity->cover()->exists()) {
|
if ($entity instanceof HasCoverImage && $entity->cover()->exists()) {
|
||||||
$imageService = app()->make(ImageService::class);
|
$imageService = app()->make(ImageService::class);
|
||||||
|
|
|
@ -14,6 +14,8 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||||
*/
|
*/
|
||||||
class Reference extends Model
|
class Reference extends Model
|
||||||
{
|
{
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
public function from(): MorphTo
|
public function from(): MorphTo
|
||||||
{
|
{
|
||||||
return $this->morphTo('from');
|
return $this->morphTo('from');
|
||||||
|
|
67
tests/References/ReferencesTest.php
Normal file
67
tests/References/ReferencesTest.php
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\References;
|
||||||
|
|
||||||
|
use BookStack\Entities\Models\Page;
|
||||||
|
use BookStack\Entities\Repos\PageRepo;
|
||||||
|
use BookStack\Entities\Tools\TrashCan;
|
||||||
|
use BookStack\Model;
|
||||||
|
use BookStack\References\Reference;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class ReferencesTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function test_references_created_on_page_update()
|
||||||
|
{
|
||||||
|
/** @var Page $pageA */
|
||||||
|
/** @var Page $pageB */
|
||||||
|
$pageA = Page::query()->first();
|
||||||
|
$pageB = Page::query()->where('id', '!=', $pageA->id)->first();
|
||||||
|
|
||||||
|
$this->assertDatabaseMissing('references', ['from_id' => $pageA->id, 'from_type' => $pageA->getMorphClass()]);
|
||||||
|
|
||||||
|
$this->asEditor()->put($pageA->getUrl(), [
|
||||||
|
'name' => 'Reference test',
|
||||||
|
'html' => '<a href="' . $pageB->getUrl() . '">Testing</a>'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('references', [
|
||||||
|
'from_id' => $pageA->id,
|
||||||
|
'from_type' => $pageA->getMorphClass(),
|
||||||
|
'to_id' => $pageB->id,
|
||||||
|
'to_type' => $pageB->getMorphClass(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_references_deleted_on_entity_delete()
|
||||||
|
{
|
||||||
|
/** @var Page $pageA */
|
||||||
|
/** @var Page $pageB */
|
||||||
|
$pageA = Page::query()->first();
|
||||||
|
$pageB = Page::query()->where('id', '!=', $pageA->id)->first();
|
||||||
|
|
||||||
|
$this->createReference($pageA, $pageB);
|
||||||
|
$this->createReference($pageB, $pageA);
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('references', ['from_id' => $pageA->id, 'from_type' => $pageA->getMorphClass()]);
|
||||||
|
$this->assertDatabaseHas('references', ['to_id' => $pageA->id, 'to_type' => $pageA->getMorphClass()]);
|
||||||
|
|
||||||
|
app(PageRepo::class)->destroy($pageA);
|
||||||
|
app(TrashCan::class)->empty();
|
||||||
|
|
||||||
|
$this->assertDatabaseMissing('references', ['from_id' => $pageA->id, 'from_type' => $pageA->getMorphClass()]);
|
||||||
|
$this->assertDatabaseMissing('references', ['to_id' => $pageA->id, 'to_type' => $pageA->getMorphClass()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createReference(Model $from, Model $to)
|
||||||
|
{
|
||||||
|
(new Reference())->forceFill([
|
||||||
|
'from_type' => $from->getMorphClass(),
|
||||||
|
'from_id' => $from->id,
|
||||||
|
'to_type' => $to->getMorphClass(),
|
||||||
|
'to_id' => $to->id,
|
||||||
|
])->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue