Skip to content

Conversation

erikriv16
Copy link
Contributor

@erikriv16 erikriv16 commented Jul 15, 2025

Overview:

This PR introduces an Audit Data Trails admin page that allows users to look up recent session activity by entering a username. It retrieves the most recent session and displays all associated actions across multiple portals.

PR Status:

  • Ready.
  • Work in Progress.
  • Hold.

Related Jira tickets:

Summary of Changes:

  • Created a new admin view under the Designsafe portal for audit trail lookups

  • Implemented backend logic to:

    • Retrieve the most recent session for a given username
    • Query all associated audit actions tied to that session across portals
    • Basic frontend added with search input and results display
    • Placeholder for future file search integration

Testing Steps:

  1. Get updated designsafe.env from stache with Audit Trails secrets

  2. From the top-right dropdown menu, select "Audit Trails Admin"

  3. For testing purposes:

    • Enter the username "joyce_cywu" to generate a populated example
    • To test other users, comment out the second query in portal/designsafe/apps/audit/views.py
  4. Confirm that audit actions from the most recent session are being fetched and displayed correctly

UI Photos:

Screenshot 2025-07-15 at 1 17 22 PM Screenshot 2025-07-15 at 1 17 36 PM Screenshot 2025-07-15 at 1 17 48 PM Screenshot 2025-07-15 at 1 17 59 PM

Notes:

TACC Staff and others added 10 commits June 18, 2025 10:36
…ounts", not sure if supposed to follow same way other tab on there are created or make something completely new, have UI set up in html under "terms and conditions" in manage account section.
… Changed names on dropdown menu for type of search, implemented username auto-search dropdown menu capability for easier selection, added css file for AuditTrials.tsx
@erikriv16
Copy link
Contributor Author

Need recommendation if I should create new hook files to handle getting the query information from the functions in audit/views.py, maybe like a useUserAudit.ts for the username search and a useFileAudit.ts for the file search. Also if I should ignore most of the missing module docstring errors I'm getting on serverside linting because other apps.py and urls.py in the codebase don't have them at all.

@rstijerina rstijerina changed the title Task/WP-930 task/WP-930: Audit Trails UI Jul 16, 2025
@rstijerina
Copy link
Member

Need recommendation if I should create new hook files to handle getting the query information from the functions in audit/views.py, maybe like a useUserAudit.ts for the username search and a useFileAudit.ts for the file search. Also if I should ignore most of the missing module docstring errors I'm getting on serverside linting because other apps.py and urls.py in the codebase don't have them at all.

Yes, new hooks would be good.

Serverside linting is r.e. trailing whitespace and missing newlines:

 ************* Module designsafe.apps.audit.__init__
designsafe/apps/audit/__init__.py:1:0: C0304: Final newline missing (missing-final-newline)
************* Module designsafe.apps.audit.apps
designsafe/apps/audit/apps.py:8:43: C0303: Trailing whitespace (trailing-whitespace)
designsafe/apps/audit/apps.py:4:0: C0115: Missing class docstring (missing-class-docstring)
************* Module designsafe.apps.audit.urls
designsafe/apps/audit/urls.py:10:0: C0304: Final newline missing (missing-final-newline)
************* Module designsafe.apps.audit.views
designsafe/apps/audit/views.py:49:0: C0303: Trailing whitespace (trailing-whitespace)
designsafe/apps/audit/views.py:116:0: C0303: Trailing whitespace (trailing-whitespace)
designsafe/apps/audit/views.py:120:0: C0304: Final newline missing (missing-final-newline)
designsafe/apps/audit/views.py:56:11: W0718: Catching too general exception Exception (broad-exception-caught)
designsafe/apps/audit/views.py:118:11: W0718: Catching too general exception Exception (broad-exception-caught)

Copy link
Contributor

@fnets fnets left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking super clean, and easy to read! Thanks so much!

I think what we need now is some unit testing and to address the linting errors that are popping up. You can usually check these locally by running the same script that github actions does (npx nx format:check and pylint)

@jarosenb jarosenb marked this pull request as draft August 1, 2025 18:27
Copy link
Contributor

@fnets fnets left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's some work to be done on these tests, still. But a great start!

TACC Staff added 3 commits August 13, 2025 11:21
… include (essential-graphrag.pdf, TAPIS_ERROR_ex_file.png) --case insensitive, still need to implement file tracking from submitJob action, need to figure out file tracking on tapis side, and fix small bugs on both ends
…Job included, and try to rework UI into more of a tree like format
@fnets fnets self-requested a review September 9, 2025 14:33
@rstijerina rstijerina marked this pull request as ready for review September 11, 2025 21:26
Copy link
Member

@rstijerina rstijerina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some really good work here connecting pieces together. I think we can clean it up a bit

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you point me to what changed in this file?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason we don't want to use class based views here? You could use the AuthenticatedApiView, which would cut down on repeated @login_required decorators


{auditData?.data && auditData.data.length > 0 && (
<div className="styles.tableWrapper">
<table
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future, I would suggest using antd's Table component

Comment on lines +39 to +50
//using in filetable as well, maybe move to another file?
const formatTimestamp = (timestamp: string) => {
const date = new Date(timestamp);
return date.toLocaleString('en-US', {
hour: 'numeric',
minute: '2-digit',
hour12: true,
month: 'numeric',
day: 'numeric',
year: '2-digit',
});
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If duplicated, best to pull out into a util file somewhere, and import from there

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking this too but not sure if it would have been best to pull out to utils, thank you!


return (
<div>
<form onSubmit={onSearch} style={{ marginBottom: 16 }}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Antd components would give us some nice UI styling for free

FROM public.portal_audit
WHERE username = %s
ORDER BY timestamp DESC
LIMIT 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we only want 1 response?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, here we only limit it to 1 because we only look for the single most recent session.

Comment on lines +229 to +238
def get_path_without_filename(full_path):
"""Extract path without filename"""
if not full_path or "." not in full_path.split("/")[-1]:
return full_path
return "/".join(full_path.rstrip("/").split("/")[:-1])

def get_filename_from_path(full_path):
return full_path.rstrip("/").split("/")[-1].lower()

def normalize_dir_path(p):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'll want to refactor this to not have nested functions



@login_required
def get_rename_portal_search(request, filename):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the same as get_upload_portal_search?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, so this one handles things a little differently, but uses get_upload_portal_search() if the upload row is found to get its full trace.

'designsafe.apps.api.publications_v2',
'designsafe.apps.api.filemeta',
'designsafe.apps.accounts',
'designsafe.apps.audit',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're not running tests, you'll want to remove this line.

@fnets fnets self-requested a review September 15, 2025 16:58
Copy link
Contributor

@fnets fnets left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would second Sal's comments, and there's a small part of turning off your unit tests that still needs to be done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants