Skip to content

Commit

Permalink
Added Audit Trail
Browse files Browse the repository at this point in the history
  • Loading branch information
nasrulhazim committed Feb 12, 2024
1 parent 0ce6724 commit 97e7d8d
Show file tree
Hide file tree
Showing 19 changed files with 473 additions and 7 deletions.
35 changes: 35 additions & 0 deletions app/Http/Controllers/Administration/AuditTrailController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace App\Http\Controllers\Administration;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class AuditTrailController extends Controller
{
/**
* Handle the incoming request.
*/
public function index(Request $request)
{
$this->authorize('viewAny', config('audit.implementation'));

$sub = 'Audit trail log';

return view('administration.audit-trail.index', compact('sub'));
}

/**
* Handle the incoming request.
*/
public function show(Request $request, string $uuid)
{
$audit = config('audit.implementation')::whereUuid($uuid)->firstOrFail();

$this->authorize('view', $audit);

$sub = 'Audit trail details';

return view('administration.audit-trail.show', compact('audit', 'sub'));
}
}
97 changes: 97 additions & 0 deletions app/Livewire/Datatable/AuditTrail.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

namespace App\Livewire\Datatable;

use App\Models\Audit as Model;
use App\View\ActionColumn;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
use Rappasoft\LaravelLivewireTables\Views\Filters\DateFilter;
use Rappasoft\LaravelLivewireTables\Views\Filters\SelectFilter;

class AuditTrail extends DataTableComponent
{
public function configure(): void
{
$this->setPrimaryKey('uuid')
->setEagerLoadAllRelationsEnabled()
->setAdditionalSelects([
'audits.user_id',
'audits.auditable_id',
'audits.old_values',
'audits.new_values',
'audits.created_at',
])
->setDefaultSort('created_at', 'desc')
->setFilterLayoutSlideDown();
}

public function columns(): array
{
return [
Column::make('Event', 'event')
->view('components.badge')
->searchable()
->sortable(),
Column::make('User', 'user.name')
->searchable()
->sortable(),
Column::make('IP Address', 'ip_address')
->searchable()
->sortable(),
Column::make('Created Date', 'created_at')
->format(fn ($value) => Carbon::parse($value)->format('d-m-Y H:i:s'))
->searchable()
->sortable(),
Column::make('URL', 'url')
->format(fn ($value) => str_replace(url('/'), '', $value))
->searchable()
->sortable(),
Column::make('Type', 'auditable_type')
->format(fn ($value) => class_basename($value))
->searchable()
->sortable(),
ActionColumn::make('Actions', 'uuid')
->form('')
->setView('administration.audit-trail.partials.datatable-actions'),
];
}

/**
* The base query.
*/
public function builder(): Builder
{
return Model::query();
}

public function filters(): array
{
return [
SelectFilter::make('Event')
->options([
'created' => 'Created',
'updated' => 'Updated',
'deleted' => 'Deleted',
])
->filter(function (Builder $builder, $value) {
$builder->where('event', $value);
}),
SelectFilter::make('Type')
->options(audit_type_options())
->filter(function (Builder $builder, $value) {
$builder->where('auditable_type', $value);
}),
DateFilter::make('Date From', 'from')
->filter(function (Builder $builder, string $value) {
$builder->whereDate('audits.created_at', '>=', $value);
})->setFilterSlidedownColspan('2'),
DateFilter::make('Date To', 'to')
->filter(function (Builder $builder, string $value) {
$builder->whereDate('audits.created_at', '<=', $value);
})->setFilterSlidedownColspan('2'),
];
}
}
15 changes: 15 additions & 0 deletions app/Models/Audit.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace App\Models;

use App\Concerns\InteractsWithUuid;

class Audit extends \OwenIt\Auditing\Models\Audit
{
use InteractsWithUuid;

public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
}
82 changes: 82 additions & 0 deletions app/Policies/AuditPolicy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

namespace App\Policies;

use App\Models\Audit;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class AuditPolicy
{
use HandlesAuthorization;

/**
* Determine whether the user can view any models.
*
* @return \Illuminate\Auth\Access\Response|bool
*/
public function viewAny(User $user)
{
return auth()->user()->can('view-audit-administration');
}

/**
* Determine whether the user can view the model.
*
* @return \Illuminate\Auth\Access\Response|bool
*/
public function view(User $user, Audit $audit)
{
return auth()->user()->can('view-audit-administration');
}

/**
* Determine whether the user can create models.
*
* @return \Illuminate\Auth\Access\Response|bool
*/
public function create(User $user)
{
return false;
}

/**
* Determine whether the user can update the model.
*
* @return \Illuminate\Auth\Access\Response|bool
*/
public function update(User $user, Audit $audit)
{
return false;
}

/**
* Determine whether the user can delete the model.
*
* @return \Illuminate\Auth\Access\Response|bool
*/
public function delete(User $user, Audit $audit)
{
return false;
}

/**
* Determine whether the user can restore the model.
*
* @return \Illuminate\Auth\Access\Response|bool
*/
public function restore(User $user, Audit $audit)
{
return false;
}

/**
* Determine whether the user can permanently delete the model.
*
* @return \Illuminate\Auth\Access\Response|bool
*/
public function forceDelete(User $user, Audit $audit)
{
return false;
}
}
2 changes: 1 addition & 1 deletion app/View/ActionColumn.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function form(string $form): self
return $this;
}

