Skip to content

Add anonymizing of user applications feature#4702

Merged
wes-otf merged 26 commits into
mainfrom
feature/clean_user_pii
May 1, 2026
Merged

Add anonymizing of user applications feature#4702
wes-otf merged 26 commits into
mainfrom
feature/clean_user_pii

Conversation

@wes-otf
Copy link
Copy Markdown
Contributor

@wes-otf wes-otf commented Feb 17, 2026

Would close #3441. Adds a new AnonymizedSubmission model that only contains minimal, non-PII datapoints. Also adds UI features for staff to select whether a user's application(s) should be deleted or converted to skeletoned/anonymized application.

The todos:

  • Implement AnonymizedSubmission model & creation methods
  • Handle manual individual submission deletions
  • Handle manual bulk submission deletions/anonymization
  • Handle submissions with individual user deletions
  • Handle submissions with bulk user deletions
  • Include anonymized submissions in the results dashboard
  • Add unit tests for new functionality

Test Steps

@wes-otf wes-otf force-pushed the feature/clean_user_pii branch 3 times, most recently from b389175 to 0bc0caf Compare March 3, 2026 15:48
@wes-otf wes-otf force-pushed the feature/clean_user_pii branch 2 times, most recently from 9ae8d11 to 30b37bd Compare March 18, 2026 19:57
@wes-otf wes-otf requested a review from frjo March 18, 2026 19:58
@wes-otf
Copy link
Copy Markdown
Contributor Author

wes-otf commented Mar 18, 2026

@frjo I'm going to add a unit test for the results view, some docs & do a final look over but it should be ready for review if you wanted to take a look before that

Comment thread hypha/apply/funds/views/results.py Outdated
SubmissionSkeletonFilter.declared_filters
)
if not set(self.request.GET) & set(non_skeleton_fields):
skeleton_qs = SubmissionSkeletonFilter(
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

somewhat of a hacky solution to managing 2 models with one FilterView but seems to work?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

seems like the # of SQL queries shoots up though so might need some optimizing

@wes-otf wes-otf marked this pull request as ready for review March 19, 2026 16:09
@wes-otf wes-otf changed the title WIP: Add "skeletoning"/anonymizing of user applications Add "skeletoning"/anonymizing of user applications Mar 19, 2026
@frjo frjo added Type: Feature This is something new (not an enhancement of an existing thing). Type: Minor Minor change, used in release drafter labels Apr 3, 2026
@frjo frjo force-pushed the feature/clean_user_pii branch from 30b37bd to a5e160a Compare April 13, 2026 13:51
@frjo
Copy link
Copy Markdown
Member

frjo commented Apr 13, 2026

@wes-otf I rebased this with main to solve a small merge conflict.

@frjo
Copy link
Copy Markdown
Member

frjo commented Apr 13, 2026

@wes-otf When I was testing this I realised we have some existing issues with deleted/archive. When I started with fixing that more things followed as you can see in the PR now 😄.

  • The backend is nearly untouched. This part seems to works really well!
  • The wagtail admin part is nearly untouched as well, only added some classes for margins etc.

My changes:

  1. Renamed everything skeleton -> anonymize, makes it easier to read the code I believe.
  2. Added some tests.
  3. Added "Anonymise" button in "MORE ACTIONS" section on submission detail. Anonymise also has its own confirm modal now.
  4. Moved "Delete" button to "MORE ACTIONS" section for staff as well. I think this makes more sense.
  5. Reverted changes to SubmissionDeleteView since they are not used any more.

@frjo
Copy link
Copy Markdown
Member

frjo commented Apr 13, 2026

The batch functions on submission/all only have a simple js alert while the same functions for a single submission has a nice modal. That is not logical. Will fix that in a separate PR.

Copy link
Copy Markdown
Member

@frjo frjo left a comment

Choose a reason for hiding this comment

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

This works very well in my testing, the backend seems solid. The anonymised submission has very little information left since all form_data is deleted. The feature talk about removing PII info, some might be surprised that almost nothing besides the value remain.

Maybe this can be communicated better?

@frjo frjo changed the title Add "skeletoning"/anonymizing of user applications Add anonymizing of user applications feature Apr 14, 2026
@frjo frjo force-pushed the feature/clean_user_pii branch from b858e27 to 7b7d9a0 Compare April 22, 2026 15:32
Comment thread hypha/apply/funds/services.py Outdated
Comment thread hypha/apply/funds/views/all.py Outdated
* `round` - round (if any) the original submission was in
* `submit_time` - time the original submission was submitted
* `screening_status` - screening status of the original submission
* `category` - the categories of the original submission
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are categories always preserved? Will try to test this for bulk_anonymize_submissions, submission_cleanup and on user delete.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes they should be as of the latest push, needed to add form_fields to the values(...) call for them to be parsed

Comment thread hypha/apply/funds/management/commands/submission_cleanup.py
Comment thread docs/setup/administrators/cron-jobs.md Outdated
timestamp = models.DateTimeField()
type = models.CharField(choices=ACTIVITY_TYPES.items(), max_length=30)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This needs to be documented I think. Deleting a user will now delete the audit trail.

Would it not be better to anonymise the user account instead of deleting it? Or do the activities contain sensitive info?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm thinking that would likely be another PR/feature if we wanted to go that route. As it stands I'm the only one at OTF that can delete a user when a GDPR request comes in for deletion because all staff member gets in wagtail is an error saying the user is used elsewhere but never pointed to which specific activity that is. This is definitely more of a nuclear option but definitely GDPR compliant as activities can contain a host of data especially when it's a comment - open to your thoughts on this though!

"""
return reverse("wagtailusers_users:edit", args=[self.id])

def delete(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this needed, does not the wagtail_hook handle this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I added it for any manual .delete()s that could come of the user model (as we continue w retention tooling I could see it being used in accounts_cleanup)

user=self.request.user,
request=self.request,
source=submission,
)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This records an event but no adapter (slack/mail etc.) is configured. Is the submission not deleted at this stage so "submission" is empty?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed by both adding a slack adapter and pushing the super call down past the messaging call

Comment thread hypha/templates/cotton/modal/confirm.html Outdated
…ation notifications for slack, pulled `form_fields` from values for categories
@wes-otf
Copy link
Copy Markdown
Contributor Author

wes-otf commented Apr 30, 2026

@frjo thanks for the feedback! I appreciate the attention to detail in the review, especially the stuff around messaging I'm not sure if I wouldn't quite caught that

@wes-otf wes-otf requested a review from frjo April 30, 2026 17:32
Copy link
Copy Markdown
Member

@frjo frjo left a comment

Choose a reason for hiding this comment

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

Found two bugs, other than that it seems to work nicely now.

Comment thread hypha/apply/users/wagtail_hooks.py Outdated
Comment thread hypha/apply/funds/services.py
@wes-otf
Copy link
Copy Markdown
Contributor Author

wes-otf commented May 1, 2026

Fat fingering got me again - gonna deploy to test and make sure all looks good over there. Thanks again @frjo!

@frjo frjo self-requested a review May 1, 2026 16:52
@wes-otf
Copy link
Copy Markdown
Contributor Author

wes-otf commented May 1, 2026

Seems to work good on test - I think theres some general issues with the category filtering (for applications both normal and anonymized) that I need to look at when in the results view but I think that might be out of scope here

@wes-otf wes-otf merged commit f705a99 into main May 1, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Status: Tested - approved for live ✅ Type: Feature This is something new (not an enhancement of an existing thing). Type: Minor Minor change, used in release drafter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deactivate and anonymise user accounts

2 participants