Add Admin CRUD#2330
Conversation
📝 WalkthroughWalkthroughThis PR implements comprehensive admin activity logging for the Pelican panel. It adds a generic ChangesAdmin Activity Logging
Possibly Related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (1 warning, 2 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/Observers/AdminActivityObserver.php`:
- Around line 75-78: The update handlers in AdminActivityObserver (e.g.,
userUpdated) only log the current name; change them to compute per-field old/new
diffs using the model's dirty attributes (getDirty() or getChanges()) and
getOriginal() while excluding noisy keys like updated_at, then pass a structured
"changes" payload to $this->log (e.g., ['changes' => ['email' => ['old' => ...,
'new' => ...], ...]]); apply the same change to the other update handlers
referenced (the methods at the other ranges) so all admin:*.update events
include per-field old/new values for auditability.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: d200f5ac-1dec-45f6-ad5f-affb1c5d9c33
📒 Files selected for processing (9)
app/Filament/Admin/Pages/Settings.phpapp/Filament/Admin/Resources/ActivityLogs/ActivityLogResource.phpapp/Filament/Admin/Resources/ActivityLogs/Pages/ListActivityLogs.phpapp/Filament/Admin/Resources/Users/UserResource.phpapp/Models/ActivityLog.phpapp/Models/Role.phpapp/Models/User.phpapp/Observers/AdminActivityObserver.phpapp/Providers/AppServiceProvider.php
There was a problem hiding this comment.
♻️ Duplicate comments (1)
app/Observers/AdminActivityObserver.php (1)
77-86:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftUpdate events still lack before/after values for changed fields.
The update handlers only capture which field names changed, not the actual old and new values. Per the PR objectives from issue
#1585: "with descriptive entries and metadata, including before/after values where applicable." This is essential for proper audit trail reconstruction—knowing that "email" changed is insufficient without seeing it changed fromold@example.comtonew@example.com.The past review comment on this code segment provided a specific implementation approach using
getOriginal()andgetChanges()to capture per-field diffs while excluding noisy keys.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/Observers/AdminActivityObserver.php` around lines 77 - 86, The userUpdated handler currently only records field names; update it to record before/after values by using User::getOriginal() and User::getChanges() (or modify changedFieldsFor to return an associative map of changedField => ['from'=>original, 'to'=>changed]) and pass that map into $this->log instead of just implode(', ', $changedFields); exclude noisy keys like updated_at, last_login, password_digest (or whatever keys changedFieldsFor already filters) so the log payload contains count, a descriptive name and a 'changes' object with per-field {from,to} entries; ensure you update any callers of changedFieldsFor or userUpdated to expect the new shape and preserve the existing log keys ('name', 'count') while adding the detailed 'changes' metadata.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@app/Observers/AdminActivityObserver.php`:
- Around line 77-86: The userUpdated handler currently only records field names;
update it to record before/after values by using User::getOriginal() and
User::getChanges() (or modify changedFieldsFor to return an associative map of
changedField => ['from'=>original, 'to'=>changed]) and pass that map into
$this->log instead of just implode(', ', $changedFields); exclude noisy keys
like updated_at, last_login, password_digest (or whatever keys changedFieldsFor
already filters) so the log payload contains count, a descriptive name and a
'changes' object with per-field {from,to} entries; ensure you update any callers
of changedFieldsFor or userUpdated to expect the new shape and preserve the
existing log keys ('name', 'count') while adding the detailed 'changes'
metadata.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: e469d3ab-be87-42c6-a0ca-b0baee457bae
📒 Files selected for processing (4)
app/Filament/Admin/Resources/ActivityLogs/ActivityLogResource.phpapp/Observers/AdminActivityObserver.phpapp/Providers/AppServiceProvider.phplang/en/activity.php
🚧 Files skipped from review as they are similar to previous changes (1)
- app/Providers/AppServiceProvider.php
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/Observers/AdminActivityObserver.php`:
- Around line 47-53: The deduplication currently builds $key as
"$event:$model::class:{$model->getKey()}" in AdminActivityObserver which
suppresses subsequent distinct changes to the same record; change the key to
include the change signature (for example a hash/serialized representation of
the changed attributes or getChanges()/getDirty() keys or values) so identical
events with different modifications are not deduplicated — update the $key
construction to combine $event, $model::class, $model->getKey() and a stable
fingerprint of the model's changes before setting/checking self::$logged[$key].
- Around line 72-81: The updated() observer should early-return when no
auditable fields changed: use changedFieldsFor($model) and if it returns an
empty array (count 0) skip calling log() to avoid noisy entries; update the
updated(Model $model) method to check changedFieldsFor($model) and only call
$this->log($this->eventFor($model, 'update'), $model, [...]) when there are
changed fields, keeping existing uses of displayNameFor(), eventFor(), and
log().
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 660f4b16-e438-418f-a0dc-1d159e9472a6
📒 Files selected for processing (9)
app/Eloquent/BackupQueryBuilder.phpapp/Models/Egg.phpapp/Models/Node.phpapp/Models/Role.phpapp/Models/Server.phpapp/Models/User.phpapp/Observers/AdminActivityObserver.phpapp/Traits/HasAdminActivityLogging.phplang/en/admin/log.php
✅ Files skipped from review due to trivial changes (4)
- lang/en/admin/log.php
- app/Models/Egg.php
- app/Eloquent/BackupQueryBuilder.php
- app/Traits/HasAdminActivityLogging.php
🚧 Files skipped from review as they are similar to previous changes (2)
- app/Models/Role.php
- app/Models/User.php
| // Deduplicate identical events for the same record within a single request. | ||
| $key = $event . ':' . $model::class . ':' . $model->getKey(); | ||
| if (isset(self::$logged[$key])) { | ||
| return; | ||
| } | ||
| self::$logged[$key] = true; | ||
|
|
There was a problem hiding this comment.
Deduplication key can drop valid audit entries.
Line 48 deduplicates by {event}:{model}:{id} only. If the same record is updated twice in one request with different changes, the second event is suppressed and the audit trail is incomplete.
Suggested fix
- $key = $event . ':' . $model::class . ':' . $model->getKey();
+ $fingerprint = md5(serialize($properties));
+ $key = $event . ':' . $model::class . ':' . $model->getKey() . ':' . $fingerprint;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/Observers/AdminActivityObserver.php` around lines 47 - 53, The
deduplication currently builds $key as "$event:$model::class:{$model->getKey()}"
in AdminActivityObserver which suppresses subsequent distinct changes to the
same record; change the key to include the change signature (for example a
hash/serialized representation of the changed attributes or
getChanges()/getDirty() keys or values) so identical events with different
modifications are not deduplicated — update the $key construction to combine
$event, $model::class, $model->getKey() and a stable fingerprint of the model's
changes before setting/checking self::$logged[$key].
| public function updated(Model $model): void | ||
| { | ||
| $changedFields = $this->changedFieldsFor($model); | ||
| $name = $this->displayNameFor($model); | ||
|
|
||
| $this->log($this->eventFor($model, 'update'), $model, [ | ||
| 'name' => empty($changedFields) ? $name : sprintf('%s (%s)', $name, implode(', ', $changedFields)), | ||
| 'count' => count($changedFields), | ||
| 'changes' => implode(', ', $changedFields), | ||
| ]); |
There was a problem hiding this comment.
Skip update logs when no auditable fields changed.
Line 77 still logs updates when changedFieldsFor() returns empty (for example, only updated_at changed). That creates noisy entries with count = 0 and empty changes.
Suggested fix
public function updated(Model $model): void
{
$changedFields = $this->changedFieldsFor($model);
+ if ($changedFields === []) {
+ return;
+ }
+
$name = $this->displayNameFor($model);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/Observers/AdminActivityObserver.php` around lines 72 - 81, The updated()
observer should early-return when no auditable fields changed: use
changedFieldsFor($model) and if it returns an empty array (count 0) skip calling
log() to avoid noisy entries; update the updated(Model $model) method to check
changedFieldsFor($model) and only call $this->log($this->eventFor($model,
'update'), $model, [...]) when there are changed fields, keeping existing uses
of displayNameFor(), eventFor(), and log().
Closes #1585
Adds logging for admin curd actions, and panel setting edits. Also includes a role permission to allow other admins to see it or not.