mirror of
https://github.com/AnimeThemes/animethemes-server.git
synced 2026-07-11 01:24:46 +02:00
chore(admin): activity logs (#1197)
This commit is contained in:
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\Actions\Storage\Admin\Dump;
|
||||
|
||||
use App\Concerns\Repositories\Admin\ReconcilesDumpRepositories;
|
||||
use App\Models\Admin\ActionLog;
|
||||
use App\Models\Admin\Activity;
|
||||
use App\Models\Admin\Announcement;
|
||||
use App\Models\Admin\Dump;
|
||||
use App\Models\Admin\Feature;
|
||||
@@ -27,7 +27,8 @@ class DumpAdminAction extends DumpAction
|
||||
{
|
||||
return [
|
||||
'action_events', // Nova events
|
||||
ActionLog::TABLE,
|
||||
'action_logs',
|
||||
Activity::TABLE,
|
||||
Announcement::TABLE,
|
||||
Dump::TABLE,
|
||||
Feature::TABLE,
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Concerns\Filament\ActionLogs;
|
||||
|
||||
use App\Models\Admin\ActionLog;
|
||||
use Filament\Actions\Action;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
use Throwable;
|
||||
|
||||
trait HasActionLogs
|
||||
{
|
||||
protected string $batchId = '';
|
||||
protected ?ActionLog $actionLog = null;
|
||||
protected ?Model $recordLog = null;
|
||||
protected ?Model $parentRecordLog = null;
|
||||
protected ?Model $pivot = null;
|
||||
|
||||
public function createBatchId(): string
|
||||
{
|
||||
$this->batchId = Str::orderedUuid()->__toString();
|
||||
|
||||
return $this->batchId;
|
||||
}
|
||||
|
||||
public function createActionLog(Action $action, Model $record, ?bool $shouldCreateNewBatchId = true): void
|
||||
{
|
||||
if ($shouldCreateNewBatchId) {
|
||||
$this->createBatchId();
|
||||
}
|
||||
|
||||
$this->recordLog = $record;
|
||||
|
||||
$actionLog = ActionLog::modelActioned(
|
||||
$this->batchId,
|
||||
$action,
|
||||
$this->recordLog,
|
||||
);
|
||||
|
||||
$this->actionLog = $actionLog;
|
||||
}
|
||||
|
||||
public function updateLog(Model $relatedModel, Model $pivot): void
|
||||
{
|
||||
$this->actionLog->update([
|
||||
ActionLog::ATTRIBUTE_TARGET_TYPE => $relatedModel->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_TARGET_ID => $relatedModel->getKey(),
|
||||
ActionLog::ATTRIBUTE_MODEL_TYPE => $pivot->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_MODEL_ID => $pivot->getKey(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function failedLog(Throwable|string|null $exception): void
|
||||
{
|
||||
$this->actionLog->failed($exception);
|
||||
|
||||
// Filament notifications
|
||||
if ($this instanceof Action) {
|
||||
$this->failureNotificationTitle(Str::limit($exception, 200));
|
||||
$this->failure();
|
||||
}
|
||||
}
|
||||
|
||||
public function finishedLog(): void
|
||||
{
|
||||
if (($actionLog = $this->actionLog) && ! $this->hasFailedLog()) {
|
||||
$actionLog->finished();
|
||||
// Filament notifications
|
||||
if ($this instanceof Action) {
|
||||
$this->success();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function batchFinishedLog(): void
|
||||
{
|
||||
$this->actionLog->batchFinished();
|
||||
}
|
||||
|
||||
public function hasFailedLog(): bool
|
||||
{
|
||||
return $this->actionLog->hasFailed();
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Concerns\Filament\ActionLogs;
|
||||
|
||||
use App\Filament\RelationManagers\BaseRelationManager;
|
||||
use App\Models\Admin\ActionLog;
|
||||
use Filament\Actions\Action;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
trait HasPivotActionLogs
|
||||
{
|
||||
public function pivotActionLog(string $actionName, BaseRelationManager $livewire, Model $record, ?Action $action = null): void
|
||||
{
|
||||
$ownerRecord = $livewire->getOwnerRecord();
|
||||
|
||||
$relation = $livewire->getRelationship();
|
||||
|
||||
if ($relation instanceof BelongsToMany) {
|
||||
ActionLog::modelPivot(
|
||||
$actionName,
|
||||
$ownerRecord,
|
||||
$record,
|
||||
$record->getRelationValue($relation->getPivotAccessor()) ?? $record,
|
||||
$action,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function associateActionLog(string $actionName, BaseRelationManager $livewire, Model $record, Action $action): void
|
||||
{
|
||||
$ownerRecord = $livewire->getOwnerRecord();
|
||||
|
||||
$relation = $livewire->getRelationship();
|
||||
|
||||
if ($relation instanceof HasMany) {
|
||||
ActionLog::modelAssociated(
|
||||
$actionName,
|
||||
$ownerRecord,
|
||||
$record,
|
||||
$action,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Concerns\Filament\ActionLogs;
|
||||
|
||||
use App\Models\Admin\ActionLog;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
|
||||
trait ModelHasActionLogs
|
||||
{
|
||||
public function actionlogs(): MorphMany
|
||||
{
|
||||
return $this->morphMany(ActionLog::class, 'actionable');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Concerns\Filament;
|
||||
|
||||
use App\Enums\Models\Admin\ActivityStatus;
|
||||
use App\Models\Admin\Activity;
|
||||
use Filament\Actions\Action;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Activitylog\Contracts\Activity as ContractsActivity;
|
||||
use Throwable;
|
||||
|
||||
trait HasActivityLogs
|
||||
{
|
||||
protected ?Activity $activity = null;
|
||||
|
||||
public function createActivityLog(Action $action, Model $record): void
|
||||
{
|
||||
/** @phpstan-ignore-next-line */
|
||||
$this->activity = activity()
|
||||
->performedOn($record)
|
||||
->withProperties($action->getData())
|
||||
->tap(function (Activity $activity): void {
|
||||
$activity->status = ActivityStatus::RUNNING;
|
||||
})
|
||||
->event($action->getLabel())
|
||||
->log('actioned');
|
||||
}
|
||||
|
||||
public function failedLog(Throwable|string|null $exception): void
|
||||
{
|
||||
$this->activity?->update([
|
||||
Activity::ATTRIBUTE_STATUS => ActivityStatus::FAILED,
|
||||
Activity::ATTRIBUTE_EXCEPTION => Str::limit($exception, 200),
|
||||
Activity::ATTRIBUTE_FINISHED_AT => now(),
|
||||
]);
|
||||
|
||||
// Filament notifications
|
||||
if ($this instanceof Action) {
|
||||
$this->failureNotificationTitle(Str::limit($exception, 200));
|
||||
$this->failure();
|
||||
}
|
||||
}
|
||||
|
||||
public function finishedLog(): void
|
||||
{
|
||||
if (! $this->hasFailedLog()) {
|
||||
$this->activity?->update([
|
||||
Activity::ATTRIBUTE_STATUS => ActivityStatus::FINISHED,
|
||||
Activity::ATTRIBUTE_FINISHED_AT => now(),
|
||||
]);
|
||||
|
||||
// Filament notifications
|
||||
if ($this instanceof Action) {
|
||||
$this->success();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function hasFailedLog(): bool
|
||||
{
|
||||
return $this->activity?->status === ActivityStatus::FAILED;
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -9,7 +9,7 @@ use Filament\Support\Colors\Color;
|
||||
use Filament\Support\Contracts\HasColor;
|
||||
use Filament\Support\Contracts\HasLabel;
|
||||
|
||||
enum ActionLogStatus: int implements HasColor, HasLabel
|
||||
enum ActivityStatus: int implements HasColor, HasLabel
|
||||
{
|
||||
use LocalizesName;
|
||||
|
||||
@@ -25,9 +25,9 @@ enum ActionLogStatus: int implements HasColor, HasLabel
|
||||
public function getColor(): string|array
|
||||
{
|
||||
return match ($this) {
|
||||
ActionLogStatus::RUNNING => Color::Amber,
|
||||
ActionLogStatus::FAILED => 'danger',
|
||||
ActionLogStatus::FINISHED => 'success',
|
||||
ActivityStatus::RUNNING => Color::Amber,
|
||||
ActivityStatus::FAILED => 'danger',
|
||||
ActivityStatus::FINISHED => 'success',
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use App\Models\Admin\ActionLog;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Throwable;
|
||||
|
||||
@@ -27,10 +25,6 @@ class Handler extends ExceptionHandler
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->reportable(function (Throwable $e): void {
|
||||
if (Filament::isServing() && $this->shouldReport($e)) {
|
||||
ActionLog::updateCurrentActionLogToFailed($e);
|
||||
}
|
||||
});
|
||||
$this->reportable(function (Throwable $e): void {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Actions\Base;
|
||||
|
||||
use App\Concerns\Filament\ActionLogs\HasPivotActionLogs;
|
||||
use App\Filament\Components\Fields\Select;
|
||||
use App\Filament\RelationManagers\BaseRelationManager;
|
||||
use App\Models\Admin\ActionLog;
|
||||
use App\Models\Wiki\Image;
|
||||
use Filament\Actions\AttachAction as BaseAttachAction;
|
||||
use Filament\Facades\Filament;
|
||||
@@ -20,8 +18,6 @@ use Illuminate\Support\Str;
|
||||
|
||||
class AttachAction extends BaseAttachAction
|
||||
{
|
||||
use HasPivotActionLogs;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
@@ -56,13 +52,7 @@ class AttachAction extends BaseAttachAction
|
||||
if ($this->shouldShowCreateOption($model)) {
|
||||
return $select
|
||||
->createOptionForm(fn (Schema $schema) => Filament::getModelResource($model)::form($schema)->getComponents())
|
||||
->createOptionUsing(function (array $data) use ($model) {
|
||||
$created = $model::query()->create($data);
|
||||
|
||||
ActionLog::modelCreated($created);
|
||||
|
||||
return $created->getKey();
|
||||
});
|
||||
->createOptionUsing(fn (array $data) => $model::query()->create($data)->getKey());
|
||||
}
|
||||
|
||||
return $select;
|
||||
@@ -72,8 +62,6 @@ class AttachAction extends BaseAttachAction
|
||||
$action->getRecordSelect(),
|
||||
...$livewire->getPivotComponents(),
|
||||
]);
|
||||
|
||||
$this->after(fn (BaseRelationManager $livewire, Model $record, AttachAction $action) => $this->pivotActionLog('Attach', $livewire, $record, $action));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,23 +4,18 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Actions\Base;
|
||||
|
||||
use App\Concerns\Filament\ActionLogs\HasPivotActionLogs;
|
||||
use App\Filament\RelationManagers\BaseRelationManager;
|
||||
use App\Filament\Resources\Base\BaseListResources;
|
||||
use App\Filament\Resources\Base\BaseManageResources;
|
||||
use App\Models\Admin\ActionLog;
|
||||
use Filament\Actions\CreateAction as BaseCreateAction;
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Schemas\Schema;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class CreateAction extends BaseCreateAction
|
||||
{
|
||||
use HasPivotActionLogs;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
@@ -38,20 +33,6 @@ class CreateAction extends BaseCreateAction
|
||||
return null;
|
||||
});
|
||||
|
||||
$this->after(function (BaseManageResources|BaseListResources|BaseRelationManager $livewire, Model $record, CreateAction $action): void {
|
||||
if ($livewire instanceof BaseListResources) {
|
||||
ActionLog::modelCreated($record);
|
||||
}
|
||||
|
||||
if ($livewire instanceof BaseRelationManager) {
|
||||
$relationship = $livewire->getRelationship();
|
||||
|
||||
if ($relationship instanceof HasMany) {
|
||||
$this->associateActionLog('Create and Associate', $livewire, $record, $action);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$this->visible(function (BaseManageResources|BaseListResources|BaseRelationManager $livewire, string $model): bool {
|
||||
if ($livewire instanceof BaseRelationManager && $livewire->getRelationship() instanceof BelongsToMany) {
|
||||
return false;
|
||||
|
||||
@@ -5,7 +5,6 @@ declare(strict_types=1);
|
||||
namespace App\Filament\Actions\Base;
|
||||
|
||||
use App\Actions\Http\Api\List\Playlist\Track\DestroyTrackAction;
|
||||
use App\Models\Admin\ActionLog;
|
||||
use App\Models\List\Playlist\PlaylistTrack;
|
||||
use Filament\Actions\DeleteAction as BaseDeleteAction;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
@@ -36,8 +35,6 @@ class DeleteAction extends BaseDeleteAction
|
||||
return (bool) $result;
|
||||
});
|
||||
|
||||
$this->after(fn (Model $record): ActionLog => ActionLog::modelDeleted($record));
|
||||
|
||||
$this->authorize(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Actions\Base;
|
||||
|
||||
use App\Concerns\Filament\ActionLogs\HasPivotActionLogs;
|
||||
use App\Filament\RelationManagers\BaseRelationManager;
|
||||
use App\Filament\Resources\Base\BaseListResources;
|
||||
use App\Filament\Resources\Base\BaseManageResources;
|
||||
use App\Filament\Resources\Base\BaseViewResource;
|
||||
use Filament\Actions\DetachAction as BaseDetachAction;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
@@ -18,8 +16,6 @@ use Illuminate\Support\Str;
|
||||
|
||||
class DetachAction extends BaseDetachAction
|
||||
{
|
||||
use HasPivotActionLogs;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
@@ -54,13 +50,5 @@ class DetachAction extends BaseDetachAction
|
||||
});
|
||||
|
||||
$this->authorize(true);
|
||||
|
||||
$this->after(function (BaseRelationManager $livewire, Model $record): void {
|
||||
$relationship = $livewire->getRelationship();
|
||||
|
||||
if ($relationship instanceof BelongsToMany) {
|
||||
$this->pivotActionLog('Detach', $livewire, $record);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,26 +4,19 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Actions\Base;
|
||||
|
||||
use App\Concerns\Filament\ActionLogs\HasActionLogs;
|
||||
use App\Concerns\Filament\ActionLogs\HasPivotActionLogs;
|
||||
use App\Filament\RelationManagers\BaseRelationManager;
|
||||
use App\Filament\Resources\Base\BaseListResources;
|
||||
use App\Filament\Resources\Base\BaseManageResources;
|
||||
use App\Filament\Resources\Base\BaseViewResource;
|
||||
use App\Models\Admin\ActionLog;
|
||||
use Filament\Actions\EditAction as BaseEditAction;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Enums\IconSize;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class EditAction extends BaseEditAction
|
||||
{
|
||||
use HasActionLogs;
|
||||
use HasPivotActionLogs;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
@@ -38,16 +31,6 @@ class EditAction extends BaseEditAction
|
||||
...($livewire instanceof BaseRelationManager ? $livewire->getPivotComponents() : []),
|
||||
]);
|
||||
|
||||
$this->after(function (BaseListResources|BaseViewResource|BaseManageResources|BaseRelationManager $livewire, Model $record, EditAction $action): void {
|
||||
if ($livewire instanceof BaseListResources || $livewire instanceof BaseViewResource) {
|
||||
ActionLog::modelUpdated($record);
|
||||
}
|
||||
|
||||
if ($livewire instanceof BaseRelationManager && $livewire->getRelationship() instanceof BelongsToMany) {
|
||||
$this->pivotActionLog('Update Attached', $livewire, $record, $action);
|
||||
}
|
||||
});
|
||||
|
||||
$this->beforeFormFilled(function (Model $record): void {
|
||||
Gate::authorize('update', $record);
|
||||
});
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace App\Filament\Actions\Base;
|
||||
use App\Filament\RelationManagers\BaseRelationManager;
|
||||
use App\Filament\Resources\Base\BaseListResources;
|
||||
use App\Filament\Resources\Base\BaseManageResources;
|
||||
use App\Models\Admin\ActionLog;
|
||||
use Filament\Actions\ReplicateAction as BaseReplicateAction;
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Schemas\Schema;
|
||||
@@ -22,7 +21,5 @@ class ReplicateAction extends BaseReplicateAction
|
||||
$this->schema(fn (Schema $schema, BaseListResources|BaseManageResources|BaseRelationManager $livewire): array => $livewire->form($schema)->getComponents());
|
||||
|
||||
$this->successRedirectUrl(fn (Model $replica) => Filament::getModelResource($replica)::getUrl('view', ['record' => $replica]));
|
||||
|
||||
$this->after(fn (Model $replica): ActionLog => ActionLog::modelCreated($replica));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ declare(strict_types=1);
|
||||
namespace App\Filament\Actions\Base;
|
||||
|
||||
use App\Contracts\Models\SoftDeletable;
|
||||
use App\Models\Admin\ActionLog;
|
||||
use Filament\Actions\RestoreAction as BaseRestoreAction;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@@ -33,8 +32,6 @@ class RestoreAction extends BaseRestoreAction
|
||||
return $record->trashed();
|
||||
});
|
||||
|
||||
$this->after(fn (Model $record): ActionLog => ActionLog::modelRestored($record));
|
||||
|
||||
$this->using(function (Model&SoftDeletable $record): bool {
|
||||
Gate::authorize('restore', $record);
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Actions;
|
||||
|
||||
use App\Concerns\Filament\ActionLogs\HasActionLogs;
|
||||
use App\Concerns\Filament\HasActivityLogs;
|
||||
use App\Enums\Models\Admin\ActivityStatus;
|
||||
use App\Filament\RelationManagers\BaseRelationManager;
|
||||
use App\Filament\Resources\Base\BaseViewResource;
|
||||
use Filament\Actions\Action;
|
||||
@@ -15,7 +16,7 @@ use Illuminate\Support\Str;
|
||||
|
||||
abstract class BaseAction extends Action
|
||||
{
|
||||
use HasActionLogs;
|
||||
use HasActivityLogs;
|
||||
|
||||
public static function getDefaultName(): ?string
|
||||
{
|
||||
@@ -32,10 +33,10 @@ abstract class BaseAction extends Action
|
||||
|
||||
$this->before(function (BaseAction $action, mixed $livewire): void {
|
||||
if ($livewire instanceof BaseRelationManager) {
|
||||
$this->createActionLog($action, $livewire->getOwnerRecord());
|
||||
$this->createActivityLog($action, $livewire->getOwnerRecord());
|
||||
$livewire->dispatch('updateAllRelationManager');
|
||||
} elseif (($record = $this->getRecord()) instanceof Model) {
|
||||
$this->createActionLog($action, $record);
|
||||
$this->createActivityLog($action, $record);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -44,6 +45,11 @@ abstract class BaseAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
$this->activity?->update([
|
||||
'status' => ActivityStatus::FINISHED,
|
||||
'finished_at' => now(),
|
||||
]);
|
||||
|
||||
$this->finishedLog();
|
||||
|
||||
if ($livewire instanceof BaseViewResource || $livewire instanceof BaseRelationManager) {
|
||||
|
||||
@@ -6,9 +6,7 @@ namespace App\Filament\Actions\Storage;
|
||||
|
||||
use App\Contracts\Actions\Storage\StorageAction as BaseStorageAction;
|
||||
use App\Filament\Actions\BaseAction;
|
||||
use App\Filament\RelationManagers\BaseRelationManager;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
abstract class StorageAction extends BaseAction
|
||||
{
|
||||
@@ -57,22 +55,5 @@ abstract class StorageAction extends BaseAction
|
||||
}
|
||||
|
||||
$this->afterStorageAction($record, $data);
|
||||
|
||||
$livewire = $this->getLivewire();
|
||||
if ($livewire instanceof BaseRelationManager && $record instanceof Model) {
|
||||
$relation = $livewire->getRelationship();
|
||||
$pivot = $record;
|
||||
|
||||
if ($relation instanceof BelongsToMany) {
|
||||
$pivotClass = $relation->getPivotClass();
|
||||
|
||||
$pivot = $pivotClass::query()
|
||||
->where($livewire->getOwnerRecord()->getKeyName(), $livewire->getOwnerRecord()->getKey())
|
||||
->where($record->getKeyName(), $record->getKey())
|
||||
->first();
|
||||
}
|
||||
|
||||
$this->updateLog($record, $pivot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,15 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\BulkActions\Base;
|
||||
|
||||
use App\Concerns\Filament\ActionLogs\HasActionLogs;
|
||||
use Filament\Actions\DeleteBulkAction as BaseDeleteBulkAction;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class DeleteBulkAction extends BaseDeleteBulkAction
|
||||
{
|
||||
use HasActionLogs;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
@@ -22,12 +18,5 @@ class DeleteBulkAction extends BaseDeleteBulkAction
|
||||
$this->authorize(true);
|
||||
|
||||
$this->before(fn (string $model) => Gate::authorize('forceDeleteAny', $model));
|
||||
|
||||
$this->after(function (DeleteBulkAction $action, Collection $records): void {
|
||||
foreach ($records as $record) {
|
||||
$this->createActionLog($action, $record);
|
||||
$this->finishedLog();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,15 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\BulkActions\Base;
|
||||
|
||||
use App\Concerns\Filament\ActionLogs\HasActionLogs;
|
||||
use Filament\Actions\DetachBulkAction as BaseDetachBulkAction;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class DetachBulkAction extends BaseDetachBulkAction
|
||||
{
|
||||
use HasActionLogs;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
@@ -22,12 +18,5 @@ class DetachBulkAction extends BaseDetachBulkAction
|
||||
$this->authorize(true);
|
||||
|
||||
$this->before(fn (string $model) => Gate::authorize('forceDeleteAny', $model));
|
||||
|
||||
$this->after(function (DetachBulkAction $action, Collection $records): void {
|
||||
foreach ($records as $record) {
|
||||
$this->createActionLog($action, $record);
|
||||
$this->finishedLog();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\BulkActions\Base;
|
||||
|
||||
use App\Concerns\Filament\ActionLogs\HasActionLogs;
|
||||
use Filament\Actions\ForceDeleteBulkAction as BaseForceDeleteBulkAction;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class ForceDeleteBulkAction extends BaseForceDeleteBulkAction
|
||||
{
|
||||
use HasActionLogs;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
@@ -4,15 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\BulkActions\Base;
|
||||
|
||||
use App\Concerns\Filament\ActionLogs\HasActionLogs;
|
||||
use Filament\Actions\RestoreBulkAction as BaseRestoreBulkAction;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class RestoreBulkAction extends BaseRestoreBulkAction
|
||||
{
|
||||
use HasActionLogs;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
@@ -22,12 +18,5 @@ class RestoreBulkAction extends BaseRestoreBulkAction
|
||||
$this->authorize(true);
|
||||
|
||||
$this->before(fn (string $model) => Gate::authorize('restoreAny', $model));
|
||||
|
||||
$this->after(function (RestoreBulkAction $action, Collection $records): void {
|
||||
foreach ($records as $record) {
|
||||
$this->createActionLog($action, $record);
|
||||
$this->finishedLog();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\BulkActions;
|
||||
|
||||
use App\Concerns\Filament\ActionLogs\HasActionLogs;
|
||||
use Filament\Actions\BulkAction;
|
||||
use Filament\Support\Enums\Width;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -14,22 +13,12 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
abstract class BaseBulkAction extends BulkAction
|
||||
{
|
||||
use HasActionLogs;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->requiresConfirmation();
|
||||
|
||||
$this->before(function (BaseBulkAction $action, Collection $records): void {
|
||||
foreach ($records as $record) {
|
||||
$this->createActionLog($action, $record, false);
|
||||
}
|
||||
});
|
||||
|
||||
$this->after(fn () => $this->batchFinishedLog());
|
||||
|
||||
$this->modalWidth(Width::FourExtraLarge);
|
||||
|
||||
$this->action(fn (Collection $records, array $data) => $this->handle($records, $data));
|
||||
|
||||
@@ -44,11 +44,7 @@ class VideoDiscordNotificationBulkAction extends BaseBulkAction
|
||||
|
||||
$action = new DiscordVideoNotificationActionAction();
|
||||
|
||||
$result = $action->handle($videos, $data);
|
||||
|
||||
if ($result->hasFailed()) {
|
||||
$this->failedLog($result->getMessage());
|
||||
}
|
||||
$action->handle($videos, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,10 +34,6 @@ abstract class StorageBulkAction extends BaseBulkAction
|
||||
$action->then($storageResults);
|
||||
|
||||
$actionResult = $storageResults->toActionResult();
|
||||
|
||||
if ($actionResult->hasFailed()) {
|
||||
$this->failedLog($actionResult->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-6
@@ -5,23 +5,28 @@ declare(strict_types=1);
|
||||
namespace App\Filament\RelationManagers\Base;
|
||||
|
||||
use App\Filament\RelationManagers\BaseRelationManager;
|
||||
use App\Filament\Resources\Admin\ActionLogResource;
|
||||
use App\Filament\Resources\Admin\ActivityResource;
|
||||
use App\Filament\Resources\BaseResource;
|
||||
use App\Models\Admin\ActionLog;
|
||||
use App\Models\Admin\Activity;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class ActionLogRelationManager extends BaseRelationManager
|
||||
class ActivityRelationManager extends BaseRelationManager
|
||||
{
|
||||
protected static string $relationship = 'actionlogs';
|
||||
protected static string $relationship = 'activities';
|
||||
|
||||
protected static ?string $recordTitleAttribute = ActionLog::ATTRIBUTE_ID;
|
||||
protected static ?string $recordTitleAttribute = Activity::ATTRIBUTE_ID;
|
||||
|
||||
/**
|
||||
* The resource of the relation manager.
|
||||
*
|
||||
* @var class-string<BaseResource>|null
|
||||
*/
|
||||
protected static ?string $relatedResource = ActionLogResource::class;
|
||||
protected static ?string $relatedResource = ActivityResource::class;
|
||||
|
||||
public static function isLazy(): true
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Admin\ActionLog\Pages;
|
||||
|
||||
use App\Filament\Resources\Admin\ActionLogResource;
|
||||
use App\Filament\Resources\Base\BaseManageResources;
|
||||
|
||||
class ManageActionLogs extends BaseManageResources
|
||||
{
|
||||
protected static string $resource = ActionLogResource::class;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Admin\Activity\Pages;
|
||||
|
||||
use App\Filament\Resources\Admin\ActivityResource;
|
||||
use App\Filament\Resources\Base\BaseManageResources;
|
||||
|
||||
class ManageActivities extends BaseManageResources
|
||||
{
|
||||
protected static string $resource = ActivityResource::class;
|
||||
}
|
||||
+47
-66
@@ -6,17 +6,16 @@ namespace App\Filament\Resources\Admin;
|
||||
|
||||
use App\Enums\Auth\Role;
|
||||
use App\Enums\Filament\NavigationGroup;
|
||||
use App\Enums\Models\Admin\ActionLogStatus;
|
||||
use App\Enums\Models\Admin\ActivityStatus;
|
||||
use App\Filament\Actions\Base\ViewAction;
|
||||
use App\Filament\Components\Columns\BelongsToColumn;
|
||||
use App\Filament\Components\Columns\TextColumn;
|
||||
use App\Filament\Components\Filters\DateFilter;
|
||||
use App\Filament\Components\Infolist\BelongsToEntry;
|
||||
use App\Filament\Components\Infolist\TextEntry;
|
||||
use App\Filament\Resources\Admin\ActionLog\Pages\ManageActionLogs;
|
||||
use App\Filament\Resources\Admin\Activity\Pages\ManageActivities;
|
||||
use App\Filament\Resources\Auth\UserResource;
|
||||
use App\Filament\Resources\BaseResource;
|
||||
use App\Models\Admin\ActionLog;
|
||||
use App\Models\Admin\Activity;
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\BaseModel;
|
||||
use Filament\Facades\Filament;
|
||||
@@ -29,27 +28,26 @@ use Filament\Support\Enums\TextSize;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ActionLogResource extends BaseResource
|
||||
class ActivityResource extends BaseResource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<Model>|null
|
||||
*/
|
||||
protected static ?string $model = ActionLog::class;
|
||||
protected static ?string $model = Activity::class;
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return __('filament.resources.singularLabel.action_log');
|
||||
return __('filament.resources.singularLabel.activity');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return __('filament.resources.label.action_logs');
|
||||
return __('filament.resources.label.activities');
|
||||
}
|
||||
|
||||
public static function getNavigationGroup(): NavigationGroup
|
||||
@@ -69,18 +67,7 @@ class ActionLogResource extends BaseResource
|
||||
|
||||
public static function getRecordTitleAttribute(): string
|
||||
{
|
||||
return ActionLog::ATTRIBUTE_NAME;
|
||||
}
|
||||
|
||||
public static function getEloquentQuery(): Builder
|
||||
{
|
||||
$query = parent::getEloquentQuery();
|
||||
|
||||
// Necessary to prevent lazy loading when loading related resources
|
||||
return $query->with([
|
||||
ActionLog::RELATION_USER,
|
||||
ActionLog::RELATION_TARGET,
|
||||
]);
|
||||
return Activity::ATTRIBUTE_NAME;
|
||||
}
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
@@ -88,10 +75,10 @@ class ActionLogResource extends BaseResource
|
||||
return $schema
|
||||
->components([
|
||||
// TODO: JSON values are not being displayed
|
||||
KeyValue::make(ActionLog::ATTRIBUTE_FIELDS)
|
||||
->label(__('filament.fields.action_log.fields.name'))
|
||||
->keyLabel(__('filament.fields.action_log.fields.keys'))
|
||||
->valueLabel(__('filament.fields.action_log.fields.values'))
|
||||
KeyValue::make(Activity::ATTRIBUTE_PROPERTIES)
|
||||
->label(__('filament.fields.activity.fields.name'))
|
||||
->keyLabel(__('filament.fields.activity.fields.keys'))
|
||||
->valueLabel(__('filament.fields.activity.fields.values'))
|
||||
->columnSpanFull()
|
||||
->hidden(fn ($state): bool => is_null($state))
|
||||
->formatStateUsing(fn (?array $state) => collect($state)->mapWithKeys(function ($value, $key): array {
|
||||
@@ -102,8 +89,8 @@ class ActionLogResource extends BaseResource
|
||||
return [$key => blank($value) ? '-' : $value];
|
||||
})->toArray()),
|
||||
|
||||
Textarea::make(ActionLog::ATTRIBUTE_EXCEPTION)
|
||||
->label(__('filament.fields.action_log.exception'))
|
||||
Textarea::make(Activity::ATTRIBUTE_EXCEPTION)
|
||||
->label(__('filament.fields.activity.exception'))
|
||||
->disabled()
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
@@ -114,30 +101,30 @@ class ActionLogResource extends BaseResource
|
||||
return parent::table($table)
|
||||
->recordUrl('')
|
||||
->columns([
|
||||
TextColumn::make(ActionLog::ATTRIBUTE_ID)
|
||||
TextColumn::make(Activity::ATTRIBUTE_ID)
|
||||
->label(__('filament.fields.base.id')),
|
||||
|
||||
TextColumn::make(ActionLog::ATTRIBUTE_NAME)
|
||||
->label(__('filament.fields.action_log.name'))
|
||||
TextColumn::make(Activity::ATTRIBUTE_NAME)
|
||||
->label(__('filament.fields.activity.name'))
|
||||
->searchable(),
|
||||
|
||||
BelongsToColumn::make(ActionLog::RELATION_USER, UserResource::class),
|
||||
BelongsToColumn::make(Activity::RELATION_USER, UserResource::class),
|
||||
|
||||
TextColumn::make(ActionLog::ATTRIBUTE_TARGET)
|
||||
->label(__('filament.fields.action_log.target'))
|
||||
TextColumn::make(Activity::RELATION_RELATED)
|
||||
->label(__('filament.fields.activity.target'))
|
||||
->formatStateUsing(fn ($state): string => Str::headline(class_basename($state)).': '.$state->getName()),
|
||||
|
||||
TextColumn::make(ActionLog::ATTRIBUTE_STATUS)
|
||||
->label(__('filament.fields.action_log.status'))
|
||||
->formatStateUsing(fn (ActionLogStatus $state): ?string => $state->localize())
|
||||
TextColumn::make(Activity::ATTRIBUTE_STATUS)
|
||||
->label(__('filament.fields.activity.status'))
|
||||
->formatStateUsing(fn (ActivityStatus $state): ?string => $state->localize())
|
||||
->badge(),
|
||||
|
||||
TextColumn::make(BaseModel::ATTRIBUTE_CREATED_AT)
|
||||
->label(__('filament.fields.action_log.happened_at'))
|
||||
->label(__('filament.fields.activity.happened_at'))
|
||||
->dateTime(),
|
||||
|
||||
TextColumn::make(ActionLog::ATTRIBUTE_FINISHED_AT)
|
||||
->label(__('filament.fields.action_log.finished_at'))
|
||||
TextColumn::make(Activity::ATTRIBUTE_FINISHED_AT)
|
||||
->label(__('filament.fields.activity.finished_at'))
|
||||
->dateTime(),
|
||||
]);
|
||||
}
|
||||
@@ -146,33 +133,33 @@ class ActionLogResource extends BaseResource
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextEntry::make(ActionLog::ATTRIBUTE_NAME)
|
||||
->label(__('filament.fields.action_log.name'))
|
||||
TextEntry::make(Activity::ATTRIBUTE_NAME)
|
||||
->label(__('filament.fields.activity.name'))
|
||||
->formatStateUsing(fn ($state): string => ucfirst((string) $state)),
|
||||
|
||||
BelongsToEntry::make(ActionLog::RELATION_USER, UserResource::class),
|
||||
BelongsToEntry::make(Activity::RELATION_USER, UserResource::class),
|
||||
|
||||
TextEntry::make(ActionLog::ATTRIBUTE_TARGET)
|
||||
->label(__('filament.fields.action_log.target'))
|
||||
TextEntry::make(Activity::RELATION_RELATED)
|
||||
->label(__('filament.fields.activity.target'))
|
||||
->formatStateUsing(fn ($state): string => class_basename($state).': '.$state->getName()),
|
||||
|
||||
TextEntry::make(ActionLog::ATTRIBUTE_STATUS)
|
||||
->label(__('filament.fields.action_log.status'))
|
||||
->formatStateUsing(fn (ActionLogStatus $state): ?string => $state->localize())
|
||||
TextEntry::make(Activity::ATTRIBUTE_STATUS)
|
||||
->label(__('filament.fields.activity.status'))
|
||||
->formatStateUsing(fn (ActivityStatus $state): ?string => $state->localize())
|
||||
->badge(),
|
||||
|
||||
TextEntry::make(BaseModel::ATTRIBUTE_CREATED_AT)
|
||||
->label(__('filament.fields.action_log.happened_at'))
|
||||
->label(__('filament.fields.activity.happened_at'))
|
||||
->dateTime(),
|
||||
|
||||
TextEntry::make(ActionLog::ATTRIBUTE_FINISHED_AT)
|
||||
->label(__('filament.fields.action_log.finished_at'))
|
||||
TextEntry::make(Activity::ATTRIBUTE_FINISHED_AT)
|
||||
->label(__('filament.fields.activity.finished_at'))
|
||||
->dateTime(),
|
||||
|
||||
KeyValueEntry::make(ActionLog::ATTRIBUTE_FIELDS)
|
||||
->label(__('filament.fields.action_log.fields.name'))
|
||||
->keyLabel(__('filament.fields.action_log.fields.keys'))
|
||||
->valueLabel(__('filament.fields.action_log.fields.values'))
|
||||
KeyValueEntry::make(Activity::ATTRIBUTE_PROPERTIES)
|
||||
->label(__('filament.fields.activity.fields.name'))
|
||||
->keyLabel(__('filament.fields.activity.fields.keys'))
|
||||
->valueLabel(__('filament.fields.activity.fields.values'))
|
||||
->columnSpanFull()
|
||||
->hidden(fn ($state): bool => is_null($state))
|
||||
->formatStateUsing(fn (?array $state) => collect($state)->mapWithKeys(function ($value, $key): array {
|
||||
@@ -183,8 +170,8 @@ class ActionLogResource extends BaseResource
|
||||
return [$key => blank($value) ? '-' : $value];
|
||||
})->toArray()),
|
||||
|
||||
TextEntry::make(ActionLog::ATTRIBUTE_EXCEPTION)
|
||||
->label(__('filament.fields.action_log.exception'))
|
||||
TextEntry::make(Activity::ATTRIBUTE_EXCEPTION)
|
||||
->label(__('filament.fields.activity.exception'))
|
||||
->columnSpanFull()
|
||||
->size(TextSize::Large),
|
||||
])
|
||||
@@ -197,15 +184,9 @@ class ActionLogResource extends BaseResource
|
||||
public static function getFilters(): array
|
||||
{
|
||||
return [
|
||||
SelectFilter::make(ActionLog::ATTRIBUTE_STATUS)
|
||||
->label(__('filament.fields.action_log.status'))
|
||||
->options(ActionLogStatus::class),
|
||||
|
||||
DateFilter::make(BaseModel::ATTRIBUTE_CREATED_AT)
|
||||
->label(__('filament.fields.action_log.happened_at')),
|
||||
|
||||
DateFilter::make(ActionLog::ATTRIBUTE_FINISHED_AT)
|
||||
->label(__('filament.fields.action_log.finished_at')),
|
||||
SelectFilter::make(Activity::ATTRIBUTE_STATUS)
|
||||
->label(__('filament.fields.activity.status'))
|
||||
->options(ActivityStatus::class),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -270,7 +251,7 @@ class ActionLogResource extends BaseResource
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ManageActionLogs::route('/'),
|
||||
'index' => ManageActivities::route('/'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ use App\Filament\Actions\Base\ViewAction;
|
||||
use App\Filament\BulkActions\Base\DeleteBulkAction;
|
||||
use App\Filament\BulkActions\Base\ForceDeleteBulkAction;
|
||||
use App\Filament\BulkActions\Base\RestoreBulkAction;
|
||||
use App\Filament\RelationManagers\Base\ActionLogRelationManager;
|
||||
use App\Filament\RelationManagers\Base\ActivityRelationManager;
|
||||
use App\Models\BaseModel;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\ActionGroup;
|
||||
@@ -169,7 +169,7 @@ abstract class BaseResource extends Resource
|
||||
public static function getBaseRelations(): array
|
||||
{
|
||||
return [
|
||||
ActionLogRelationManager::class,
|
||||
ActivityRelationManager::class,
|
||||
AuditsRelationManager::class,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,409 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Models\Admin;
|
||||
|
||||
use App\Constants\ModelConstants;
|
||||
use App\Contracts\Models\Nameable;
|
||||
use App\Discord\DiscordEmbedField;
|
||||
use App\Enums\Models\Admin\ActionLogStatus;
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\BaseModel;
|
||||
use App\Observers\Admin\ActionLogObserver;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
use Illuminate\Database\Eloquent\Attributes\Table;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Date;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Str;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $batch_id
|
||||
* @property string $name
|
||||
* @property string $actionable_type
|
||||
* @property int $actionable_id
|
||||
* @property string $target_type
|
||||
* @property int $target_id
|
||||
* @property string $model_type
|
||||
* @property int $model_id
|
||||
* @property string|null $exception
|
||||
* @property array|null $fields
|
||||
* @property Carbon|null $finished_at
|
||||
* @property ActionLogStatus $status
|
||||
* @property Model $target
|
||||
* @property int|null $user_id
|
||||
* @property User|null $user
|
||||
*/
|
||||
#[ObservedBy(ActionLogObserver::class)]
|
||||
#[Table(ActionLog::TABLE, ActionLog::ATTRIBUTE_ID)]
|
||||
class ActionLog extends Model implements Nameable
|
||||
{
|
||||
final public const string TABLE = 'action_logs';
|
||||
|
||||
final public const string ATTRIBUTE_ID = 'id';
|
||||
final public const string ATTRIBUTE_BATCH_ID = 'batch_id';
|
||||
final public const string ATTRIBUTE_NAME = 'name';
|
||||
final public const string ATTRIBUTE_USER = 'user_id';
|
||||
|
||||
final public const string ATTRIBUTE_ACTIONABLE = 'actionable';
|
||||
final public const string ATTRIBUTE_ACTIONABLE_TYPE = 'actionable_type';
|
||||
final public const string ATTRIBUTE_ACTIONABLE_ID = 'actionable_id';
|
||||
|
||||
final public const string ATTRIBUTE_TARGET = 'target';
|
||||
final public const string ATTRIBUTE_TARGET_TYPE = 'target_type';
|
||||
final public const string ATTRIBUTE_TARGET_ID = 'target_id';
|
||||
|
||||
final public const string ATTRIBUTE_MODEL_TYPE = 'model_type';
|
||||
final public const string ATTRIBUTE_MODEL_ID = 'model_id';
|
||||
|
||||
final public const string ATTRIBUTE_FIELDS = 'fields';
|
||||
final public const string ATTRIBUTE_STATUS = 'status';
|
||||
final public const string ATTRIBUTE_EXCEPTION = 'exception';
|
||||
final public const string ATTRIBUTE_FINISHED_AT = 'finished_at';
|
||||
|
||||
final public const string RELATION_USER = 'user';
|
||||
final public const string RELATION_TARGET = 'target';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
ActionLog::ATTRIBUTE_BATCH_ID,
|
||||
ActionLog::ATTRIBUTE_NAME,
|
||||
ActionLog::ATTRIBUTE_USER,
|
||||
ActionLog::ATTRIBUTE_ACTIONABLE_TYPE,
|
||||
ActionLog::ATTRIBUTE_ACTIONABLE_ID,
|
||||
ActionLog::ATTRIBUTE_TARGET_TYPE,
|
||||
ActionLog::ATTRIBUTE_TARGET_ID,
|
||||
ActionLog::ATTRIBUTE_MODEL_TYPE,
|
||||
ActionLog::ATTRIBUTE_MODEL_ID,
|
||||
ActionLog::ATTRIBUTE_FIELDS,
|
||||
ActionLog::ATTRIBUTE_STATUS,
|
||||
ActionLog::ATTRIBUTE_EXCEPTION,
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
ActionLog::ATTRIBUTE_FIELDS => 'array',
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::class,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* When an exception is thrown, the current action logs should be handled.
|
||||
*/
|
||||
public static function updateCurrentActionLogToFailed(Throwable $e): void
|
||||
{
|
||||
if ($actionLog = Session::get('currentActionLog')) {
|
||||
ActionLog::query()
|
||||
->where(ActionLog::ATTRIBUTE_BATCH_ID, $actionLog)
|
||||
->where(ActionLog::ATTRIBUTE_STATUS, ActionLogStatus::RUNNING->value)
|
||||
->update([
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::FAILED->value,
|
||||
ActionLog::ATTRIBUTE_EXCEPTION => $e->__toString(),
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT => Date::now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return Str::of($this->name)
|
||||
->append(' - ')
|
||||
->append($this->target()->getName())
|
||||
->__toString();
|
||||
}
|
||||
|
||||
public function actionable(): MorphTo
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the target of the action for user interface linking.
|
||||
*/
|
||||
public function target(): MorphTo|BaseModel
|
||||
{
|
||||
return $this->morphTo()
|
||||
->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<User, $this>
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, ActionLog::ATTRIBUTE_USER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user id for the action log.
|
||||
*/
|
||||
public static function getUserId(): int
|
||||
{
|
||||
return Filament::auth()->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an action log for a model created.
|
||||
*/
|
||||
public static function modelCreated(Model $model): ActionLog
|
||||
{
|
||||
return ActionLog::query()->create([
|
||||
ActionLog::ATTRIBUTE_BATCH_ID => Str::orderedUuid()->__toString(),
|
||||
ActionLog::ATTRIBUTE_USER => ActionLog::getUserId(),
|
||||
ActionLog::ATTRIBUTE_NAME => 'Create',
|
||||
ActionLog::ATTRIBUTE_ACTIONABLE_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_ACTIONABLE_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_TARGET_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_TARGET_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_MODEL_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_MODEL_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_FIELDS => static::getFields($model->getAttributes(), $model),
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::FINISHED->value,
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT => Date::now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an action log for a model updated.
|
||||
*/
|
||||
public static function modelUpdated(Model $model): ActionLog
|
||||
{
|
||||
return ActionLog::query()->create([
|
||||
ActionLog::ATTRIBUTE_BATCH_ID => Str::orderedUuid()->__toString(),
|
||||
ActionLog::ATTRIBUTE_USER => ActionLog::getUserId(),
|
||||
ActionLog::ATTRIBUTE_NAME => 'Update',
|
||||
ActionLog::ATTRIBUTE_ACTIONABLE_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_ACTIONABLE_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_TARGET_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_TARGET_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_MODEL_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_MODEL_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_FIELDS => static::getFields($model->getChanges(), $model),
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::FINISHED->value,
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT => Date::now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an action log for a model deleted.
|
||||
*/
|
||||
public static function modelDeleted(Model $model): ActionLog
|
||||
{
|
||||
return ActionLog::modelSoftDeleted('Delete', $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an action log for a model restored.
|
||||
*/
|
||||
public static function modelRestored(Model $model): ActionLog
|
||||
{
|
||||
return ActionLog::modelSoftDeleted('Restore', $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an action log for a model that is soft-deleted.
|
||||
*/
|
||||
public static function modelSoftDeleted(string $actionName, Model $model): ActionLog
|
||||
{
|
||||
return ActionLog::query()->create([
|
||||
ActionLog::ATTRIBUTE_BATCH_ID => Str::orderedUuid()->__toString(),
|
||||
ActionLog::ATTRIBUTE_USER => ActionLog::getUserId(),
|
||||
ActionLog::ATTRIBUTE_NAME => $actionName,
|
||||
ActionLog::ATTRIBUTE_ACTIONABLE_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_ACTIONABLE_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_TARGET_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_TARGET_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_MODEL_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_MODEL_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_FIELDS => static::getFields($model->getAttributes(), $model),
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::FINISHED->value,
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT => Date::now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an action log for a model attached.
|
||||
*/
|
||||
public static function modelPivot(string $actionName, Model $related, Model $parent, Model $pivot, ?Action $action = null): ActionLog
|
||||
{
|
||||
$data = $action?->getData();
|
||||
|
||||
return ActionLog::query()->create([
|
||||
ActionLog::ATTRIBUTE_BATCH_ID => Str::orderedUuid()->__toString(),
|
||||
ActionLog::ATTRIBUTE_USER => ActionLog::getUserId(),
|
||||
ActionLog::ATTRIBUTE_NAME => $actionName,
|
||||
ActionLog::ATTRIBUTE_ACTIONABLE_TYPE => $related->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_ACTIONABLE_ID => $related->getKey(),
|
||||
ActionLog::ATTRIBUTE_TARGET_TYPE => $parent->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_TARGET_ID => $parent->getKey(),
|
||||
ActionLog::ATTRIBUTE_MODEL_TYPE => $pivot->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_MODEL_ID => $pivot instanceof Pivot ? null : $pivot->getKey(),
|
||||
ActionLog::ATTRIBUTE_FIELDS => $data ? static::getFields($data) : static::getFields($pivot->getAttributes(), $pivot),
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::FINISHED->value,
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT => Date::now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an action log for a model associated (HasMany).
|
||||
*/
|
||||
public static function modelAssociated(string $actionName, Model $related, Model $parent, Action $action): ActionLog
|
||||
{
|
||||
return ActionLog::query()->create([
|
||||
ActionLog::ATTRIBUTE_BATCH_ID => Str::orderedUuid()->__toString(),
|
||||
ActionLog::ATTRIBUTE_USER => ActionLog::getUserId(),
|
||||
ActionLog::ATTRIBUTE_NAME => $actionName,
|
||||
ActionLog::ATTRIBUTE_ACTIONABLE_TYPE => $related->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_ACTIONABLE_ID => $related->getKey(),
|
||||
ActionLog::ATTRIBUTE_TARGET_TYPE => $parent->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_TARGET_ID => $parent->getKey(),
|
||||
ActionLog::ATTRIBUTE_MODEL_TYPE => $related->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_MODEL_ID => $related->getKey(),
|
||||
ActionLog::ATTRIBUTE_FIELDS => static::getFields($action->getData()),
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::FINISHED->value,
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT => Date::now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an action log for when a model has an action executed.
|
||||
*/
|
||||
public static function modelActioned(string $batchId, Action $action, Model $model): ActionLog
|
||||
{
|
||||
return ActionLog::query()->create([
|
||||
ActionLog::ATTRIBUTE_BATCH_ID => $batchId,
|
||||
ActionLog::ATTRIBUTE_USER => ActionLog::getUserId(),
|
||||
ActionLog::ATTRIBUTE_NAME => $action->getLabel(),
|
||||
ActionLog::ATTRIBUTE_ACTIONABLE_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_ACTIONABLE_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_TARGET_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_TARGET_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_MODEL_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_MODEL_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_FIELDS => static::getFields($action->getData()),
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::RUNNING->value,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the all the models status of a batch to running.
|
||||
*/
|
||||
public function batchRunning(): void
|
||||
{
|
||||
$this->query()->where(ActionLog::ATTRIBUTE_BATCH_ID, $this->batch_id)
|
||||
->whereNotIn(ActionLog::ATTRIBUTE_STATUS, [ActionLogStatus::FINISHED->value, ActionLogStatus::FAILED->value])
|
||||
->update([
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::RUNNING->value,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the all the models status of a batch to finished.
|
||||
*/
|
||||
public function batchFinished(): void
|
||||
{
|
||||
$this->query()->where(ActionLog::ATTRIBUTE_BATCH_ID, $this->batch_id)
|
||||
->whereNotIn(ActionLog::ATTRIBUTE_STATUS, [ActionLogStatus::FINISHED->value, ActionLogStatus::FAILED->value])
|
||||
->update([
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::FINISHED->value,
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT => Date::now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the all the models status of a batch to failed.
|
||||
*/
|
||||
public function batchFailed(Throwable|string|null $exception = null): void
|
||||
{
|
||||
$this->query()->where(ActionLog::ATTRIBUTE_BATCH_ID, $this->batch_id)
|
||||
->whereNotIn(ActionLog::ATTRIBUTE_STATUS, [ActionLogStatus::FINISHED->value, ActionLogStatus::FAILED->value])
|
||||
->update([
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::FAILED->value,
|
||||
ActionLog::ATTRIBUTE_EXCEPTION => $exception ? $exception->__toString() : null,
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT => Date::now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the model status to finished.
|
||||
*/
|
||||
public function finished(): void
|
||||
{
|
||||
$this->updateStatus(ActionLogStatus::FINISHED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the model status to failed.
|
||||
*/
|
||||
public function failed(Throwable|string|null $exception = null): void
|
||||
{
|
||||
$this->updateStatus(ActionLogStatus::FAILED, $exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the model status is failed.
|
||||
*/
|
||||
public function hasFailed(): bool
|
||||
{
|
||||
return $this->status === ActionLogStatus::FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the status of a given action event.
|
||||
*/
|
||||
public function updateStatus(ActionLogStatus $status, Throwable|string|null $exception = null): void
|
||||
{
|
||||
if ($exception instanceof Throwable) {
|
||||
$exception = $exception->__toString();
|
||||
}
|
||||
|
||||
$this->update([
|
||||
ActionLog::ATTRIBUTE_STATUS => $status->value,
|
||||
ActionLog::ATTRIBUTE_EXCEPTION => $exception,
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT => Date::now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the fields to store.
|
||||
*/
|
||||
protected static function getFields(array $fields, ?Model $model = null): array
|
||||
{
|
||||
return collect($fields)
|
||||
->forget(Model::CREATED_AT)
|
||||
->forget(Model::UPDATED_AT)
|
||||
->forget(ModelConstants::ATTRIBUTE_DELETED_AT)
|
||||
->map(function ($value, $key) use ($model): string {
|
||||
if ($model instanceof Model) {
|
||||
if (in_array($key, $model->getHidden())) {
|
||||
return DiscordEmbedField::DEFAULT_FIELD_VALUE;
|
||||
}
|
||||
|
||||
return DiscordEmbedField::formatEmbedFieldValue($model->getAttribute($key));
|
||||
}
|
||||
|
||||
return DiscordEmbedField::formatEmbedFieldValue($value);
|
||||
})
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Models\Admin;
|
||||
|
||||
use App\Enums\Models\Admin\ActivityStatus;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Spatie\Activitylog\Models\Activity as BaseActivity;
|
||||
|
||||
/**
|
||||
* @property ActivityStatus|null $status
|
||||
*/
|
||||
class Activity extends BaseActivity
|
||||
{
|
||||
final public const string TABLE = 'activity_log';
|
||||
|
||||
final public const string ATTRIBUTE_ID = 'id';
|
||||
final public const string ATTRIBUTE_EXCEPTION = 'exception';
|
||||
final public const string ATTRIBUTE_FINISHED_AT = 'finished_at';
|
||||
final public const string ATTRIBUTE_NAME = 'event';
|
||||
final public const string ATTRIBUTE_PROPERTIES = 'properties';
|
||||
final public const string ATTRIBUTE_RELATED_ID = 'related_id';
|
||||
final public const string ATTRIBUTE_STATUS = 'status';
|
||||
|
||||
final public const string RELATION_RELATED = 'related';
|
||||
final public const string RELATION_USER = 'causer';
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
...parent::casts(),
|
||||
Activity::ATTRIBUTE_FINISHED_AT => 'datetime',
|
||||
Activity::ATTRIBUTE_STATUS => ActivityStatus::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function related(): MorphTo
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ use App\Events\Auth\User\UserCreated;
|
||||
use App\Events\Auth\User\UserDeleted;
|
||||
use App\Events\Auth\User\UserRestored;
|
||||
use App\Events\Auth\User\UserUpdated;
|
||||
use App\Models\Admin\ActionLog;
|
||||
use App\Models\Admin\Activity;
|
||||
use App\Models\List\ExternalProfile;
|
||||
use App\Models\List\Playlist;
|
||||
use App\Models\User\Like;
|
||||
@@ -229,13 +229,13 @@ class User extends Authenticatable implements Auditable, FilamentUser, HasAvatar
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the action logs that the user has executed.
|
||||
* Get the activities that the user has executed.
|
||||
*
|
||||
* @return HasMany<ActionLog, $this>
|
||||
* @return MorphMany<Activity, $this>
|
||||
*/
|
||||
public function actionlogs(): HasMany
|
||||
public function activities(): MorphMany
|
||||
{
|
||||
return $this->hasMany(ActionLog::class, ActionLog::ATTRIBUTE_USER);
|
||||
return $this->morphMany(Activity::class, 'causer');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,10 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Concerns\Filament\ActionLogs\ModelHasActionLogs;
|
||||
use App\Contracts\Models\HasSubtitle;
|
||||
use App\Contracts\Models\Nameable;
|
||||
use App\Models\Admin\Activity;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Str;
|
||||
@@ -18,8 +19,6 @@ use Illuminate\Support\Str;
|
||||
*/
|
||||
abstract class BaseModel extends Model implements HasSubtitle, Nameable
|
||||
{
|
||||
use ModelHasActionLogs;
|
||||
|
||||
/**
|
||||
* The storage format of the model's date columns.
|
||||
*
|
||||
@@ -42,4 +41,10 @@ abstract class BaseModel extends Model implements HasSubtitle, Nameable
|
||||
$this->setConnection(Config::get($connectionKey));
|
||||
}
|
||||
}
|
||||
|
||||
/** @return MorphMany<Activity, $this> */
|
||||
public function activities(): MorphMany
|
||||
{
|
||||
return $this->morphMany(Activity::class, 'subject');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Observers\Admin;
|
||||
|
||||
use App\Enums\Models\Admin\ActionLogStatus;
|
||||
use App\Models\Admin\ActionLog;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
|
||||
class ActionLogObserver
|
||||
{
|
||||
/**
|
||||
* Handle the ActionLog "creating" event.
|
||||
*/
|
||||
public function creating(ActionLog $actionLog): void
|
||||
{
|
||||
if ($actionLog->status === ActionLogStatus::RUNNING) {
|
||||
Session::put('currentActionLog', $actionLog->batch_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the ActionLog "updating" event.
|
||||
*/
|
||||
public function updating(ActionLog $actionLog): void
|
||||
{
|
||||
if ($actionLog->status === ActionLogStatus::RUNNING) {
|
||||
Session::put('currentActionLog', $actionLog->batch_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,7 @@
|
||||
"propaganistas/laravel-disposable-email": "^2.4.27",
|
||||
"spatie/db-dumper": "^3.8.3",
|
||||
"spatie/eloquent-sortable": "^5.0.1",
|
||||
"spatie/laravel-activitylog": "^5.0",
|
||||
"spatie/laravel-permission": "^6.25.0",
|
||||
"staudenmeir/belongs-to-through": "^2.18",
|
||||
"staudenmeir/eloquent-has-many-deep": "^1.22.1",
|
||||
|
||||
Generated
+94
-1
@@ -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": "6755161c85626cab15eacc8869e6836d",
|
||||
"content-hash": "069560ab509c56cc16fc63007f65e7af",
|
||||
"packages": [
|
||||
{
|
||||
"name": "awcodes/recently",
|
||||
@@ -8925,6 +8925,99 @@
|
||||
],
|
||||
"time": "2024-05-17T09:06:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-activitylog",
|
||||
"version": "5.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-activitylog.git",
|
||||
"reference": "0e00fe74fd071cc572a045459f6d4c9de33130bd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-activitylog/zipball/0e00fe74fd071cc572a045459f6d4c9de33130bd",
|
||||
"reference": "0e00fe74fd071cc572a045459f6d4c9de33130bd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/config": "^12.0 || ^13.0",
|
||||
"illuminate/database": "^12.0 || ^13.0",
|
||||
"illuminate/support": "^12.0 || ^13.0",
|
||||
"php": "^8.4",
|
||||
"spatie/laravel-package-tools": "^1.6.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-json": "*",
|
||||
"larastan/larastan": "^3.0",
|
||||
"laravel/pint": "^1.29",
|
||||
"orchestra/testbench": "^10.0 || ^11.0",
|
||||
"pestphp/pest": "^4.0"
|
||||
},
|
||||
"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/5.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://spatie.be/open-source/support-us",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-03-25T10:04:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-package-tools",
|
||||
"version": "1.93.0",
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\Admin\Activity;
|
||||
use Spatie\Activitylog\Actions\CleanActivityLogAction;
|
||||
use Spatie\Activitylog\Actions\LogActivityAction;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
* If set to false, no activities will be saved to the database.
|
||||
*/
|
||||
'enabled' => env('ACTIVITYLOG_ENABLED', true),
|
||||
|
||||
/*
|
||||
* When the clean command is executed, all recording activities older than
|
||||
* the number of days specified here will be deleted.
|
||||
*/
|
||||
'clean_after_days' => 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 relationship on activities
|
||||
* will include soft deleted models.
|
||||
*/
|
||||
'include_soft_deleted_subjects' => 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' => Activity::class,
|
||||
|
||||
/*
|
||||
* These attributes will be excluded from logging for all models.
|
||||
* Model-specific exclusions via logExcept() are merged with these.
|
||||
*/
|
||||
'default_except_attributes' => [],
|
||||
|
||||
/*
|
||||
* When enabled, activities are buffered in memory and inserted in a
|
||||
* single bulk query after the response has been sent to the client.
|
||||
* This can significantly reduce the number of database queries when
|
||||
* many activities are logged during a single request.
|
||||
*
|
||||
* Only enable this if your application logs a high volume of activities
|
||||
* per request. Buffered activities will not have an ID until the
|
||||
* buffer is flushed.
|
||||
*/
|
||||
'buffer' => [
|
||||
'enabled' => env('ACTIVITYLOG_BUFFER_ENABLED', false),
|
||||
],
|
||||
|
||||
/*
|
||||
* These action classes can be overridden to customize how activities
|
||||
* are logged and cleaned. Your custom classes must extend the originals.
|
||||
*/
|
||||
'actions' => [
|
||||
'log_activity' => LogActivityAction::class,
|
||||
'clean_log' => CleanActivityLogAction::class,
|
||||
],
|
||||
];
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('action_logs')) {
|
||||
Schema::create('action_logs', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('batch_id');
|
||||
|
||||
$table->unsignedBigInteger('user_id')->nullable();
|
||||
$table->foreign('user_id')->references('id')->on('users')->nullOnDelete();
|
||||
|
||||
$table->string('name');
|
||||
$table->morphs('actionable');
|
||||
$table->morphs('target');
|
||||
$table->string('model_type');
|
||||
$table->uuid('model_id')->nullable();
|
||||
$table->integer('status')->nullable();
|
||||
$table->json('fields')->nullable();
|
||||
$table->text('exception')->nullable();
|
||||
$table->timestamps(6);
|
||||
$table->timestamp('finished_at', 6)->nullable();
|
||||
|
||||
$table->index(['batch_id', 'model_type', 'model_id']);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('activity_log')) {
|
||||
Schema::create('activity_log', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('log_name')->nullable()->index();
|
||||
$table->text('description');
|
||||
$table->nullableMorphs('subject', 'subject');
|
||||
$table->nullableMorphs('related', 'related');
|
||||
$table->string('event')->nullable();
|
||||
$table->nullableMorphs('causer', 'causer');
|
||||
$table->json('attribute_changes')->nullable();
|
||||
$table->json('properties')->nullable();
|
||||
$table->integer('status')->nullable();
|
||||
$table->text('exception')->nullable();
|
||||
$table->timestamps(6);
|
||||
$table->timestamp('finished_at', 6)->nullable();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
+5
-5
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Enums\Models\Admin\ActionLogStatus;
|
||||
use App\Enums\Models\Admin\ActivityStatus;
|
||||
use App\Enums\Models\List\ExternalEntryStatus;
|
||||
use App\Enums\Models\List\ExternalProfileSite;
|
||||
use App\Enums\Models\List\ExternalProfileVisibility;
|
||||
@@ -20,10 +20,10 @@ use App\Enums\Models\Wiki\VideoSource;
|
||||
use App\Enums\Pivots\Document\PageRoleType;
|
||||
|
||||
return [
|
||||
ActionLogStatus::class => [
|
||||
ActionLogStatus::RUNNING->name => 'Running',
|
||||
ActionLogStatus::FAILED->name => 'Failed',
|
||||
ActionLogStatus::FINISHED->name => 'Finished',
|
||||
ActivityStatus::class => [
|
||||
ActivityStatus::RUNNING->name => 'Running',
|
||||
ActivityStatus::FAILED->name => 'Failed',
|
||||
ActivityStatus::FINISHED->name => 'Finished',
|
||||
],
|
||||
AnimeFormat::class => [
|
||||
AnimeFormat::TV->name => 'TV',
|
||||
|
||||
@@ -515,7 +515,7 @@ return [
|
||||
],
|
||||
],
|
||||
'fields' => [
|
||||
'action_log' => [
|
||||
'activity' => [
|
||||
'name' => 'Name',
|
||||
'target' => 'Target',
|
||||
'status' => 'Status',
|
||||
@@ -1015,7 +1015,7 @@ return [
|
||||
],
|
||||
'resources' => [
|
||||
'label' => [
|
||||
'action_logs' => 'Action Logs',
|
||||
'activities' => 'Activities',
|
||||
'anime_theme_entries' => 'Anime Theme Entries',
|
||||
'anime_themes' => 'Anime Themes',
|
||||
'anime' => 'Anime',
|
||||
@@ -1051,7 +1051,7 @@ return [
|
||||
'videos' => 'Videos',
|
||||
],
|
||||
'singularLabel' => [
|
||||
'action_log' => 'Action Log',
|
||||
'activity' => 'Activity',
|
||||
'anime_theme_entry' => 'Anime Theme Entry',
|
||||
'anime_theme' => 'Anime Theme',
|
||||
'anime' => 'Anime',
|
||||
|
||||
Reference in New Issue
Block a user