Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.x] Support non-revisable fields #11252

Open
wants to merge 25 commits into
base: 5.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Entries/Entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@ protected function revisionAttributes()
'slug' => $this->slug(),
'published' => $this->published(),
'date' => $this->collection()->dated() ? $this->date()->timestamp : null,
'data' => $this->data()->except(['updated_by', 'updated_at'])->all(),
'data' => $this->data()->except(['updated_by', 'updated_at', ...$this->nonRevisableFields()])->all(),
];
}

Expand All @@ -689,7 +689,7 @@ public function makeFromRevision($revision)

$entry
->published($attrs['published'])
->data($attrs['data'])
->data($this->data()->merge($attrs['data']))
->slug($attrs['slug']);

if ($this->collection()->dated() && ($date = Arr::get($attrs, 'date'))) {
Expand Down
13 changes: 13 additions & 0 deletions src/Fields/Field.php
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ public function isFilterable()
return (bool) $this->get('filterable');
}

public function isRevisable()
{
return (bool) $this->get('revisable', true);
}

public function shouldBeDuplicated()
{
if (is_null($this->get('duplicate'))) {
Expand All @@ -269,6 +274,7 @@ public function toPublishArray()
'visibility' => $this->visibility(),
'read_only' => $this->visibility() === 'read_only', // Deprecated: Addon fieldtypes should now reference new `visibility` state.
'always_save' => $this->alwaysSave(),
'revisable' => $this->isRevisable(),
]);
}

Expand Down Expand Up @@ -567,6 +573,13 @@ public static function commonFieldOptions(): Fields
'validate' => 'boolean',
'default' => true,
],
'revisable' => [
'display' => __('Revisable'),
'instructions' => __('statamic::messages.fields_revisable_instructions'),
'type' => 'toggle',
'validate' => 'boolean',
'default' => true,
],
])->map(fn ($field, $handle) => compact('handle', 'field'))->values()->all();

return new ConfigFields($fields);
Expand Down
19 changes: 18 additions & 1 deletion src/Http/Controllers/CP/Collections/EntriesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
use Illuminate\Validation\ValidationException;
use Statamic\Contracts\Entries\Entry as EntryContract;
use Statamic\CP\Breadcrumbs;
use Statamic\Entries\Entry as EntriesEntry;
use Statamic\Exceptions\BlueprintNotFoundException;
use Statamic\Facades\Action;
use Statamic\Facades\Asset;
use Statamic\Facades\Entry;
use Statamic\Facades\Site;
use Statamic\Facades\Stache;
use Statamic\Facades\User;
use Statamic\Fields\Field;
use Statamic\Hooks\CP\EntriesIndexQuery;
use Statamic\Http\Controllers\CP\CpController;
use Statamic\Http\Requests\FilteredRequest;
Expand Down Expand Up @@ -262,7 +264,8 @@ public function update(Request $request, $collection, $entry)
->save();

// catch any changes through RevisionSaving event
$entry = $entry->fromWorkingCopy();
// have to save in case there are non-revisable fields
$entry = $this->saveNonRevisableFields($entry);
} else {
if (! $entry->revisionsEnabled() && User::current()->can('publish', $entry)) {
$entry->published($request->published);
Expand Down Expand Up @@ -563,4 +566,18 @@ protected function ensureCollectionIsAvailableOnSite($collection, $site)
return redirect()->back()->with('error', __('Collection is not available on site ":handle".', ['handle' => $site->handle]));
}
}

private function saveNonRevisableFields(EntriesEntry $entry): EntriesEntry
{
/** @var EntriesEntry */
$savedVersion = $entry->fresh();

$entry->blueprint()->fields()->all()
->reject(fn (Field $field) => $field->isRevisable())
->each(fn ($ignore, string $fieldHandle) => $savedVersion->set($fieldHandle, $entry->{$fieldHandle}));

$savedVersion->save();

return $savedVersion;
}
}
3 changes: 3 additions & 0 deletions src/Http/Controllers/CP/Taxonomies/TermsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ public function update(Request $request, $taxonomy, $term, $site)
->makeWorkingCopy()
->user(User::current())
->save();

