1
0
mirror of https://github.com/Kovah/LinkAce.git synced 2025-04-20 23:11:56 +02:00

Add base for activity logs (#466)

This commit is contained in:
Kovah 2022-06-21 23:06:03 +02:00
parent cce410eac3
commit 50a40e8914
No known key found for this signature in database
GPG Key ID: AAAA031BA9830D7B
14 changed files with 321 additions and 9 deletions

10
app/Enums/ActivityLog.php Normal file
View File

@ -0,0 +1,10 @@
<?php
namespace App\Enums;
class ActivityLog
{
public const SYSTEM_CRON_TOKEN_REGENERATED = 'system.cron_token_regenerated';
public const USER_API_TOKEN_GENERATED = 'user.api_token_regenerated';
}

View File

@ -4,8 +4,8 @@ use App\Helper\Sharing;
use App\Helper\WaybackMachine;
use App\Models\Link;
use App\Models\Setting;
use Carbon\CarbonInterface;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
@ -65,11 +65,11 @@ function systemsettings(string $key = '')
/**
* Output a correctly formatted date with the correct timezone
*
* @param Carbon $date
* @param CarbonInterface $date
* @param bool $use_relational
* @return string
*/
function formatDateTime(Carbon $date, bool $use_relational = false): string
function formatDateTime(CarbonInterface $date, bool $use_relational = false): string
{
$timezone = config('app.timezone');

View File

@ -6,11 +6,14 @@ use App\Http\Controllers\Controller;
use App\Models\Setting;
use App\Models\User;
use OwenIt\Auditing\Models\Audit;
use Spatie\Activitylog\Models\Activity;
class AuditController extends Controller
{
public function __invoke()
{
$activities = Activity::query()->with('causer')->latest()->paginate(pageName: 'activities_page');
$settingsHistory = Audit::where('auditable_type', Setting::class)->with('auditable')
->latest()->paginate(pageName: 'settings_page');
@ -18,6 +21,7 @@ class AuditController extends Controller
->latest()->paginate(pageName: 'user_page');
return view('app.audit-logs', [
'activities' => $activities,
'settings_history' => $settingsHistory,
'user_history' => $userHistory,
]);

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\App;
use App\Enums\ActivityLog;
use App\Helper\UpdateHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\SystemSettingsUpdateRequest;
@ -91,6 +92,8 @@ class SystemSettingsController extends Controller
Cache::forget('systemsettings');
activity()->by(auth()->user())->log(ActivityLog::SYSTEM_CRON_TOKEN_REGENERATED);
return response()->json([
'new_token' => $newToken,
]);

View File

@ -4,6 +4,7 @@ namespace App\Http\Controllers\App;
use App\Actions\Fortify\UpdateUserPassword;
use App\Actions\Fortify\UpdateUserProfileInformation;
use App\Enums\ActivityLog;
use App\Helper\LinkAce;
use App\Http\Controllers\Controller;
use App\Http\Requests\UserSettingsUpdateRequest;
@ -118,6 +119,8 @@ class UserSettingsController extends Controller
$request->user()->api_token = $new_token;
$request->user()->save();
activity()->by(auth()->user())->log(ActivityLog::USER_API_TOKEN_GENERATED);
return response()->json([
'new_token' => $new_token,
]);

View File

@ -0,0 +1,43 @@
<?php
namespace App\View\Components\History;
use Illuminate\View\Component;
use Spatie\Activitylog\Models\Activity;
class ActivityEntry extends Component
{
private array $changes = [];
private string $translateBase = 'audit.logs';
public function __construct(private Activity $activity)
{
}
public function render()
{
$timestamp = formatDateTime($this->activity->created_at);
$this->processActivity();
return view('components.history-entry', [
'timestamp' => $timestamp,
'changes' => $this->changes,
]);
}
protected function processActivity(): void
{
$change = trans($this->translateBase . '.' . $this->activity->description);
if ($this->activity->causer() !== null) {
$this->changes[] = trans('audit.activity_entry_with_causer', [
'change' => $change,
'causer' => $this->activity->causer?->name ?: trans('user.unknown_user'),
]);
return;
}
$this->changes[] = $change;
}
}

View File

@ -21,6 +21,7 @@
"rap2hpoutre/laravel-log-viewer": "^2.2",
"sentry/sentry-laravel": "^2.3",
"shaarli/netscape-bookmark-parser": "^v3.2",
"spatie/laravel-activitylog": "^4.5",
"spatie/laravel-backup": "^8.1.2",
"symfony/http-client": "^6.0",
"symfony/mailgun-mailer": "^6.0"

93
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "0ab96c681f49e103b7c5e85954d29678",
"content-hash": "2883267016653be160d0af84f30957f9",
"packages": [
{
"name": "aws/aws-crt-php",
@ -5053,6 +5053,97 @@
],
"time": "2022-03-10T16:01:42+00:00"
},
{
"name": "spatie/laravel-activitylog",
"version": "4.5.3",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-activitylog.git",
"reference": "feb1a37d649b03711e546807688fbea53469dfc3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-activitylog/zipball/feb1a37d649b03711e546807688fbea53469dfc3",
"reference": "feb1a37d649b03711e546807688fbea53469dfc3",
"shasum": ""
},
"require": {
"illuminate/config": "^8.0 || ^9.0",
"illuminate/database": "^8.53 || ^9.0",
"illuminate/support": "^8.0 || ^9.0",
"php": "^8.0",
"spatie/laravel-package-tools": "^1.6.3"
},
"require-dev": {
"ext-json": "*",
"orchestra/testbench": "^6.23 || ^7.0",
"pestphp/pest": "^1.20"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Spatie\\Activitylog\\ActivitylogServiceProvider"
]
}
},
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"Spatie\\Activitylog\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
},
{
"name": "Sebastian De Deyne",
"email": "sebastian@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
},
{
"name": "Tom Witkowski",
"email": "dev.gummibeer@gmail.com",
"homepage": "https://gummibeer.de",
"role": "Developer"
}
],
"description": "A very simple activity logger to monitor the users of your website or application",
"homepage": "https://github.com/spatie/activitylog",
"keywords": [
"activity",
"laravel",
"log",
"spatie",
"user"
],
"support": {
"issues": "https://github.com/spatie/laravel-activitylog/issues",
"source": "https://github.com/spatie/laravel-activitylog/tree/4.5.3"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2022-05-31T10:01:05+00:00"
},
{
"name": "spatie/laravel-backup",
"version": "8.1.2",

52
config/activitylog.php Normal file
View File

@ -0,0 +1,52 @@
<?php
return [
/*
* If set to false, no activities will be saved to the database.
*/
'enabled' => env('ACTIVITY_LOGGER_ENABLED', true),
/*
* When the clean-command is executed, all recording activities older than
* the number of days specified here will be deleted.
*/
'delete_records_older_than_days' => env('ACTIVITY_LOGGER_RECORD_DELETION_THRESHOLD', 365),
/*
* If no log name is passed to the activity() helper
* we use this default log name.
*/
'default_log_name' => 'default',
/*
* You can specify an auth driver here that gets user models.
* If this is null we'll use the current Laravel auth driver.
*/
'default_auth_driver' => null,
/*
* If set to true, the subject returns soft deleted models.
*/
'subject_returns_soft_deleted_models' => false,
/*
* This model will be used to log activity.
* It should implement the Spatie\Activitylog\Contracts\Activity interface
* and extend Illuminate\Database\Eloquent\Model.
*/
'activity_model' => \Spatie\Activitylog\Models\Activity::class,
/*
* This is the name of the table that will be created by the migration and
* used by the Activity model shipped with this package.
*/
'table_name' => 'activity_log',
/*
* This is the database connection that will be used by the migration and
* the Activity model shipped with this package. In case it's not set
* Laravel's database.default will be used instead.
*/
'database_connection' => env('ACTIVITY_LOGGER_DB_CONNECTION'),
];

View File

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateActivityLogTable extends Migration
{
public function up()
{
Schema::connection(config('activitylog.database_connection'))
->create(config('activitylog.table_name'), function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('log_name')->nullable();
$table->text('description');
$table->nullableMorphs('subject', 'subject');
$table->string('event')->nullable();
$table->nullableMorphs('causer', 'causer');
$table->json('properties')->nullable();
$table->uuid('batch_uuid')->nullable();
$table->timestamps();
$table->index('log_name');
});
}
public function down()
{
Schema::connection(config('activitylog.database_connection'))->dropIfExists(config('activitylog.table_name'));
}
}

