Feature/audit frontend#264
Merged
Merged
Conversation
Backend: - AuditFilter with content_type__model (method-based) and object_id - AuditViewSet: select_related, search_fields, ordering_fields, ordering - Exclude last_login from User auditlog tracking Frontend — new files: - api/services/audit.jsx: getAudits, getObjectAudits with pagination - views/audits/ListAudit.jsx: global audit log page with search/pagination - views/audits/components/TableAudit.jsx: table with action badges - views/audits/components/AuditModal.jsx: reusable modal with paginated 'Load more' + auto-scroll, per-object audit history Frontend — AuditModal button added to 12 views: - ReadEvent, ReadCase, ViewNetwork, ViewContact (dedicated pages) - TableFeed, TableContact, TableTaxonomy, TableStates, TablePriorities, TableReport, TableUsers, ModalDetailNetwork (table modals) Frontend — routing/menu: - Route /audits with view_logentry permission - Menu item 'Audit Log' under Configuration - i18n: w.action, w.changes, w.load_more, ngen.audit.title, menu.audit
- AuditViewSet was missing filter_backends, so filterset_class (AuditFilter) was silently ignored — content_type__model and object_id filtering had no effect. - Added filter_backends with DjangoFilterBackend, SearchFilter, OrderingFilter so filtering, search, and ordering all work. - Added 'filters' to rest_framework imports. - TestAuditFilter (4 cases): verifies method-based filter correctly excludes entries from other content_types sharing the same object_id, handles nonexistent models, and returns all models when content_type filter is omitted.
- Register ngen.TaggedObject (custom taggit through model) with auditlog - Add post_save signal on TaggedObject that creates LogEntry for the parent (Event/Case) when tags are added/updated - Generic THROUGH_MODELS dict in AuditFilter maps parent models to their through models (fk or gfk), enabling filter_by_model to include through-model entries via Subquery - Covers: Event (TodoTask, Evidence, ArtifactRelation, TaggedObject) and Case (Evidence, ArtifactRelation, TaggedObject) - Tests: signal creates audit entry for parent; filter includes through-model entries for event
- post_delete handler creates LogEntry for parent (Event/Case) with
changes={"tags": ["", "removed: <tag>"]} when a tag is removed
- Test verifies tag removal generates audit entry for parent
Signals (signals.py): - m2m_changed handler that creates LogEntry for parent model when M2M relations change (post_add/post_remove/post_clear) - Covers Network.contacts, Contact.users, Playbook.taxonomy — the three M2M fields without custom through models that were not previously tracked Tests (test_audit.py): - TestM2MAuditSignals: 4 tests for network contacts add/remove, contact users add, playbook taxonomy add - TestCaseBasicAudit: 2 tests verifying Case creation and update generate audit entries - Total: 13 audit tests, all passing
…fined objectId
ReadCase uses id as a plain string (from URL split), ViewNetwork
and ViewContact destructure {id} from useParams(). All three were
passing id.id (undefined) instead of id. Only ReadEvent was correct
because it stores the full useParams() object in useState.
- AuditModal.jsx: rows expand/collapse on click showing full changes text without truncation - TableAudit.jsx: same expandable behavior for global audit list - Clicking a row toggles between truncated (maxWidth + ellipsis) and expanded (full content, no width limit)
Backend (signals.py): - m2m_changed signal now stores related model name alongside PKs e.g. 'post_add [contact]: [1, 2, 3]' instead of 'post_add: [1, 2, 3]' Frontend (AuditModal.jsx, TableAudit.jsx): - renderValue function parses M2M change patterns and renders each PK as a React Router Link to e.g. /contacts/view/1, /users/view/2 - Covers: Network.contacts → contact, Contact.users → user, Playbook.taxonomy → taxonomy
- pre_save signal stores old case_id before Event save - post_save signal compares old vs new case_id and creates LogEntry on the Case side (added/removed event) - Tests: link event to case creates audit on Case; unlink also creates audit on Case (in addition to existing Event audit)
Backend (signals.py): - _log_event_case_audit now includes event UUID/domain and uses format 'added [event]: #21 (domain.com)' for FK link detection Frontend (AuditModal.jsx, TableAudit.jsx): - renderValue now detects FK patterns like 'added [model]: #pk (...)' and renders the PK as a clickable Link to /models/view/pk - Works alongside existing M2M pattern detection
AuditSerializer now adds actor_username and content_type_model as computed fields (via SerializerMethodField) instead of relying on HyperlinkedRelatedField URLs. Frontend tables updated to use these new fields instead of a.actor?.username and a.content_type?.model which were always undefined.
auditlog.register(TaggedObject) creates LogEntry records but TaggedObject has no DRF ViewSet, so generic_detail_link raises NoReverseMatch. Catch both ObjectDoesNotExist and NoReverseMatch in get_related() to prevent 500 errors on /api/audit/.
Backend (AuditFilter): - action: ChoiceFilter (0=Create, 1=Update, 2=Delete) - actor__username: CharFilter (icontains) - timestamp_after / timestamp_before: DateTimeFilter (gte/lte) Frontend (ListAudit.jsx): - Action dropdown (Create/Update/Delete/All) - Reporter text input - Type text input - Date range (datetime-local from/to) Tests: action filter + actor filter (17 total)
Match the design pattern used by /events: filters are hidden behind a toggle button (FilterToolbar) with Bootstrap Collapse. FilterToolbar also provides clear-filters and reload buttons.
…izing
Filters now use the same visual style as ListEvent.jsx:
- Date inputs use type='date' (not datetime-local)
- Form controls at default size (not size='sm')
- Same Col layout (sm={4} lg={4}) for filter row
- FilterToolbar positioned identically
Replace transparent var(--bs-dropdown-bg) with solid #1e1f22 for both react-select__menu and react-select__menu-list to fix transparent background issue in dark mode.
Replace native Form.Select with react-select component to match the filter style used across the frontend (/events, etc.)
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds an end-to-end Audit Log feature spanning backend filtering/serialization and a new frontend audit UI (list page + per-object modal), plus navigation and translations to expose it across the app.
Changes:
- Backend: adds audit filtering/search/ordering support, enriches audit serialization, and adds signals to log tag/m2m/event↔case relationship changes.
- Frontend: introduces an audit list page and reusable audit components (table + modal) and wires the modal into multiple entity views.
- UI/UX: adds menu + route entry for audit log, adds EN/ES translations, and tweaks dark mode styling for react-select.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| ngen/views/tools.py | Adds AuditFilter and enables DRF filtering/search/ordering for the audit endpoint. |
| ngen/tests/api/test_audit.py | Adds backend tests for audit filtering and signal-driven audit entries. |
| ngen/signals.py | Adds audit logging for tags, selected m2m relations, and Event↔Case link/unlink actions. |
| ngen/serializers/tools.py | Extends audit serializer with actor_username and content_type_model for frontend display. |
| ngen/models/init.py | Registers additional models with auditlog (User/TaggedObject). |
| frontend/src/views/user/components/TableUsers.jsx | Adds per-user audit modal access from the user detail modal. |
| frontend/src/views/taxonomy/components/TableTaxonomy.jsx | Adds per-taxonomy audit modal access from taxonomy modal. |
| frontend/src/views/state/components/TableStates.jsx | Adds per-state audit modal access from state modal. |
| frontend/src/views/report/components/TableReport.jsx | Adds per-report audit modal access from report modal. |
| frontend/src/views/priority/components/TablePriorities.jsx | Adds per-priority audit modal access from priority modal. |
| frontend/src/views/network/ViewNetwork.jsx | Adds audit modal access from network view page. |
| frontend/src/views/network/components/ModalDetailNetwork.jsx | Adds audit modal access from network detail modal. |
| frontend/src/views/feeds/components/TableFeed.jsx | Adds per-feed audit modal access from feed modal. |
| frontend/src/views/event/ReadEvent.jsx | Adds audit modal access from event read page. |
| frontend/src/views/contact/ViewContact.jsx | Adds audit modal access from contact view page. |
| frontend/src/views/contact/components/TableContact.jsx | Adds per-contact audit modal access from contact modal. |
| frontend/src/views/case/ReadCase.jsx | Adds audit modal access from case read page. |
| frontend/src/views/audits/ListAudit.jsx | New audit log list page with filters, search, ordering, pagination. |
| frontend/src/views/audits/components/TableAudit.jsx | New table component for rendering audit entries and change details. |
| frontend/src/views/audits/components/AuditModal.jsx | New per-object audit history modal with “load more” pagination. |
| frontend/src/routes.jsx | Registers /audits route guarded by view_logentry. |
| frontend/src/menu-items.jsx | Adds Audit Log entry to the main menu. |
| frontend/src/config/constant.jsx | Registers audit API endpoint base path. |
| frontend/src/assets/scss/partials/_dark-mode.scss | Adjusts react-select menu background in dark mode. |
| frontend/src/api/services/audit.jsx | Adds API service functions to fetch audits and per-object audits. |
| frontend/public/locales/es/translation.json | Adds ES strings for audit UI. |
| frontend/public/locales/en/translation.json | Adds EN strings for audit UI. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Audit tests (TestAuditFilterThroughModels) create Events which advance the auto-increment sequence even when rolled back. The case post test hardcoded pk=1 as the event URL, causing 400 when the test Event got a higher PK. Fixed by using the actual event.pk.
…crash Backend fixes: - CaseSerializer.update(): always sync events on PUT — elif is_put unlinks all when events key is missing from FormData - EventSerializer: declare case with allow_null=True, required=False - audit_m2m_changes: guard sorted(pk_set) for post_clear (pk_set=None) - _store_event_old_case/_audit_event_case_link: use instance attribute instead of module-level dict (thread-safe) - AuditViewSet: ModelViewSet → ReadOnlyModelViewSet (defense in depth) - FormEvent.deleteCaseFromForm(): clear body.case for event unlink - AuditFilter: THROUGH_MODELS for M2M/dependent audit coverage - TaggedObject signals: post_save/post_delete for tag audit tracking - m2m_changed handler: audit Contact.users, Network.contacts, Playbook.taxonomy - User auditlog register: exclude_fields=['last_login'] - auto_link_contact_by_email: post_save signal on User creation Frontend fixes: - setupInterceptors.jsx: setAlert → console.error (dedup) - users.jsx: remove duplicate setAlert calls - TablePriorities.jsx: fix priority.data.url crash - FormCase.jsx: always send events in editCase (no conditional guard) - Audit list: FilterToolbar + Collapse, date range filters - Audit modal: per-object paginated audit view with Load more - Audit renderValue: parse M2M and FK patterns into links/display Tests: - test_case_put_unlinks_removed_events, test_case_put_empty_events_unlinks_all - test_event_put_without_case, test_event_patch_clear_case - 17 audit tests covering filters, through models, M2M signals, case audit - 504 tests passing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request introduces a comprehensive frontend audit log feature, including new API services, UI components, menu integration, and localization enhancements. The audit log allows users to view, filter, and inspect object-level change history, with support for detailed change rendering and multi-language support.
Audit Log Feature Implementation:
getAudits,getObjectAudits) for fetching audit logs and object-specific audit history. (frontend/src/api/services/audit.jsx)frontend/src/views/audits/ListAudit.jsx)frontend/src/views/audits/components/TableAudit.jsx)frontend/src/views/audits/components/AuditModal.jsx)Navigation and Routing:
frontend/src/menu-items.jsx,frontend/src/routes.jsx) [1] [2]frontend/src/views/case/ReadCase.jsx)Localization and UI Enhancements:
frontend/public/locales/en/translation.json,frontend/public/locales/es/translation.json) [1] [2] [3] [4]frontend/src/assets/scss/partials/_dark-mode.scss)Configuration:
frontend/src/config/constant.jsx)