1
0
mirror of https://github.com/Kovah/LinkAce.git synced 2025-01-17 13:18:21 +01:00

Add migration of existing revisions (#467)

This commit is contained in:
Kovah 2022-06-14 22:48:27 +02:00
parent 65298fe9aa
commit cce410eac3
No known key found for this signature in database
GPG Key ID: AAAA031BA9830D7B
4 changed files with 295 additions and 27 deletions

View File

@ -166,4 +166,15 @@ return [
*/
'console' => env('AUDIT_CONSOLE_EVENTS', true),
/*
|--------------------------------------------------------------------------
| Revision Migration
|--------------------------------------------------------------------------
|
| Whether the revisions table should be deleted after successful migration.
|
*/
'delete_revisions_table' => true,
];

View File

@ -1,43 +1,124 @@
<?php
use App\Models\Link;
use App\Models\User;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use OwenIt\Auditing\Models\Audit;
class CreateAuditsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
public function up(): void
{
Schema::create('audits', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('user_type')->nullable();
$table->unsignedBigInteger('user_id')->nullable();
$table->string('event');
$table->morphs('auditable');
$table->text('old_values')->nullable();
$table->text('new_values')->nullable();
$table->text('url')->nullable();
$table->ipAddress('ip_address')->nullable();
$table->string('user_agent', 1023)->nullable();
$table->string('tags')->nullable();
$table->timestamps();
if (!Schema::hasTable('audits')) {
Schema::create('audits', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('user_type')->nullable();
$table->unsignedBigInteger('user_id')->nullable();
$table->string('event');
$table->morphs('auditable');
$table->text('old_values')->nullable();
$table->text('new_values')->nullable();
$table->text('url')->nullable();
$table->ipAddress()->nullable();
$table->string('user_agent', 1023)->nullable();
$table->string('tags')->nullable();
$table->timestamps();
$table->index(['user_id', 'user_type']);
});
$table->index(['user_id', 'user_type']);
});
}
$this->migrateExistingRevisions();
if (config('audit.delete_revisions_table')) {
Schema::drop('revisions');
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
public function down(): void
{
Schema::drop('audits');
}
protected function migrateExistingRevisions(): void
{
$entries = DB::table('revisions')->orderBy('created_at')->get();
foreach ($entries as $entry) {
$newAudit = new Audit();
$newAudit->user_type = $entry->user_id ? User::class : null;
$newAudit->user_id = $entry->user_id ?? null;
$newAudit->auditable_type = $entry->revisionable_type;
$newAudit->auditable_id = $entry->revisionable_id;
$newAudit->url = null;
$newAudit->ip_address = null;
$newAudit->user_agent = null;
$newAudit->tags = null;
$newAudit->created_at = $entry->created_at;
$newAudit->updated_at = $entry->updated_at;
$newAudit->event = $this->processAuditEvent($entry);
[$newAudit->old_values, $newAudit->new_values] = match ($newAudit->event) {
Link::AUDIT_RELATION_EVENT => $this->buildModelRelationValues($entry),
'deleted' => $this->buildDeletionValues($entry),
'restored' => $this->buildRestoreValues($entry),
default => $this->buildValues($entry),
};
$newAudit->save(['timestamps' => false]);
}
}
protected function processAuditEvent($entry): string
{
if (in_array($entry->key, [Link::AUDIT_TAGS_NAME, Link::AUDIT_LISTS_NAME])) {
return Link::AUDIT_RELATION_EVENT;
}
if ($entry->key === 'deleted_at' && $entry->old_value === null) {
return 'deleted';
}
if ($entry->key === 'deleted_at' && $entry->new_value === null) {
return 'restored';
}
return 'updated';
}
protected function buildValues($entry): array
{
$old = $entry->old_value ? [$entry->key => $entry->old_value] : [];
$new = $entry->new_value ? [$entry->key => $entry->new_value] : [];
return [$old, $new];
}
protected function buildModelRelationValues($entry): array
{
$old = $entry->old_value ? [$entry->key => array_map('intval', explode(',', $entry->old_value))] : [];
$new = $entry->new_value ? [$entry->key => array_map('intval', explode(',', $entry->new_value))] : [];
return [$old, $new];
}
protected function buildDeletionValues($entry): array
{
$old = Link::withTrashed()->find($entry->revisionable_id) ?: [];
$new = [];
return [$old, $new];
}
protected function buildRestoreValues($entry): array
{
$old = [];
$new = Link::withTrashed()->find($entry->revisionable_id) ?: [];
return [$old, $new];
}
}

View File

@ -26,6 +26,9 @@
<testsuite name="Helper">
<directory suffix="Test.php">./tests/Helper</directory>
</testsuite>
<testsuite name="Migrations">
<directory suffix="Test.php">./tests/Migrations</directory>
</testsuite>
<testsuite name="Models">
<directory suffix="Test.php">./tests/Models</directory>
</testsuite>

