From 185842a89164f18f4759d9c1acca91fdc54462dd Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 2 Oct 2022 05:37:38 +0200 Subject: [PATCH] Add audit logs for rules. --- app/Events/TriggeredAuditLog.php | 53 +++++++++++++++++ app/Handlers/Events/AuditEventHandler.php | 45 ++++++++++++++ app/Models/AuditLogEntry.php | 58 +++++++++++++++++++ app/Models/Note.php | 2 +- app/Providers/EventServiceProvider.php | 6 ++ app/TransactionRules/Actions/AddTag.php | 6 ++ .../2022_10_01_210238_audit_log_entries.php | 42 ++++++++++++++ 7 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 app/Events/TriggeredAuditLog.php create mode 100644 app/Handlers/Events/AuditEventHandler.php create mode 100644 app/Models/AuditLogEntry.php create mode 100644 database/migrations/2022_10_01_210238_audit_log_entries.php diff --git a/app/Events/TriggeredAuditLog.php b/app/Events/TriggeredAuditLog.php new file mode 100644 index 0000000000..311aa05bc9 --- /dev/null +++ b/app/Events/TriggeredAuditLog.php @@ -0,0 +1,53 @@ +. + */ + +namespace FireflyIII\Events; + +use Illuminate\Database\Eloquent\Model; +use Illuminate\Queue\SerializesModels; + +/** + * Class TriggeredAuditLog + */ +class TriggeredAuditLog extends Event + +{ + use SerializesModels; + + public Model $changer; + public Model $auditable; + public string $field; + public mixed $before; + public mixed $after; + + /** + * Create a new event instance. + */ + public function __construct(Model $changer, Model $auditable, string $field, mixed $before = null, mixed $after = null) + { + $this->changer = $changer; + $this->auditable = $auditable; + $this->field = $field; + $this->before = $before; + $this->after = $after; + } + +} diff --git a/app/Handlers/Events/AuditEventHandler.php b/app/Handlers/Events/AuditEventHandler.php new file mode 100644 index 0000000000..43ee76a222 --- /dev/null +++ b/app/Handlers/Events/AuditEventHandler.php @@ -0,0 +1,45 @@ +. + */ + +namespace FireflyIII\Handlers\Events; + +use FireflyIII\Events\TriggeredAuditLog; +use FireflyIII\Models\AuditLogEntry; + +class AuditEventHandler +{ + + /** + * @param TriggeredAuditLog $event + * @return void + */ + public function storeAuditEvent(TriggeredAuditLog $event) + { + $auditLogEntry = new AuditLogEntry; + $auditLogEntry->auditable()->associate($event->auditable); + $auditLogEntry->changer()->associate($event->changer); + $auditLogEntry->action = $event->field; + $auditLogEntry->before = $event->before; + $auditLogEntry->after = $event->after; + $auditLogEntry->save(); + } + +} diff --git a/app/Models/AuditLogEntry.php b/app/Models/AuditLogEntry.php new file mode 100644 index 0000000000..4cdcaedaa1 --- /dev/null +++ b/app/Models/AuditLogEntry.php @@ -0,0 +1,58 @@ +. + */ + +namespace FireflyIII\Models; + +use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\MorphTo; +use Illuminate\Database\Eloquent\SoftDeletes; + +/** + * Class AuditLogEntry + */ +class AuditLogEntry extends Model +{ + use SoftDeletes; + + protected $casts = [ + 'before' => 'array', + 'after' => 'array', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + 'deleted_at' => 'datetime', + ]; + + /** + * @codeCoverageIgnore + */ + public function auditable(): MorphTo + { + return $this->morphTo(); + } + + /** + * @codeCoverageIgnore + */ + public function changer(): MorphTo + { + return $this->morphTo(); + } +} diff --git a/app/Models/Note.php b/app/Models/Note.php index 2090715d3b..59e03f4501 100644 --- a/app/Models/Note.php +++ b/app/Models/Note.php @@ -78,7 +78,7 @@ class Note extends Model /** * @codeCoverageIgnore * - * Get all of the owning noteable models. + * Get all the owning noteable models. */ public function noteable(): MorphTo { diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index ade51af104..1d63fb8e0c 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -36,6 +36,7 @@ use FireflyIII\Events\RequestedSendWebhookMessages; use FireflyIII\Events\RequestedVersionCheckStatus; use FireflyIII\Events\StoredAccount; use FireflyIII\Events\StoredTransactionGroup; +use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\UpdatedAccount; use FireflyIII\Events\UpdatedTransactionGroup; use FireflyIII\Events\UserChangedEmail; @@ -157,6 +158,11 @@ class EventServiceProvider extends ServiceProvider WarnUserAboutBill::class => [ 'FireflyIII\Handlers\Events\BillEventHandler@warnAboutBill', ], + + // audit log events: + TriggeredAuditLog::class => [ + 'FireflyIII\Handlers\Events\AuditEventHandler@storeAuditEvent', + ], ]; /** diff --git a/app/TransactionRules/Actions/AddTag.php b/app/TransactionRules/Actions/AddTag.php index 22b8345cef..5048b19fe8 100644 --- a/app/TransactionRules/Actions/AddTag.php +++ b/app/TransactionRules/Actions/AddTag.php @@ -23,8 +23,10 @@ declare(strict_types=1); namespace FireflyIII\TransactionRules\Actions; use DB; +use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Factory\TagFactory; use FireflyIII\Models\RuleAction; +use FireflyIII\Models\TransactionJournal; use FireflyIII\User; use Log; @@ -71,6 +73,10 @@ class AddTag implements ActionInterface // add to journal: DB::table('tag_transaction_journal')->insert(['tag_id' => $tag->id, 'transaction_journal_id' => $journal['transaction_journal_id']]); Log::debug(sprintf('RuleAction AddTag. Added tag #%d ("%s") to journal %d.', $tag->id, $tag->tag, $journal['transaction_journal_id'])); + $journal = TransactionJournal::find($journal['transaction_journal_id']); + // event for audit log entry + //// changer, auditable, field, value before, value after + event(new TriggeredAuditLog($this->action->rule, $journal, 'add_tag', null, $tag->tag)); return true; } diff --git a/database/migrations/2022_10_01_210238_audit_log_entries.php b/database/migrations/2022_10_01_210238_audit_log_entries.php new file mode 100644 index 0000000000..9ad71654d6 --- /dev/null +++ b/database/migrations/2022_10_01_210238_audit_log_entries.php @@ -0,0 +1,42 @@ +id(); + $table->timestamps(); + $table->softDeletes(); + + $table->integer('auditable_id', false, true); + $table->string('auditable_type'); + + $table->integer('changer_id', false, true); + $table->string('changer_type'); + + $table->string('action', 255); + $table->text('before')->nullable(); + $table->text('after')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('audit_log_entries'); + } +};