-
-
Notifications
You must be signed in to change notification settings - Fork 24
feature: create a feature to allow easy anonymization of donors #619
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
tudoramariei
commented
Jan 13, 2026
- create a feature to allow the anonymization of all the "old" donations (>1/2 years old)
- allow anonymization of a donation in different contexts in the admin
- create a feature to allow the anonymization of all the "old" donations (>1/2 years old) - allow anonymization of a donation in different contexts in the admin
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request introduces a donor anonymization feature that allows administrators to anonymize donation data for privacy compliance, particularly for donations older than 1-2 years. The feature includes both manual and bulk anonymization capabilities through the Django admin interface.
Changes:
- Added donor anonymization functionality with async/sync execution support
- Created crypto helper utilities to centralize encryption/decryption operations
- Introduced admin actions for anonymizing individual and bulk donations
- Added time constants (MONTH, YEAR) for date calculations in anonymization logic
Reviewed changes
Copilot reviewed 11 out of 14 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| backend/utils/constants/time.py | Added MONTH and YEAR constants for time-based calculations |
| backend/utils/common/crypto_helper.py | Created centralized encryption/decryption helper functions |
| backend/redirectioneaza/settings/environment.py | Added USER_ANONIMIZATION_METHOD configuration parameter |
| backend/redirectioneaza/settings/app_configs.py | Configured anonymization method with fallback to default run method |
| backend/donations/models/donors.py | Implemented anonymize() method and refactored encryption to use crypto_helper |
| backend/donations/admin/donors.py | Added anonymization admin actions and confirmation workflow |
| backend/donations/management/commands/generate_donations.py | Enhanced donation generation with PDF handling options |
| backend/locale/*/LC_MESSAGES/django.po | Added translations for anonymization messages |
| .idea/runConfigurations/*.xml | Updated IDE run configurations |
Files not reviewed (3)
- .idea/runConfigurations/compilemessages.xml: Language not supported
- .idea/runConfigurations/generate_donations_PDF_only.xml: Language not supported
- .idea/runConfigurations/makemessages.xml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| for donor in two_year_donations_qs: | ||
| anonymize_donor(donor) | ||
| for donor in one_year_donations_qs: | ||
| anonymize_donor(donor) |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The _anonymize_old_donations method processes donors synchronously in a loop, which could lead to performance issues when there are many old donations to anonymize. Consider using bulk operations or async tasks to process large numbers of donors more efficiently. You could batch the operations or use the anonymize_donations action which already has better control flow.
| for donor in two_year_donations_qs: | |
| anonymize_donor(donor) | |
| for donor in one_year_donations_qs: | |
| anonymize_donor(donor) | |
| for donor in two_year_donations_qs.iterator(chunk_size=1000): | |
| async_wrapper(anonymize_donor, donor) | |
| for donor in one_year_donations_qs.iterator(chunk_size=1000): | |
| async_wrapper(anonymize_donor, donor) |
| if form.is_valid(): | ||
| result: dict = self._anonymize_donation(donor) | ||
|
|
||
| self.message_user(request, result["message"], level=DEFAULT_LEVELS.get(result["status"], messages.INFO)) |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code uses DEFAULT_LEVELS.get() to map task result statuses to message levels, but DEFAULT_LEVELS is a dictionary that maps level names to integers (e.g., 'SUCCESS' -> 25, 'ERROR' -> 40), not the reverse. The task result flags like TASK_SUCCESS_FLAG are strings ("SUCCESS", "ERROR", etc.), which won't match the expected keys in DEFAULT_LEVELS. This will always fall back to messages.INFO, which may not be the intended behavior. Consider creating an explicit mapping like: {"SUCCESS": messages.SUCCESS, "ERROR": messages.ERROR, "SCHEDULED": messages.INFO}.
| def anonymize(self, commit: bool = True): | ||
| self.l_name = "" | ||
| self.f_name = "" | ||
| self.initial = "" | ||
| self.set_cnp("") | ||
|
|
||
| self._set_address({}) | ||
|
|
||
| self.phone = "" | ||
| self.email = "" | ||
|
|
||
| self.geoip = {} | ||
|
|
||
| self.pdf_file.delete(save=commit) | ||
| self.filename = "" | ||
|
|
||
| if commit: | ||
| self.save() |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new anonymize() method in the Donor model lacks test coverage. Given that this method performs critical data anonymization operations including clearing personal information and deleting files, it's important to add comprehensive tests to verify that all personal data is properly cleared and that the method handles edge cases correctly (e.g., when pdf_file is already empty).