// have to save in case there are non-revisable fields
$term = tap($term->fromWorkingCopy())->save();
} else {
if (! $term->revisionsEnabled()) {
$term->published($request->published);
Expand Down
10 changes: 10 additions & 0 deletions src/Revisions/Revisable.php
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,16 @@ public function revisionsEnabled()
return config('statamic.revisions.enabled') && Statamic::pro();
}

public function nonRevisableFields(): array
{
return $this->blueprint()
->fields()
->all()
->reject(fn ($field) => $field->isRevisable())
->keys()
->all();
}

abstract protected function revisionKey();

abstract protected function revisionAttributes();
Expand Down
10 changes: 5 additions & 5 deletions src/Taxonomies/LocalizedTerm.php
Original file line number Diff line number Diff line change
Expand Up @@ -244,23 +244,23 @@ protected function revisionAttributes()
'id' => $this->id(),
'slug' => $this->slug(),
'published' => $this->published(),
'data' => $this->data()->except(['updated_by', 'updated_at'])->all(),
'data' => $this->data()->except(['updated_by', 'updated_at', ...$this->nonRevisableFields()])->all(),
];
}

public function makeFromRevision($revision)
{
$entry = clone $this;
$term = clone $this;

if (! $revision) {
return $entry;
return $term;
}

$attrs = $revision->attributes();

return $entry
return $term
->published($attrs['published'])
->data($attrs['data'])
->data($this->data()->merge($attrs['data']))
->slug($attrs['slug']);
}

Expand Down
52 changes: 48 additions & 4 deletions tests/Feature/Entries/EntryRevisionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,16 @@ public function it_gets_revisions()
{
$now = Carbon::parse('2017-02-03');
Carbon::setTestNow($now);
$this->setTestBlueprint('test', ['foo' => ['type' => 'text']]);
$this->setTestBlueprint(
'test',
[
'foo' => ['type' => 'text'],
'bar' => [
'type' => 'text',
'revisable' => false,
],
]
);
$this->setTestRoles(['test' => ['access cp', 'publish blog entries']]);
$user = User::make()->id('user-1')->assignRole('test')->save();

Expand All @@ -58,6 +67,7 @@ public function it_gets_revisions()
'blueprint' => 'test',
'title' => 'Original title',
'foo' => 'bar',
'bar' => 'foo',
])->create();

tap($entry->makeRevision(), function ($copy) {
Expand Down Expand Up @@ -85,6 +95,7 @@ public function it_gets_revisions()
->assertJsonPath('0.revisions.0.message', 'Revision one')
->assertJsonPath('0.revisions.0.attributes.data.title', 'Original title')
->assertJsonPath('0.revisions.0.attributes.item_url', 'http://localhost/cp/collections/blog/entries/1/revisions/'.Carbon::parse('2017-02-01')->timestamp)
->assertJsonPath('0.revisions.0.attributes.data.bar', null)

->assertJsonPath('1.revisions.0.action', 'revision')
->assertJsonPath('1.revisions.0.message', false)
Expand All @@ -102,7 +113,16 @@ public function it_publishes_an_entry()
{
$now = Carbon::parse('2017-02-03');
Carbon::setTestNow($now);
$this->setTestBlueprint('test', ['foo' => ['type' => 'text']]);
$this->setTestBlueprint(
'test',
[
'foo' => ['type' => 'text'],
'bar' => [
'type' => 'text',
'revisable' => false,
],
]
);
$this->setTestRoles(['test' => ['access cp', 'publish blog entries']]);
$user = User::make()->id('user-1')->assignRole('test')->save();

Expand All @@ -115,6 +135,7 @@ public function it_publishes_an_entry()
'blueprint' => 'test',
'title' => 'Title',
'foo' => 'bar',
'bar' => 'foo',
])->create();

tap($entry->makeWorkingCopy(), function ($copy) {
Expand All @@ -137,6 +158,7 @@ public function it_publishes_an_entry()
'blueprint' => 'test',
'title' => 'Title',
'foo' => 'foo modified in working copy',
'bar' => 'foo',
'updated_at' => $now->timestamp,
'updated_by' => $user->id(),
], $entry->data()->all());
Expand Down Expand Up @@ -166,7 +188,16 @@ public function it_unpublishes_an_entry()
{
$now = Carbon::parse('2017-02-03');
Carbon::setTestNow($now);
$this->setTestBlueprint('test', ['foo' => ['type' => 'text']]);
$this->setTestBlueprint(
'test',
[
'foo' => ['type' => 'text'],
'bar' => [
'type' => 'text',
'revisable' => false,
],
]
);
$this->setTestRoles(['test' => ['access cp', 'publish blog entries']]);
$user = User::make()->id('user-1')->assignRole('test')->save();

Expand All @@ -179,6 +210,7 @@ public function it_unpublishes_an_entry()
'blueprint' => 'test',
'title' => 'Title',
'foo' => 'bar',
'bar' => 'foo',
])->create();

