mirror of
https://github.com/Kovah/LinkAce.git
synced 2025-01-17 13:18:21 +01:00
Add audit logs for settings (#467)
This commit is contained in:
parent
18089253fe
commit
d67a04ebee
15
app/Audits/Modifiers/DarkmodeSettingModifier.php
Normal file
15
app/Audits/Modifiers/DarkmodeSettingModifier.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Audits\Modifiers;
|
||||
|
||||
class DarkmodeSettingModifier implements ModifierInterface
|
||||
{
|
||||
public function modify($value): string
|
||||
{
|
||||
return match ((int)$value) {
|
||||
0 => trans('settings.darkmode_disabled'),
|
||||
1 => trans('settings.darkmode_permanent'),
|
||||
2 => trans('settings.darkmode_auto'),
|
||||
};
|
||||
}
|
||||
}
|
16
app/Audits/Modifiers/DisplayModeSettingModifier.php
Normal file
16
app/Audits/Modifiers/DisplayModeSettingModifier.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Audits\Modifiers;
|
||||
|
||||
class DisplayModeSettingModifier implements ModifierInterface
|
||||
{
|
||||
public function modify($value): string
|
||||
{
|
||||
return match ((int)$value) {
|
||||
0 => trans('settings.display_mode_list_detailed'),
|
||||
1 => trans('settings.display_mode_cards'),
|
||||
2 => trans('settings.display_mode_list_simple'),
|
||||
3 => trans('settings.display_mode_cards_detailed'),
|
||||
};
|
||||
}
|
||||
}
|
11
app/Audits/Modifiers/LocaleSettingModifier.php
Normal file
11
app/Audits/Modifiers/LocaleSettingModifier.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Audits\Modifiers;
|
||||
|
||||
class LocaleSettingModifier implements ModifierInterface
|
||||
{
|
||||
public function modify($value): string
|
||||
{
|
||||
return config('app.available_locales.' . $value);
|
||||
}
|
||||
}
|
20
app/Http/Controllers/App/AuditController.php
Normal file
20
app/Http/Controllers/App/AuditController.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\App;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Setting;
|
||||
use OwenIt\Auditing\Models\Audit;
|
||||
|
||||
class AuditController extends Controller
|
||||
{
|
||||
public function __invoke()
|
||||
{
|
||||
$settingsHistory = Audit::where('auditable_type', Setting::class)->with('auditable')
|
||||
->latest()->paginate(pageName: 'settings');
|
||||
|
||||
return view('app.audit-logs', [
|
||||
'settings_history' => $settingsHistory,
|
||||
]);
|
||||
}
|
||||
}
|
@ -52,20 +52,21 @@ class SystemSettingsController extends Controller
|
||||
|
||||
if ($guestSharingSettings) {
|
||||
foreach (config('sharing.services') as $service => $details) {
|
||||
$toggle = array_key_exists($service, $guestSharingSettings);
|
||||
$toggle = (int)array_key_exists($service, $guestSharingSettings);
|
||||
|
||||
Setting::updateOrCreate([
|
||||
'user_id' => null,
|
||||
'key' => 'guest_share_' . $service,
|
||||
], [
|
||||
'key' => 'guest_share_' . $service,
|
||||
'value' => $toggle,
|
||||
'value' => (string)$toggle,
|
||||
'user_id' => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Cache::forget('systemsettings');
|
||||
Cache::forget('settings_keys');
|
||||
|
||||
flash(trans('settings.settings_saved'));
|
||||
return redirect()->route('get-systemsettings');
|
||||
|
@ -12,6 +12,7 @@ use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
@ -73,16 +74,18 @@ class UserSettingsController extends Controller
|
||||
$userServices = $userServices['share'] ?? [];
|
||||
|
||||
foreach (config('sharing.services') as $service => $details) {
|
||||
$toggle = array_key_exists($service, $userServices);
|
||||
$toggle = (int)array_key_exists($service, $userServices);
|
||||
|
||||
Setting::updateOrCreate([
|
||||
'user_id' => $userId,
|
||||
'key' => 'share_' . $service,
|
||||
], [
|
||||
'value' => $toggle,
|
||||
'value' => (string)$toggle,
|
||||
]);
|
||||
}
|
||||
|
||||
Cache::forget('settings_keys');
|
||||
|
||||
flash(trans('settings.settings_saved'), 'success');
|
||||
return redirect()->back();
|
||||
}
|
||||
|
@ -2,8 +2,16 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Audits\Modifiers\BooleanModifier;
|
||||
use App\Audits\Modifiers\DarkmodeSettingModifier;
|
||||
use App\Audits\Modifiers\DisplayModeSettingModifier;
|
||||
use App\Audits\Modifiers\LocaleSettingModifier;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use OwenIt\Auditing\Auditable as AuditableTrait;
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
|
||||
/**
|
||||
* Class Setting
|
||||
@ -16,8 +24,10 @@ use Illuminate\Database\Eloquent\Model;
|
||||
* @method static Builder|Setting byUser($user_id)
|
||||
* @method static Builder|Setting systemOnly()
|
||||
*/
|
||||
class Setting extends Model
|
||||
class Setting extends Model implements Auditable
|
||||
{
|
||||
use AuditableTrait;
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
public $fillable = [
|
||||
@ -31,8 +41,53 @@ class Setting extends Model
|
||||
];
|
||||
|
||||
/*
|
||||
| ========================================================================
|
||||
| SCOPES
|
||||
* ========================================================================
|
||||
* AUDIT SETTINGS
|
||||
*/
|
||||
|
||||
protected $auditEvents = [
|
||||
'updated',
|
||||
];
|
||||
|
||||
public static array $auditModifiers = [
|
||||
'archive_backups_enabled' => BooleanModifier::class,
|
||||
'archive_private_backups_enabled' => BooleanModifier::class,
|
||||
'darkmode_setting' => DarkmodeSettingModifier::class,
|
||||
'link_display_mode' => DisplayModeSettingModifier::class,
|
||||
'links_new_tab' => BooleanModifier::class,
|
||||
'links_private_default' => BooleanModifier::class,
|
||||
'lists_private_default' => BooleanModifier::class,
|
||||
'locale' => LocaleSettingModifier::class,
|
||||
'markdown_for_text' => BooleanModifier::class,
|
||||
'notes_private_default' => BooleanModifier::class,
|
||||
'private_default' => BooleanModifier::class,
|
||||
'share_service' => BooleanModifier::class,
|
||||
'system_guest_access' => BooleanModifier::class,
|
||||
'tags_private_default' => BooleanModifier::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Instead of having 'value' as the changed field, use the actual settings
|
||||
* key as the changed field.
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function transformAudit(array $data): array
|
||||
{
|
||||
$keys = self::getSettingKeys();
|
||||
$key = $keys[$data['auditable_id']];
|
||||
|
||||
$data['old_values'][$key] = $data['old_values']['value'];
|
||||
$data['new_values'][$key] = $data['new_values']['value'];
|
||||
unset($data['old_values']['value'], $data['new_values']['value']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/*
|
||||
* ========================================================================
|
||||
* SCOPES
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -57,4 +112,24 @@ class Setting extends Model
|
||||
{
|
||||
return $query->whereNull('user_id');
|
||||
}
|
||||
|
||||
/*
|
||||
* ========================================================================
|
||||
* RELATIONSHIPS
|
||||
*/
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'user_id');
|
||||
}
|
||||
|
||||
/*
|
||||
* ========================================================================
|
||||
* METHODS
|
||||
*/
|
||||
|
||||
public static function getSettingKeys()
|
||||
{
|
||||
return Cache::rememberForever('settings_keys', fn() => Setting::get()->pluck('key', 'id'));
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\View\Components\History;
|
||||
|
||||
use App\Models\Link;
|
||||
use App\Models\LinkList;
|
||||
use Illuminate\View\Component;
|
||||
use OwenIt\Auditing\Models\Audit;
|
||||
|
||||
@ -71,7 +71,7 @@ class ListEntry extends Component
|
||||
$oldValue = $changeData['old'] ?? null;
|
||||
$newValue = $changeData['new'] ?? null;
|
||||
|
||||
/** @var Link $model */
|
||||
/** @var LinkList $model */
|
||||
$model = app($this->entry->auditable_type);
|
||||
|
||||
if (isset($model->auditModifiers[$field])) {
|
||||
|
98
app/View/Components/History/SettingsEntry.php
Normal file
98
app/View/Components/History/SettingsEntry.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace App\View\Components\History;
|
||||
|
||||
use App\Models\Setting;
|
||||
use Illuminate\View\Component;
|
||||
use OwenIt\Auditing\Models\Audit;
|
||||
|
||||
class SettingsEntry extends Component
|
||||
{
|
||||
public function __construct(private Audit $entry, private array $changes = [])
|
||||
{
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
$timestamp = formatDateTime($this->entry->created_at);
|
||||
|
||||
foreach ($this->entry->getModified() as $field => $change) {
|
||||
$this->processChange($field, $change);
|
||||
}
|
||||
|
||||
return view('components.history-entry', [
|
||||
'timestamp' => $timestamp,
|
||||
'changes' => $this->changes,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function processChange(string $field, array $changeData): void
|
||||
{
|
||||
$fieldName = $this->processFieldName($field);
|
||||
[$oldValue, $newValue] = $this->processValues($field, $changeData);
|
||||
|
||||
$change = trans('linkace.history_changed', [
|
||||
'fieldname' => $fieldName,
|
||||
'oldvalue' => htmlspecialchars($oldValue),
|
||||
'newvalue' => htmlspecialchars($newValue),
|
||||
]);
|
||||
|
||||
$this->changes[] = $change;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the field name appearance to make sure it is properly displayed
|
||||
* in the audit log.
|
||||
* All guest settings will get the 'guest_' prefix removed and prepend
|
||||
* 'Guest Setting:' to the field name.
|
||||
* If the setting of a user was changed, append this info to the field.
|
||||
*
|
||||
* @param string $field
|
||||
* @return string
|
||||
*/
|
||||
protected function processFieldName(string $field)
|
||||
{
|
||||
if (str_starts_with($field, 'guest_')) {
|
||||
$field = str_replace('guest_', '', $field);
|
||||
$prepend = trans('settings.guest_settings') . ': ';
|
||||
}
|
||||
|
||||
if (str_starts_with($field, 'share_')) {
|
||||
$service = str_replace('share_', '', $field);
|
||||
return trans('settings.sharing') . ': ' . trans('sharing.service.' . $service);
|
||||
}
|
||||
|
||||
if ($this->entry->auditable->user_id !== null) {
|
||||
$append = sprintf(' %s %s', trans('user.for_user'), $this->entry->auditable->user_id);
|
||||
}
|
||||
|
||||
return ($prepend ?? '') . trans('settings.' . $field) . ($append ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply specialized methods for different fields to handle particular
|
||||
* formatting needs of these fields.
|
||||
*
|
||||
* @param string $field
|
||||
* @param array $changeData
|
||||
* @return array
|
||||
*/
|
||||
protected function processValues(string $field, array $changeData): array
|
||||
{
|
||||
$oldValue = $changeData['old'] ?? null;
|
||||
$newValue = $changeData['new'] ?? null;
|
||||
|
||||
if (str_contains($field, 'guest_share_') || str_contains($field, 'share_')) {
|
||||
$field = 'share_service';
|
||||
}
|
||||
|
||||
if (isset(Setting::$auditModifiers[$field])) {
|
||||
$modifier = app(Setting::$auditModifiers[$field]);
|
||||
$oldValue = $modifier->modify($oldValue);
|
||||
$newValue = $modifier->modify($newValue);
|
||||
return [$oldValue, $newValue];
|
||||
}
|
||||
|
||||
return [$oldValue, $newValue];
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\View\Components\History;
|
||||
|
||||
use App\Models\Link;
|
||||
use App\Models\Tag;
|
||||
use Illuminate\View\Component;
|
||||
use OwenIt\Auditing\Models\Audit;
|
||||
|
||||
@ -71,7 +71,7 @@ class TagEntry extends Component
|
||||
$oldValue = $changeData['old'] ?? null;
|
||||
$newValue = $changeData['new'] ?? null;
|
||||
|
||||
/** @var Link $model */
|
||||
/** @var Tag $model */
|
||||
$model = app($this->entry->auditable_type);
|
||||
|
||||
if (isset($model->auditModifiers[$field])) {
|
||||
|
8
lang/en_US/audit.php
Normal file
8
lang/en_US/audit.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'log' => 'Audit Log',
|
||||
'settings_history' => 'Settings History',
|
||||
|
||||
];
|
@ -7,7 +7,7 @@ return [
|
||||
'system_settings' => 'System Settings',
|
||||
'guest_settings' => 'Guest Settings',
|
||||
|
||||
'language' => 'Language',
|
||||
'locale' => 'Language',
|
||||
'timezone' => 'Timezone',
|
||||
'date_format' => 'Date Format',
|
||||
'time_format' => 'Time Format',
|
||||
@ -34,6 +34,7 @@ return [
|
||||
'archive_private_backups_enabled' => 'Enable backups for private links',
|
||||
'archive_private_backups_enabled_help' => 'If enabled, private links will also be saved. Backups must be enabled.',
|
||||
|
||||
'link_display_mode' => 'Link Display Mode',
|
||||
'display_mode' => 'Display links as',
|
||||
'display_mode_list_detailed' => 'list with many details',
|
||||
'display_mode_list_simple' => 'list with less details',
|
||||
@ -41,10 +42,11 @@ return [
|
||||
'display_mode_cards_detailed' => 'cards with many details',
|
||||
|
||||
'sharing' => 'Link Sharing',
|
||||
'guest_sharing' => 'Guest Link Sharing',
|
||||
'sharing_help' => 'Enable all services you want to display for links, to be able to share them easily with one click.',
|
||||
'sharing_toggle' => 'Toggle all on/off',
|
||||
|
||||
'darkmode' => 'Darkmode',
|
||||
'darkmode_setting' => 'Darkmode',
|
||||
'darkmode_help' => 'You can either choose to turn on permanently or automatically based on your device settings. (<small>Check <a href="https://caniuse.com/#search=prefers-color-scheme">here</a> if your browser supports automatic detection</small>)',
|
||||
'darkmode_disabled' => 'Disabled',
|
||||
'darkmode_auto' => 'Automatically',
|
||||
|
@ -7,4 +7,5 @@ return [
|
||||
'email' => 'Email',
|
||||
|
||||
'hello' => 'Hello :user!',
|
||||
'for_user' => 'for User',
|
||||
];
|
||||
|
22
resources/views/app/audit-logs.blade.php
Normal file
22
resources/views/app/audit-logs.blade.php
Normal file
@ -0,0 +1,22 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
@lang('audit.settings_history')
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="history mb-6">
|
||||
@foreach($settings_history as $entry)
|
||||
<x-history.settings-entry :entry="$entry"/>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
{!! $settings_history->onEachSide(1)->links() !!}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@endsection
|
@ -1,7 +1,7 @@
|
||||
<div class="mb-3 my-5">
|
||||
|
||||
<h5>
|
||||
@lang('settings.darkmode')
|
||||
@lang('settings.darkmode_setting')
|
||||
</h5>
|
||||
|
||||
<p class="my-3 small">@lang('settings.darkmode_help')</p>
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="form-label" for="locale">
|
||||
@lang('settings.language')
|
||||
@lang('settings.locale')
|
||||
</label>
|
||||
<select id="locale" name="locale"
|
||||
class="simple-select {{ $errors->has('locale') ? ' is-invalid' : '' }}">
|
||||
@ -23,7 +23,7 @@
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@if ($errors->has('locale'))
|
||||
@if($errors->has('locale'))
|
||||
<p class="invalid-feedback" role="alert">
|
||||
{{ $errors->first('locale') }}
|
||||
</p>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div class="mb-3 my-5">
|
||||
|
||||
<h5>
|
||||
@lang('settings.darkmode')
|
||||
@lang('settings.darkmode_setting')
|
||||
</h5>
|
||||
|
||||
<p class="my-3 small">@lang('settings.darkmode_help')</p>
|
||||
|
@ -28,6 +28,9 @@
|
||||
<a href="{{ route('get-systemsettings') }}" class="dropdown-item">
|
||||
@lang('settings.system_settings')
|
||||
</a>
|
||||
<a href="{{ route('system-audit') }}" class="dropdown-item">
|
||||
@lang('audit.log')
|
||||
</a>
|
||||
<a href="{{ route('system-logs') }}" class="dropdown-item">
|
||||
@lang('linkace.system_logs')
|
||||
</a>
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\App\AuditController;
|
||||
use App\Http\Controllers\App\BookmarkletController;
|
||||
use App\Http\Controllers\App\DashboardController;
|
||||
use App\Http\Controllers\App\ExportController;
|
||||
@ -136,6 +137,8 @@ Route::group(['middleware' => ['auth']], function () {
|
||||
|
||||
Route::get('system/logs', [LogViewerController::class, 'index'])
|
||||
->name('system-logs');
|
||||
|
||||
Route::get('system/audit', AuditController::class)->name('system-audit');
|
||||
});
|
||||
|
||||
// Guest access routes
|
||||
|
140
tests/Components/History/SettingsEntryTest.php
Normal file
140
tests/Components/History/SettingsEntryTest.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Components\History;
|
||||
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\View\Components\History\SettingsEntry;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use OwenIt\Auditing\Models\Audit;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SettingsEntryTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$user = User::factory()->create(['name' => 'TestUser']);
|
||||
$this->actingAs($user);
|
||||
}
|
||||
|
||||
public function testStringSettingsChange(): void
|
||||
{
|
||||
$setting = Setting::create(['key' => 'timezone', 'value' => 'Europe/Berlin']);
|
||||
$setting->update(['value' => 'UTC']);
|
||||
|
||||
$historyEntry = Audit::where('auditable_type', Setting::class)->with('auditable')->latest()->first();
|
||||
|
||||
$output = (new SettingsEntry($historyEntry))->render();
|
||||
|
||||
$this->assertStringContainsString(
|
||||
'Changed Timezone from <code>Europe/Berlin</code> to <code>UTC</code>',
|
||||
$output
|
||||
);
|
||||
}
|
||||
|
||||
public function testBooleanSettingsChange(): void
|
||||
{
|
||||
$setting = Setting::create(['key' => 'archive_backups_enabled', 'value' => true]);
|
||||
$setting->update(['value' => false]);
|
||||
|
||||
$historyEntry = Audit::where('auditable_type', Setting::class)->with('auditable')->latest()->first();
|
||||
|
||||
$output = (new SettingsEntry($historyEntry))->render();
|
||||
|
||||
$this->assertStringContainsString('Changed Enable backups from <code>Yes</code> to <code>No</code>', $output);
|
||||
}
|
||||
|
||||
public function testDarkmodeSettingsChange(): void
|
||||
{
|
||||
$setting = Setting::create(['key' => 'darkmode_setting', 'value' => 1]);
|
||||
$setting->update(['value' => 2]);
|
||||
|
||||
$historyEntry = Audit::where('auditable_type', Setting::class)->with('auditable')->latest()->first();
|
||||
|
||||
$output = (new SettingsEntry($historyEntry))->render();
|
||||
|
||||
$this->assertStringContainsString(
|
||||
'Changed Darkmode from <code>Permanent</code> to <code>Automatically</code>',
|
||||
$output
|
||||
);
|
||||
}
|
||||
|
||||
public function testDisplayModeSettingsChange(): void
|
||||
{
|
||||
$setting = Setting::create(['key' => 'link_display_mode', 'value' => 1]);
|
||||
$setting->update(['value' => 2]);
|
||||
|
||||
$historyEntry = Audit::where('auditable_type', Setting::class)->with('auditable')->latest()->first();
|
||||
|
||||
$output = (new SettingsEntry($historyEntry))->render();
|
||||
|
||||
$this->assertStringContainsString(
|
||||
'Changed Link Display Mode from <code>cards with less details</code> to <code>list with less details</code>',
|
||||
$output
|
||||
);
|
||||
}
|
||||
|
||||
public function testLocaleSettingsChange(): void
|
||||
{
|
||||
$setting = Setting::create(['key' => 'locale', 'value' => 'en_US']);
|
||||
$setting->update(['value' => 'de_DE']);
|
||||
|
||||
$historyEntry = Audit::where('auditable_type', Setting::class)->with('auditable')->latest()->first();
|
||||
|
||||
$output = (new SettingsEntry($historyEntry))->render();
|
||||
|
||||
$this->assertStringContainsString(
|
||||
'Changed Language from <code>English</code> to <code>Deutsch</code>',
|
||||
$output
|
||||
);
|
||||
}
|
||||
|
||||
public function testSharingSettingsChange(): void
|
||||
{
|
||||
$setting = Setting::create(['key' => 'share_email', 'value' => true]);
|
||||
$setting->update(['value' => false]);
|
||||
|
||||
$historyEntry = Audit::where('auditable_type', Setting::class)->with('auditable')->latest()->first();
|
||||
|
||||
$output = (new SettingsEntry($historyEntry))->render();
|
||||
|
||||
$this->assertStringContainsString(
|
||||
'Changed Link Sharing: Email from <code>Yes</code> to <code>No</code>',
|
||||
$output
|
||||
);
|
||||
}
|
||||
|
||||
public function testGuestSettingsChange(): void
|
||||
{
|
||||
$setting = Setting::create(['key' => 'guest_listitem_count', 'value' => 24]);
|
||||
$setting->update(['value' => 60]);
|
||||
|
||||
$historyEntry = Audit::where('auditable_type', Setting::class)->with('auditable')->latest()->first();
|
||||
|
||||
$output = (new SettingsEntry($historyEntry))->render();
|
||||
|
||||
$this->assertStringContainsString(
|
||||
'Changed Guest Settings: Number of Items in Lists from <code>24</code> to <code>60</code>',
|
||||
$output
|
||||
);
|
||||
}
|
||||
|
||||
public function testUserSettingsChange(): void
|
||||
{
|
||||
$setting = Setting::create(['key' => 'locale', 'value' => 'en_US', 'user_id' => 1]);
|
||||
$setting->update(['value' => 'de_DE']);
|
||||
|
||||
$historyEntry = Audit::where('auditable_type', Setting::class)->with('auditable')->latest()->first();
|
||||
|
||||
$output = (new SettingsEntry($historyEntry))->render();
|
||||
|
||||
$this->assertStringContainsString(
|
||||
'Changed Language for User 1 from <code>English</code> to <code>Deutsch</code>',
|
||||
$output
|
||||
);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user