*/ private const SUBJECTS = [ \App\Models\User::class => 'user', \App\Modules\Files\Models\File::class => 'file', \App\Modules\Files\Models\Folder::class => 'folder', \App\Modules\Files\Models\Category::class => 'category', \App\Modules\Groups\Models\Group::class => 'group', \App\Modules\Identity\Models\Role::class => 'role', \App\Modules\Clients\Models\ClientCustomField::class => 'client_custom_field', ]; /** * The map, for the controller's reverse lookup. * * @return array */ public static function subjects(): array { return self::SUBJECTS; } /** * @return array */ public function toArray(Request $request): array { return [ 'id' => $this->id, 'action' => $this->action->value, 'created_at' => $this->created_at->toIso8601String(), // Snapshots, not joins. The actor may since have been deleted, // and the entry still has to say who it was. 'actor' => $this->actor_id === null && $this->actor_name === null ? null : [ 'id' => $this->actor_id, 'name' => $this->actor_name, 'type' => $this->actor_type, ], // How it arrived: a person in the browser, an integration, a // visitor with no account, or the installation itself. 'origin' => $this->origin->value, 'subject' => $this->subject_type === null ? null : [ 'type' => self::SUBJECTS[$this->subject_type] ?? 'other', 'id' => $this->subject_id, 'name' => $this->subject_name, ], // Whatever the action recorded beyond its subject — who a file // was shared with, how many files a cascade removed. Shape // varies by action and is documented per action rather than // here. 'context' => $this->context ?? [], // ip_address is deliberately absent. It is stored for some // actions and shown on the activity screen, but handing a // client's IP to an automation tool is a privacy expansion // with no matching use — see docs/api-todo.md. ]; } }