$this->assertTrue($entry->published());
Expand All @@ -194,6 +226,7 @@ public function it_unpublishes_an_entry()
'blueprint' => 'test',
'title' => 'Title',
'foo' => 'bar',
'bar' => 'foo',
'updated_at' => $now->timestamp,
'updated_by' => $user->id(),
], $entry->data()->all());
Expand All @@ -219,7 +252,16 @@ public function it_unpublishes_an_entry()
#[Test]
public function it_creates_a_revision()
{
$this->setTestBlueprint('test', ['foo' => ['type' => 'text']]);
$this->setTestBlueprint(
'test',
[
'foo' => ['type' => 'text'],
'bar' => [
'type' => 'text',
'revisable' => false,
],
]
);
$this->setTestRoles(['test' => ['access cp', 'edit blog entries']]);
$user = User::make()->id('user-1')->assignRole('test')->save();

Expand All @@ -232,6 +274,7 @@ public function it_creates_a_revision()
'blueprint' => 'test',
'title' => 'Title',
'foo' => 'bar',
'bar' => 'foo',
])->create();

tap($entry->makeWorkingCopy(), function ($copy) {
Expand All @@ -253,6 +296,7 @@ public function it_creates_a_revision()
'blueprint' => 'test',
'title' => 'Title',
'foo' => 'bar',
'bar' => 'foo',
], $entry->data()->all());
$this->assertFalse($entry->published());
$this->assertCount(1, $entry->revisions());
Expand Down
60 changes: 57 additions & 3 deletions tests/Feature/Entries/UpdateEntryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Statamic\Facades\Blueprint;
use Statamic\Facades\Collection;
use Statamic\Facades\Entry;
use Statamic\Facades\Folder;
use Statamic\Facades\Role;
use Statamic\Facades\User;
use Statamic\Structures\CollectionStructure;
Expand All @@ -23,6 +24,25 @@ class UpdateEntryTest extends TestCase
use FakesRoles;
use PreventSavingStacheItemsToDisk;

public function setUp(): void
{
parent::setUp();

$this->dir = __DIR__.'/tmp';

config([
'statamic.editions.pro' => true,
'statamic.revisions.path' => $this->dir,
'statamic.revisions.enabled' => true,
]);
}

public function tearDown(): void
{
Folder::delete($this->dir);
parent::tearDown();
}

#[Test]
public function it_denies_access_if_you_dont_have_edit_permission()
{
Expand Down Expand Up @@ -416,7 +436,41 @@ public function it_can_validate_against_published_value()
#[Test]
public function published_entry_gets_saved_to_working_copy()
{
$this->markTestIncomplete();
[$user, $collection] = $this->seedUserAndCollection(true);

$this->seedBlueprintFields($collection, [
'revisable' => ['type' => 'text'],
'non_revisable' => ['type' => 'text', 'revisable' => false],
]);

$entry = EntryFactory::id('1')
->slug('test')
->collection('test')
->data(['title' => 'Revisable Test', 'published' => true])
->create();

$this
->actingAs($user)
->update($entry, [
'revisable' => 'revise me',
'non_revisable' => 'no revisions for you',
])
->assertOk();

$entry = Entry::find($entry->id());
$this->assertEquals('no revisions for you', $entry->non_revisable);
$this->assertEquals('Revisable Test', $entry->title);
$this->assertEquals('test', $entry->slug());
$this->assertNull($entry->revisable);

$workingCopy = $entry->fromWorkingCopy();
$this->assertEquals('updated-entry', $workingCopy->slug());
$this->assertEquals([
'title' => 'Updated entry',
'revisable' => 'revise me',
'non_revisable' => 'no revisions for you',
'published' => true,
], $workingCopy->data()->all());
}

#[Test]
Expand Down Expand Up @@ -501,7 +555,7 @@ public function does_not_validate_max_depth_when_collection_max_depth_is_null()
->assertOk();
}

private function seedUserAndCollection()
private function seedUserAndCollection(bool $enableRevisions = false)
{
$this->setTestRoles(['test' => [
'access cp',
Expand All @@ -510,7 +564,7 @@ private function seedUserAndCollection()
'access fr site',
]]);
$user = tap(User::make()->assignRole('test'))->save();
$collection = tap(Collection::make('test'))->save();
$collection = tap(Collection::make('test')->revisionsEnabled($enableRevisions))->save();

return [$user, $collection];
}
Expand Down
Loading
Loading