View File

@ -3,8 +3,21 @@
return [
'log' => 'Audit Log',
'system_events' => 'System Events',
'settings_history' => 'Settings History',
'user_history' => 'User History',
'user_history_entry' => 'User :id: :change',
'no_logs_found' => 'No logs found',
'activity_entry_with_causer' => ':change by :causer',
'logs' => [
'system' => [
'cron_token_regenerated' => 'System: Cron Token was re-generated',
],
'user' => [
'api_token_regenerated' => 'User: API Token was re-generated',
],
],
];

View File

@ -13,4 +13,5 @@ return [
'hello' => 'Hello :user!',
'for_user' => 'for User',
'unknown_user' => 'unknown User',
];

View File

@ -1,17 +1,38 @@
@extends('layouts.app')
@section('content')
<div class="card">
<div class="card-header">
@lang('audit.system_events')
</div>
<div class="card-body">
<div class="history mb-4">
@forelse($activities as $activity)
<x-history.activity-entry :activity="$activity"/>
@empty
<div class="text-muted">@lang('audit.no_logs_found')</div>
@endforelse
</div>
{!! $activities->onEachSide(1)->links() !!}
</div>
</div>
<div class="card mt-4">
<div class="card-header">
@lang('audit.settings_history')
</div>
<div class="card-body">
<div class="history mb-4">
@foreach($settings_history as $entry)
@forelse($settings_history as $entry)
<x-history.settings-entry :entry="$entry"/>
@endforeach
@empty
<div class="text-muted">@lang('audit.no_logs_found')</div>
@endforelse
</div>
{!! $settings_history->onEachSide(1)->links() !!}
@ -26,9 +47,11 @@
<div class="card-body">
<div class="history mb-4">
@foreach($user_history as $entry)
@forelse($user_history as $entry)
<x-history.user-entry :entry="$entry"/>
@endforeach
@empty
<div class="text-muted">@lang('audit.no_logs_found')</div>
@endforelse
</div>
{!! $user_history->onEachSide(1)->links() !!}

View File

@ -0,0 +1,38 @@
<?php
namespace Tests\Controller\App;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class AuditControllerTest extends TestCase
{
use RefreshDatabase;
/** @var User */
private $user;
protected function setUp(): void
{
parent::setUp();
$this->user = User::factory()->create();
$this->actingAs($this->user);
}
public function testAuditPage(): void
{
$response = $this->get('system/audit');
$response->assertOk()->assertSee('System Events');
}
public function testAuditPageWithEntries(): void
{
$this->post('settings/generate-cron-token');
$response = $this->get('system/audit');
$response->assertSee('System: Cron Token was re-generated');
}
}