View File

@ -0,0 +1,173 @@
<?php
namespace Tests\Migrations;
use App\Models\Link;
use App\Models\User;
use CreateAuditsTable;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use OwenIt\Auditing\Models\Audit;
use Tests\TestCase;
class RevisionsToAuditsMigrationTest extends TestCase
{
use RefreshDatabase;
protected function beforeRefreshingDatabase(): void
{
config()->set('audit.delete_revisions_table', false);
}
public function testRevisionMigration(): void
{
$date = now()->subDay()->startOfSecond();
DB::table('revisions')->insert([
'revisionable_type' => Link::class,
'revisionable_id' => 5,
'user_id' => null,
'key' => 'url',
'old_value' => 'https://example.com',
'new_value' => 'https://test.com',
'created_at' => $date,
'updated_at' => $date,
]);
$this->assertDatabaseCount('revisions', 1);
$migrator = new CreateAuditsTable();
$migrator->up();
$audit = Audit::first();
$this->assertNull($audit->user_type);
$this->assertNull($audit->user_id);
$this->assertEquals('https://example.com', $audit->getModified()['url']['old']);
$this->assertEquals('https://test.com', $audit->getModified()['url']['new']);
$this->assertTrue(
$date->equalTo($audit->created_at),
sprintf('Created at date should be %s but is %s', $date, $audit->created_at)
);
$this->assertTrue(
$date->equalTo($audit->updated_at),
sprintf('Created at date should be %s but is %s', $date, $audit->updated_at)
);
}
public function testRevisionMigrationWithUser(): void
{
DB::table('revisions')->insert([
'revisionable_type' => Link::class,
'revisionable_id' => 5,
'user_id' => 7,
'key' => 'url',
'old_value' => 'https://example.com',
'new_value' => 'https://test.com',
'created_at' => now()->subDay(),
'updated_at' => now()->subDay(),
]);
$migrator = new CreateAuditsTable();
$migrator->up();
$audit = Audit::first();
$this->assertEquals(User::class, $audit->user_type);
$this->assertEquals(7, $audit->user_id);
}
public function testRevisionMigrationWithoutOldValue(): void
{
DB::table('revisions')->insert([
'revisionable_type' => Link::class,
'revisionable_id' => 5,
'user_id' => 7,
'key' => 'url',
'old_value' => null,
'new_value' => 'https://test.com',
'created_at' => now()->subDay(),
'updated_at' => now()->subDay(),
]);
$migrator = new CreateAuditsTable();
$migrator->up();
$audit = Audit::first();
$this->assertArrayNotHasKey('old', $audit->getModified()['url']);
$this->assertArrayHasKey('new', $audit->getModified()['url']);
}
public function testRevisionMigrationWithRelations(): void
{
DB::table('revisions')->insert([
'revisionable_type' => Link::class,
'revisionable_id' => 5,
'user_id' => 7,
'key' => 'revtags',
'old_value' => null,
'new_value' => '4,8,12',
'created_at' => now()->subDay(),
'updated_at' => now()->subDay(),
]);
$migrator = new CreateAuditsTable();
$migrator->up();
$audit = Audit::first();
$this->assertArrayHasKey('revtags', $audit->getModified());
$this->assertEquals([4, 8, 12], $audit->getModified()['revtags']['new']);
}
public function testRevisionMigrationWithDeletion(): void
{
Link::factory()->createQuietly(['url' => 'https://deleted.com']);
DB::table('revisions')->insert([
'revisionable_type' => Link::class,
'revisionable_id' => 1,
'user_id' => 7,
'key' => 'deleted_at',
'old_value' => null,
'new_value' => '2020-07-02 09:23:34',
'created_at' => now()->subDay(),
'updated_at' => now()->subDay(),
]);
$migrator = new CreateAuditsTable();
$migrator->up();
$audit = Audit::first();
$this->assertEquals('deleted', $audit->event);
$this->assertArrayHasKey('url', $audit->getModified());
$this->assertEquals('https://deleted.com', $audit->getModified()['url']['old']);
}
public function testRevisionMigrationWithRestore(): void
{
Link::factory()->createQuietly(['url' => 'https://restored.com']);
DB::table('revisions')->insert([
'revisionable_type' => Link::class,
'revisionable_id' => 1,
'user_id' => 7,
'key' => 'deleted_at',
'old_value' => '2020-07-02 09:23:34',
'new_value' => null,
'created_at' => now()->subDay(),
'updated_at' => now()->subDay(),
]);
$migrator = new CreateAuditsTable();
$migrator->up();
$audit = Audit::first();
$this->assertEquals('restored', $audit->event);
$this->assertArrayHasKey('url', $audit->getModified());
$this->assertEquals('https://restored.com', $audit->getModified()['url']['new']);
}
}