mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-11-23 19:32:29 +01:00
Added extendable/scalable formatter for webhook data
Creates a new organsied formatting system for webhook data, with interfaces for extending with custom model formatting rules. Allows easy usage & extension of the default bookstack formatting behaviour when customizing webhook events via theme system, and keeps default data customizations organised. This also makes the following webhook data changes: - owned_by/created_by/updated_by user details are loaded for events with Entity details. (POTENTIALLY BREAKING CHANGE). - current_revision details are loaded for page update/create events. Added testing to cover added model formatting rules. For #3279 and #3218
This commit is contained in:
parent
55d61fceb2
commit
3625f12abe
@ -3,17 +3,14 @@
|
|||||||
namespace BookStack\Actions;
|
namespace BookStack\Actions;
|
||||||
|
|
||||||
use BookStack\Auth\User;
|
use BookStack\Auth\User;
|
||||||
use BookStack\Entities\Models\Entity;
|
|
||||||
use BookStack\Facades\Theme;
|
use BookStack\Facades\Theme;
|
||||||
use BookStack\Interfaces\Loggable;
|
use BookStack\Interfaces\Loggable;
|
||||||
use BookStack\Model;
|
|
||||||
use BookStack\Theming\ThemeEvents;
|
use BookStack\Theming\ThemeEvents;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
@ -24,31 +21,16 @@ class DispatchWebhookJob implements ShouldQueue
|
|||||||
use Queueable;
|
use Queueable;
|
||||||
use SerializesModels;
|
use SerializesModels;
|
||||||
|
|
||||||
/**
|
protected Webhook $webhook;
|
||||||
* @var Webhook
|
protected string $event;
|
||||||
*/
|
protected User $initiator;
|
||||||
protected $webhook;
|
protected int $initiatedTime;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $event;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|Loggable
|
* @var string|Loggable
|
||||||
*/
|
*/
|
||||||
protected $detail;
|
protected $detail;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var User
|
|
||||||
*/
|
|
||||||
protected $initiator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $initiatedTime;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new job instance.
|
* Create a new job instance.
|
||||||
*
|
*
|
||||||
@ -70,8 +52,8 @@ class DispatchWebhookJob implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$themeResponse = Theme::dispatch(ThemeEvents::WEBHOOK_CALL_BEFORE, $this->event, $this->webhook, $this->detail);
|
$themeResponse = Theme::dispatch(ThemeEvents::WEBHOOK_CALL_BEFORE, $this->event, $this->webhook, $this->detail, $this->initiator, $this->initiatedTime);
|
||||||
$webhookData = $themeResponse ?? $this->buildWebhookData();
|
$webhookData = $themeResponse ?? WebhookFormatter::getDefault($this->event, $this->webhook, $this->detail, $this->initiator, $this->initiatedTime)->format();
|
||||||
$lastError = null;
|
$lastError = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -97,36 +79,4 @@ class DispatchWebhookJob implements ShouldQueue
|
|||||||
|
|
||||||
$this->webhook->save();
|
$this->webhook->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildWebhookData(): array
|
|
||||||
{
|
|
||||||
$textParts = [
|
|
||||||
$this->initiator->name,
|
|
||||||
trans('activities.' . $this->event),
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($this->detail instanceof Entity) {
|
|
||||||
$textParts[] = '"' . $this->detail->name . '"';
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'event' => $this->event,
|
|
||||||
'text' => implode(' ', $textParts),
|
|
||||||
'triggered_at' => Carbon::createFromTimestampUTC($this->initiatedTime)->toISOString(),
|
|
||||||
'triggered_by' => $this->initiator->attributesToArray(),
|
|
||||||
'triggered_by_profile_url' => $this->initiator->getProfileUrl(),
|
|
||||||
'webhook_id' => $this->webhook->id,
|
|
||||||
'webhook_name' => $this->webhook->name,
|
|
||||||
];
|
|
||||||
|
|
||||||
if (method_exists($this->detail, 'getUrl')) {
|
|
||||||
$data['url'] = $this->detail->getUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->detail instanceof Model) {
|
|
||||||
$data['related_item'] = $this->detail->attributesToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
123
app/Actions/WebhookFormatter.php
Normal file
123
app/Actions/WebhookFormatter.php
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BookStack\Actions;
|
||||||
|
|
||||||
|
use BookStack\Auth\User;
|
||||||
|
use BookStack\Entities\Models\Entity;
|
||||||
|
use BookStack\Entities\Models\Page;
|
||||||
|
use BookStack\Interfaces\Loggable;
|
||||||
|
use BookStack\Model;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
|
class WebhookFormatter
|
||||||
|
{
|
||||||
|
protected Webhook $webhook;
|
||||||
|
protected string $event;
|
||||||
|
protected User $initiator;
|
||||||
|
protected int $initiatedTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|Loggable
|
||||||
|
*/
|
||||||
|
protected $detail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array{condition: callable(string, Model):bool, format: callable(Model):void}[]
|
||||||
|
*/
|
||||||
|
protected $modelFormatters = [];
|
||||||
|
|
||||||
|
public function __construct(string $event, Webhook $webhook, $detail, User $initiator, int $initiatedTime)
|
||||||
|
{
|
||||||
|
$this->webhook = $webhook;
|
||||||
|
$this->event = $event;
|
||||||
|
$this->initiator = $initiator;
|
||||||
|
$this->initiatedTime = $initiatedTime;
|
||||||
|
$this->detail = is_object($detail) ? clone $detail : $detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function format(): array
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'event' => $this->event,
|
||||||
|
'text' => $this->formatText(),
|
||||||
|
'triggered_at' => Carbon::createFromTimestampUTC($this->initiatedTime)->toISOString(),
|
||||||
|
'triggered_by' => $this->initiator->attributesToArray(),
|
||||||
|
'triggered_by_profile_url' => $this->initiator->getProfileUrl(),
|
||||||
|
'webhook_id' => $this->webhook->id,
|
||||||
|
'webhook_name' => $this->webhook->name,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (method_exists($this->detail, 'getUrl')) {
|
||||||
|
$data['url'] = $this->detail->getUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->detail instanceof Model) {
|
||||||
|
$data['related_item'] = $this->formatModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param callable(string, Model):bool $condition
|
||||||
|
* @param callable(Model):void $format
|
||||||
|
*/
|
||||||
|
public function addModelFormatter(callable $condition, callable $format): void
|
||||||
|
{
|
||||||
|
$this->modelFormatters[] = [
|
||||||
|
'condition' => $condition,
|
||||||
|
'format' => $format,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addDefaultModelFormatters(): void
|
||||||
|
{
|
||||||
|
// Load entity owner, creator, updater details
|
||||||
|
$this->addModelFormatter(
|
||||||
|
fn($event, $model) => ($model instanceof Entity),
|
||||||
|
fn($model) => $model->load(['ownedBy', 'createdBy', 'updatedBy'])
|
||||||
|
);
|
||||||
|
|
||||||
|
// Load revision detail for page update and create events
|
||||||
|
$this->addModelFormatter(
|
||||||
|
fn($event, $model) => ($model instanceof Page && ($event === ActivityType::PAGE_CREATE || $event === ActivityType::PAGE_UPDATE)),
|
||||||
|
fn($model) => $model->load('currentRevision')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formatModel(): array
|
||||||
|
{
|
||||||
|
/** @var Model $model */
|
||||||
|
$model = $this->detail;
|
||||||
|
$model->unsetRelations();
|
||||||
|
|
||||||
|
foreach ($this->modelFormatters as $formatter) {
|
||||||
|
if ($formatter['condition']($this->event, $model)) {
|
||||||
|
$formatter['format']($model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $model->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formatText(): string
|
||||||
|
{
|
||||||
|
$textParts = [
|
||||||
|
$this->initiator->name,
|
||||||
|
trans('activities.' . $this->event),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($this->detail instanceof Entity) {
|
||||||
|
$textParts[] = '"' . $this->detail->name . '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(' ', $textParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getDefault(string $event, Webhook $webhook, $detail, User $initiator, int $initiatedTime): self
|
||||||
|
{
|
||||||
|
$instance = new static($event, $webhook, $detail, $initiator, $initiatedTime);
|
||||||
|
$instance->addDefaultModelFormatters();
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
|
}
|
@ -10,19 +10,22 @@ use Illuminate\Database\Eloquent\Collection;
|
|||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Page.
|
* Class Page.
|
||||||
*
|
*
|
||||||
* @property int $chapter_id
|
* @property int $chapter_id
|
||||||
* @property string $html
|
* @property string $html
|
||||||
* @property string $markdown
|
* @property string $markdown
|
||||||
* @property string $text
|
* @property string $text
|
||||||
* @property bool $template
|
* @property bool $template
|
||||||
* @property bool $draft
|
* @property bool $draft
|
||||||
* @property int $revision_count
|
* @property int $revision_count
|
||||||
* @property Chapter $chapter
|
* @property Chapter $chapter
|
||||||
* @property Collection $attachments
|
* @property Collection $attachments
|
||||||
|
* @property Collection $revisions
|
||||||
|
* @property PageRevision $currentRevision
|
||||||
*/
|
*/
|
||||||
class Page extends BookChild
|
class Page extends BookChild
|
||||||
{
|
{
|
||||||
@ -82,6 +85,19 @@ class Page extends BookChild
|
|||||||
->orderBy('id', 'desc');
|
->orderBy('id', 'desc');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current revision for the page if existing.
|
||||||
|
*
|
||||||
|
* @return PageRevision|null
|
||||||
|
*/
|
||||||
|
public function currentRevision(): HasOne
|
||||||
|
{
|
||||||
|
return $this->hasOne(PageRevision::class)
|
||||||
|
->where('type', '=', 'version')
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->orderBy('id', 'desc');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all revision instances assigned to this page.
|
* Get all revision instances assigned to this page.
|
||||||
* Includes all types of revisions.
|
* Includes all types of revisions.
|
||||||
@ -117,16 +133,6 @@ class Page extends BookChild
|
|||||||
return url('/' . implode('/', $parts));
|
return url('/' . implode('/', $parts));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current revision for the page if existing.
|
|
||||||
*
|
|
||||||
* @return PageRevision|null
|
|
||||||
*/
|
|
||||||
public function getCurrentRevision()
|
|
||||||
{
|
|
||||||
return $this->revisions()->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get this page for JSON display.
|
* Get this page for JSON display.
|
||||||
*/
|
*/
|
||||||
|
@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|||||||
/**
|
/**
|
||||||
* Class PageRevision.
|
* Class PageRevision.
|
||||||
*
|
*
|
||||||
|
* @property mixed $id
|
||||||
* @property int $page_id
|
* @property int $page_id
|
||||||
* @property string $slug
|
* @property string $slug
|
||||||
* @property string $book_slug
|
* @property string $book_slug
|
||||||
@ -27,6 +28,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|||||||
class PageRevision extends Model
|
class PageRevision extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = ['name', 'html', 'text', 'markdown', 'summary'];
|
protected $fillable = ['name', 'html', 'text', 'markdown', 'summary'];
|
||||||
|
protected $hidden = ['html', 'markdown', 'restricted', 'text'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the user that created the page revision.
|
* Get the user that created the page revision.
|
||||||
|
@ -124,11 +124,8 @@ class PageRevisionController extends Controller
|
|||||||
throw new NotFoundException("Revision #{$revId} not found");
|
throw new NotFoundException("Revision #{$revId} not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the current revision for the page
|
// Check if it's the latest revision, cannot delete the latest revision.
|
||||||
$currentRevision = $page->getCurrentRevision();
|
if (intval($page->currentRevision->id ?? null) === intval($revId)) {
|
||||||
|
|
||||||
// Check if its the latest revision, cannot delete latest revision.
|
|
||||||
if (intval($currentRevision->id) === intval($revId)) {
|
|
||||||
$this->showErrorNotification(trans('entities.revision_cannot_delete_latest'));
|
$this->showErrorNotification(trans('entities.revision_cannot_delete_latest'));
|
||||||
|
|
||||||
return redirect($page->getUrl('/revisions'));
|
return redirect($page->getUrl('/revisions'));
|
||||||
|
@ -93,6 +93,8 @@ class ThemeEvents
|
|||||||
* @param string $event
|
* @param string $event
|
||||||
* @param \BookStack\Actions\Webhook $webhook
|
* @param \BookStack\Actions\Webhook $webhook
|
||||||
* @param string|\BookStack\Interfaces\Loggable $detail
|
* @param string|\BookStack\Interfaces\Loggable $detail
|
||||||
|
* @param \BookStack\Auth\User $initiator
|
||||||
|
* @param int $initiatedTime
|
||||||
*/
|
*/
|
||||||
const WEBHOOK_CALL_BEFORE = 'webhook_call_before';
|
const WEBHOOK_CALL_BEFORE = 'webhook_call_before';
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,37 @@
|
|||||||
"priority": 2,
|
"priority": 2,
|
||||||
"created_at": "2021-12-11T21:53:24.000000Z",
|
"created_at": "2021-12-11T21:53:24.000000Z",
|
||||||
"updated_at": "2021-12-11T22:25:10.000000Z",
|
"updated_at": "2021-12-11T22:25:10.000000Z",
|
||||||
"created_by": 1,
|
"created_by": {
|
||||||
"updated_by": 1,
|
"id": 1,
|
||||||
|
"name": "Benny",
|
||||||
|
"slug": "benny"
|
||||||
|
},
|
||||||
|
"updated_by": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Benny",
|
||||||
|
"slug": "benny"
|
||||||
|
},
|
||||||
"draft": false,
|
"draft": false,
|
||||||
"revision_count": 9,
|
"revision_count": 9,
|
||||||
"template": false,
|
"template": false,
|
||||||
"owned_by": 1
|
"owned_by": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Benny",
|
||||||
|
"slug": "benny"
|
||||||
|
},
|
||||||
|
"current_revision": {
|
||||||
|
"id": 597,
|
||||||
|
"page_id": 2598,
|
||||||
|
"name": "My wonderful updated page",
|
||||||
|
"created_by": 1,
|
||||||
|
"created_at": "2021-12-11T21:53:24.000000Z",
|
||||||
|
"updated_at": "2021-12-11T21:53:24.000000Z",
|
||||||
|
"slug": "my-wonderful-updated-page",
|
||||||
|
"book_slug": "my-awesome-book",
|
||||||
|
"type": "version",
|
||||||
|
"summary": "Updated the title and fixed some spelling",
|
||||||
|
"revision_number": 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}</code></pre>
|
}</code></pre>
|
||||||
</div>
|
</div>
|
52
tests/Actions/WebhookFormatTesting.php
Normal file
52
tests/Actions/WebhookFormatTesting.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Actions;
|
||||||
|
|
||||||
|
use BookStack\Actions\ActivityType;
|
||||||
|
use BookStack\Actions\Webhook;
|
||||||
|
use BookStack\Actions\WebhookFormatter;
|
||||||
|
use BookStack\Entities\Models\Book;
|
||||||
|
use BookStack\Entities\Models\Chapter;
|
||||||
|
use BookStack\Entities\Models\Page;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class WebhookFormatTesting extends TestCase
|
||||||
|
{
|
||||||
|
public function test_entity_events_show_related_user_info()
|
||||||
|
{
|
||||||
|
$events = [
|
||||||
|
ActivityType::BOOK_UPDATE => Book::query()->first(),
|
||||||
|
ActivityType::CHAPTER_CREATE => Chapter::query()->first(),
|
||||||
|
ActivityType::PAGE_MOVE => Page::query()->first(),
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($events as $event => $entity) {
|
||||||
|
$data = $this->getWebhookData($event, $entity);
|
||||||
|
|
||||||
|
$this->assertEquals($entity->createdBy->name, Arr::get($data, 'related_item.created_by.name'));
|
||||||
|
$this->assertEquals($entity->updatedBy->id, Arr::get($data, 'related_item.updated_by.id'));
|
||||||
|
$this->assertEquals($entity->ownedBy->slug, Arr::get($data, 'related_item.owned_by.slug'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_page_create_and_update_events_show_revision_info()
|
||||||
|
{
|
||||||
|
/** @var Page $page */
|
||||||
|
$page = Page::query()->first();
|
||||||
|
$this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
|
||||||
|
|
||||||
|
$data = $this->getWebhookData(ActivityType::PAGE_UPDATE, $page);
|
||||||
|
$this->assertEquals($page->currentRevision->id, Arr::get($data, 'related_item.current_revision.id'));
|
||||||
|
$this->assertEquals($page->currentRevision->type, Arr::get($data, 'related_item.current_revision.type'));
|
||||||
|
$this->assertEquals('Update a', Arr::get($data, 'related_item.current_revision.summary'));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getWebhookData(string $event, $detail): array
|
||||||
|
{
|
||||||
|
$webhook = Webhook::factory()->make();
|
||||||
|
$user = $this->getEditor();
|
||||||
|
$formatter = WebhookFormatter::getDefault($event, $webhook, $detail, $user, time());
|
||||||
|
return $formatter->format();
|
||||||
|
}
|
||||||
|
}
|
@ -144,13 +144,14 @@ class PageRevisionTest extends TestCase
|
|||||||
|
|
||||||
public function test_revision_deletion()
|
public function test_revision_deletion()
|
||||||
{
|
{
|
||||||
$page = Page::first();
|
/** @var Page $page */
|
||||||
|
$page = Page::query()->first();
|
||||||
$this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
|
$this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
|
||||||
|
|
||||||
$page = Page::find($page->id);
|
$page->refresh();
|
||||||
$this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
|
$this->asEditor()->put($page->getUrl(), ['name' => 'Updated page', 'html' => 'new page html', 'summary' => 'Update a']);
|
||||||
|
|
||||||
$page = Page::find($page->id);
|
$page->refresh();
|
||||||
$beforeRevisionCount = $page->revisions->count();
|
$beforeRevisionCount = $page->revisions->count();
|
||||||
|
|
||||||
// Delete the first revision
|
// Delete the first revision
|
||||||
@ -158,18 +159,17 @@ class PageRevisionTest extends TestCase
|
|||||||
$resp = $this->asEditor()->delete($revision->getUrl('/delete/'));
|
$resp = $this->asEditor()->delete($revision->getUrl('/delete/'));
|
||||||
$resp->assertRedirect($page->getUrl('/revisions'));
|
$resp->assertRedirect($page->getUrl('/revisions'));
|
||||||
|
|
||||||
$page = Page::find($page->id);
|
$page->refresh();
|
||||||
$afterRevisionCount = $page->revisions->count();
|
$afterRevisionCount = $page->revisions->count();
|
||||||
|
|
||||||
$this->assertTrue($beforeRevisionCount === ($afterRevisionCount + 1));
|
$this->assertTrue($beforeRevisionCount === ($afterRevisionCount + 1));
|
||||||
|
|
||||||
// Try to delete the latest revision
|
// Try to delete the latest revision
|
||||||
$beforeRevisionCount = $page->revisions->count();
|
$beforeRevisionCount = $page->revisions->count();
|
||||||
$currentRevision = $page->getCurrentRevision();
|
$resp = $this->asEditor()->delete($page->currentRevision->getUrl('/delete/'));
|
||||||
$resp = $this->asEditor()->delete($currentRevision->getUrl('/delete/'));
|
|
||||||
$resp->assertRedirect($page->getUrl('/revisions'));
|
$resp->assertRedirect($page->getUrl('/revisions'));
|
||||||
|
|
||||||
$page = Page::find($page->id);
|
$page->refresh();
|
||||||
$afterRevisionCount = $page->revisions->count();
|
$afterRevisionCount = $page->revisions->count();
|
||||||
$this->assertTrue($beforeRevisionCount === $afterRevisionCount);
|
$this->assertTrue($beforeRevisionCount === $afterRevisionCount);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user