public function setView($view)
public function setView($view): self
{
$this->view = $view;

Expand Down
2 changes: 1 addition & 1 deletion config/audit.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
|
*/

'implementation' => OwenIt\Auditing\Models\Audit::class,
'implementation' => App\Models\Audit::class,

/*
|--------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public function up(): void
{
Schema::create('audits', function (Blueprint $table) {
$table->bigIncrements('id');
$table->uuid('uuid');
$table->string('user_type')->nullable();
$table->unsignedBigInteger('user_id')->nullable();
$table->string('event');
Expand Down
14 changes: 14 additions & 0 deletions resources/views/administration/audit-trail/index.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Audit Trail') }}
</h2>
<div class="my-2">{{ $sub }}</div>
</x-slot>

<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
@livewire('datatable.audit-trail')
</div>
</div>
</x-app-layout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="flex justify-items-center">
@can('view', $row)
<a class="cursor-pointer mr-4" href="{{ route('admin.audit-trail.show', $row->uuid) }}" x-data x-tooltip="View Record Details">
<x-icon name="o-eye" class="text-indigo hover:font-bold mr-3 flex-shrink-0 h-6 w-6">
</x-icon>
</a>
@endcan
</div>
77 changes: 77 additions & 0 deletions resources/views/administration/audit-trail/partials/info.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<div class="bg-white mx-8 py-4 px-8 rounded shadow-sm">
<div class="lg:flex lg:items-center lg:justify-between">
<div class="min-w-0 flex-1">
<h2
class="text-2xl font-semibold cursor-pointer hover:text-slate-900 leading-7 text-gray-700 sm:truncate sm:text-3xl sm:tracking-tight">
Audit for <span class="">{{ str(class_basename($audit->auditable_type))->headline() }}</span>
<x-badge :type="$audit->event" :label="strtoupper($audit->event)" x-data x-tooltip="Event" />
</h2>
<div class="mt-1 flex flex-col sm:mt-0 sm:flex-row sm:flex-wrap sm:space-x-6">
<div class="mt-2 flex items-center text-sm text-gray-500 hover:text-slate-900 cursor-pointer" x-data
x-tooltip="IP Address">
<x-icon name="o-map" class="w-4 h-4 mr-2 text-slate-700"></x-icon>
{{ $audit->ip_address }}
</div>
</div>
<div class="mt-1 flex flex-col sm:mt-0 sm:flex-row sm:flex-wrap sm:space-x-6">
<div class="mt-2 flex items-center text-sm text-gray-500 hover:text-slate-900 cursor-pointer" x-data
x-tooltip="URL">
<x-icon name="o-link" class="w-4 h-4 mr-2 text-slate-700"></x-icon>
<span class="text-indigo-700">{{ $audit->url }}</span>
</div>
</div>
<div class="mt-1 flex flex-col sm:mt-0 sm:flex-row sm:flex-wrap sm:space-x-6">
<div class="mt-2 flex items-center text-sm text-gray-500 hover:text-slate-900 cursor-pointer" x-data
x-tooltip="Browser">
<x-icon name="o-desktop-computer" class="w-4 h-4 mr-2 text-slate-700"></x-icon>
{{ $audit->user_agent }}
</div>
</div>
<div class="mt-1 flex flex-col sm:mt-0 sm:flex-row sm:flex-wrap sm:space-x-6">
<div class="mt-2 flex items-center text-sm text-gray-500 hover:text-slate-900 cursor-pointer" x-data
x-tooltip="Event Recorded Date & Time">
<x-icon name="o-clock" class="w-4 h-4 mr-2 text-slate-700"></x-icon>
{{ $audit->created_at->format('Y-m-d H:i:s') }}
</div>
</div>
</div>
@if ($audit->user)
<div class="flex-row text-right " x-data x-tooltip="Changes made by {{ $audit->user->name }}">
<div class="mb-2 flex justify-center justify-items-center">
<x-avatar class="h-10 w-10 text-2xl" :name="$audit->user->name" />
</div>
<div class="text-center">
<span class="text-sm text-slate-700">{{ $audit->user->name }}</span>
<br>
<span class="text-xs text-slate-700 italic">{{ $audit->user->email }}</span>
</div>
</div>
@endif
</div>
</div>

<div class="bg-white mx-8 py-4 px-8 rounded shadow-sm mt-8">
<div class="lg:flex lg:items-center lg:justify-between">
<div class="min-w-0 flex-1">
<h2
class="text-2xl font-semibold cursor-pointer hover:text-slate-900 leading-7 text-gray-700 sm:truncate sm:text-3xl sm:tracking-tight">
Before
</h2>
</div>
</div>

@include('administration.audit-trail.partials.table', ['values' => $audit->old_values])
</div>

<div class="bg-white mx-8 py-4 px-8 rounded shadow-sm mt-8">
<div class="lg:flex lg:items-center lg:justify-between">
<div class="min-w-0 flex-1">
<h2
class="text-2xl font-semibold cursor-pointer hover:text-slate-900 leading-7 text-gray-700 sm:truncate sm:text-3xl sm:tracking-tight">
After
</h2>
</div>
</div>

@include('administration.audit-trail.partials.table', ['values' => $audit->new_values])
</div>
Empty file.
Empty file.
Loading

0 comments on commit 97e7d8d

Please sign in to comment.