-
Notifications
You must be signed in to change notification settings - Fork 153
Fix: Handle Users with None Email in Admin Interface #1240
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: enext
Are you sure you want to change the base?
Conversation
Reviewer's guide (collapsed on small PRs)Reviewer's GuideThis PR updates the admin user edit form to properly detect and handle None email values by converting them to empty strings, making the field optional when appropriate, and refining validation; it also standardizes template displays to show an em dash placeholder for missing emails and full names. Class diagram for updated UserEditForm email handlingclassDiagram
class UserEditForm {
__init__(*args, **kwargs)
clean_email()
fields
initial
}
UserEditForm : __init__ detects None email and sets initial['email'] = ''
UserEditForm : email field required only if email exists
UserEditForm : clean_email() converts empty string to None
UserEditForm : clean_email() checks for duplicates only if email is provided
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
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.
Hey there - I've reviewed your changes and they look great!
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `app/eventyay/control/forms/users.py:79-81` </location>
<code_context>
def clean_email(self):
- email = self.cleaned_data['email']
+ email = self.cleaned_data.get('email', '').strip()
+ # Convert empty string to None for users without email
+ if not email:
+ return None
+ # Check for duplicate emails only if email is provided
</code_context>
<issue_to_address>
**suggestion:** Stripping whitespace from email may cause issues for legitimate emails with leading/trailing spaces.
Consider validating and rejecting emails with leading or trailing spaces, rather than silently removing them, to avoid masking user input errors.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| email = self.cleaned_data.get('email', '').strip() | ||
| # Convert empty string to None for users without email | ||
| if not email: |
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.
suggestion: Stripping whitespace from email may cause issues for legitimate emails with leading/trailing spaces.
Consider validating and rejecting emails with leading or trailing spaces, rather than silently removing them, to avoid masking user input errors.
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.
This seems reasonable. Please also show an error message for invalid emails.
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.
Thanks for your feedback!
To show an error message for invalid emails, you can enhance the clean_email method in your form to use Django's built-in email validation. This way, if a user enters an email with leading/trailing spaces or an invalid format, the form will display a clear error message.
Here's how you can update your clean_email method:
from django.core.validators import validate_email
from django.core.exceptions import ValidationError
def clean_email(self):
email = self.cleaned_data.get('email', '')
if email:
# Check for leading/trailing spaces
if email != email.strip():
raise forms.ValidationError(_('Email address must not have leading or trailing spaces.'), code='invalid')
try:
validate_email(email)
except ValidationError:
raise forms.ValidationError(_('Enter a valid email address.'), code='invalid')
else:
return None
# Check for duplicate emails only if email is provided
if User.objects.filter(Q(email__iexact=email) & ~Q(pk=self.instance.pk)).exists():
raise forms.ValidationError(
self.error_messages['duplicate_identifier'],
code='duplicate_identifier',
)
return emailThis will:
- Reject emails with leading/trailing spaces and show a specific error
- Use Django's email validator for format checking
- Continue to check for duplicates as before
Let me know if you need a full patch or further help integrating this!
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 PR fixes issues with displaying and editing users who have None as their email address in the Django admin interface. The fix prevents the literal string "None" from appearing and ensures proper form validation for users without email addresses.
Key Changes:
- Enhanced form logic to detect and handle
Noneemail values by converting them to empty strings in the form display - Made email field optional for existing users without email addresses while keeping it required for new users
- Updated templates to display "—" (em dash) placeholder instead of "None" or empty strings
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| app/eventyay/control/forms/users.py | Added logic in __init__ to handle None emails and updated clean_email() to convert empty strings back to None while safely checking for duplicates |
| app/eventyay/control/templates/pretixcontrol/admin/users/form.html | Added default:"—" filter to user email display in the page header |
| app/eventyay/control/templates/pretixcontrol/admin/users/index.html | Added default:"—" filters to both email and fullname columns for consistent placeholder display |
Comments suppressed due to low confidence (1)
app/eventyay/control/forms/users.py:89
- The new logic for handling users with
Noneemail addresses lacks test coverage. Consider adding tests for the following scenarios:
- Editing an existing user with
email = None(native auth) - should show empty field and allow saving without email - Editing an existing user with
email = None(non-native auth) - should show disabled empty field - Converting an email to
Noneby clearing the field for a user without email - Attempting to save duplicate emails when one user has
Noneemail
This would help ensure the fix works correctly and prevents regressions.
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Handle None email values - show empty field instead of "None" text
if self.instance and self.instance.pk and self.instance.email is None:
self.initial['email'] = ''
# Make email not required for existing users without email
self.fields['email'].required = False
else:
self.fields['email'].required = True
self.fields['last_login'].disabled = True
if self.instance and self.instance.auth_backend != 'native':
del self.fields['new_pw']
del self.fields['new_pw_repeat']
self.fields['email'].disabled = True
def clean_email(self):
email = self.cleaned_data.get('email', '').strip()
# Convert empty string to None for users without email
if not email:
return None
# Check for duplicate emails only if email is provided
if User.objects.filter(Q(email__iexact=email) & ~Q(pk=self.instance.pk)).exists():
raise forms.ValidationError(
self.error_messages['duplicate_identifier'],
code='duplicate_identifier',
)
return email
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…fossasia#1157) * Fix navigation button border radius inconsistency - Added border-radius: 0 to .header-nav class in orga/_layout.css - Makes Talk component navigation buttons match Tickets component style - Ensures consistent sharp corners across all navigation buttons - Maintains visual consistency throughout the platform Fixes fossasia#1156 * Add inset shadow on hover to match Tickets component - Added hover and active states with inset box-shadow - Matches the hover effect from btn-success in Tickets component - Uses rgba(0, 128, 0, 0.25) for green inset shadow * Fix navigation button active state to match Tickets component - Added .header-nav.active state with proper inset shadow - Fixed depth and consistency of hover, active, and current page states - Current page button now has same darker border effect as Tickets - All navigation buttons now have identical visual feedback * Improve CSS: use variables and remove important declarations * Fix CSS indentation formatting * Update app/eventyay/static/orga/css/_layout.css * Update app/eventyay/static/orga/css/_layout.css * Fix navigation buttons: sharp corners and inset shadow to match Tickets component --------- Co-authored-by: Mario Behling <[email protected]>
* talk: remove ticket/video URL fields * talk: normalize ticket base URL * Update app/eventyay/agenda/views/talk.py --------- Co-authored-by: Mario Behling <[email protected]>
* fix unable to save config * Update app/eventyay/webapp/src/views/admin/config/main.vue --------- Co-authored-by: Mario Behling <[email protected]>
…eferences with 'eventyay' in activity log system (fossasia#1310) * Replace legacy 'pretalx' references with 'eventyay' in activity logs fossasia#1305 * Replace all 'pretix/pretalx' references with 'eventyay' in activity log system - Updated log_prefix in 9 talk models (Room, Tag, Track, Submission, etc.) - Replaced 47+ hardcoded pretix.* log_action calls with eventyay.* across views - Fixed critical bug: Added logdisplay module import to ControlConfig.ready() - Added comprehensive PRETIX_LEGACY_ALIASES for backward compatibility - Added room action display strings for talk system logs * Fix signal handler bugs * Address Copilot review * added some missing * Update app/eventyay/control/logdisplay.py * Update app/eventyay/base/models/information.py * Update app/eventyay/control/logdisplay.py * Fix duplicate dictionary keys in plains dict * Update app/eventyay/control/logdisplay.py * Add 6 final missing legacy aliases --------- Co-authored-by: Mario Behling <[email protected]>
…as well as views and exporter error fix (fossasia#1177) * email tz fix * ensure browser timezone in views for all pages and export page error fix * applied suggestions * implemented suggestions * removed pytz dependency * Update app/eventyay/base/exporters/json.py Co-authored-by: Copilot <[email protected]> * Update app/eventyay/plugins/reports/exporters.py Co-authored-by: Copilot <[email protected]> * Update app/eventyay/control/forms/filter.py Co-authored-by: Copilot <[email protected]> * added suggestions * Update app/eventyay/static/common/js/timezone.js Co-authored-by: Copilot <[email protected]> * added other suggestions --------- Co-authored-by: Mario Behling <[email protected]> Co-authored-by: Copilot <[email protected]>
…ssasia#1323) Updates the requirements on [reportlab](https://www.reportlab.com/) to permit the latest version. --- updated-dependencies: - dependency-name: reportlab dependency-version: 4.4.5 dependency-type: direct:production ... Signed-off-by: Mario Behling <[email protected]>
* remove duplicate settings * remove duplicate settings --------- Co-authored-by: Srivatsav Auswin <[email protected]> Co-authored-by: Mario Behling <[email protected]>
…sasia#1327) Updates the requirements on [stripe](https://github.com/stripe/stripe-python) to permit the latest version. - [Release notes](https://github.com/stripe/stripe-python/releases) - [Changelog](https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md) - [Commits](stripe/stripe-python@v13.2.0a1...v14.0.0) --- updated-dependencies: - dependency-name: stripe dependency-version: 14.0.0 dependency-type: direct:production ... Signed-off-by: Mario Behling <[email protected]>
…ossasia#1328) Updates the requirements on [sentry-sdk](https://github.com/getsentry/sentry-python) to permit the latest version. - [Release notes](https://github.com/getsentry/sentry-python/releases) - [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md) - [Commits](getsentry/sentry-python@2.44.0...2.45.0) --- updated-dependencies: - dependency-name: sentry-sdk dependency-version: 2.45.0 dependency-type: direct:production ... Signed-off-by: Mario Behling <[email protected]>
* fix: standardize sidebar icon sizes to prevent layout shift on expand/collapse - Set consistent icon size (14px/1.28571429em) across all sidebar states - Fixed row height to 41px for both collapsed and expanded states - Used flexbox alignment to maintain icon position - Prevent icon size changes between minimized, hover, and mobile states - Removed font-size inherit which caused icon scaling issues fossasia#1215 * WIP: sidebar icon text hiding - template changes not rendering - Added sidebar-text span wrappers to navigation labels in both templates - Updated CSS to hide .sidebar-text when sidebar is minimized - CSS compiles correctly but template changes not reflecting in browser - Issue: Django template caching preventing changes from appearing Status: Work in progress - debugging template rendering issue * fix: prevent sidebar icon layout shift on expand/collapse - Standardize icon sizes to 14px in both collapsed and expanded states - Wrap menu labels in .sidebar-text spans for proper visibility control - Use display:none for text hiding instead of font-size manipulation - Maintain consistent padding and alignment in all sidebar states - Match stable behavior from Talk component sidebar * fix: hide TEST MODE text when sidebar is minimized Wrap TEST MODE label in sidebar-text span to ensure it hides properly when sidebar is collapsed, maintaining consistent behavior with other menu items. * fix: simplify sidebar hover behavior to match Talk component - Remove complex flex layouts, transitions, and positioning - Use simple display:none/inline pattern like Talk component - Remove fixed heights and line-heights causing layout shifts - Keep consistent 10px 15px padding in all states - Icon sizes remain stable at 14px - Clean hover expansion without visual glitches * just text adjustment now * done * when fully expanded also using 3 lines show same now * Fix sidebar 3 line expansion same width * Revert information.py and logdisplay.py to match enext branch - only keep sidebar CSS/HTML fixes * added last line
* Fix: socialauth URLs were not resolved * Custom path converter for URLs --------- Co-authored-by: Mario Behling <[email protected]>
* added translations * implemented suggestions --------- Co-authored-by: Mario Behling <[email protected]>
* added unscheduled rooms * implemented suggestions * added suggestions by copilot * fix(migrations): add missing migrations into base/0002 --------- Co-authored-by: Sak1012 <[email protected]>
…1333) Updates the requirements on [geoip2](https://github.com/maxmind/GeoIP2-python) to permit the latest version. - [Release notes](https://github.com/maxmind/GeoIP2-python/releases) - [Changelog](https://github.com/maxmind/GeoIP2-python/blob/main/HISTORY.rst) - [Commits](maxmind/GeoIP2-python@v4.0.0...v5.2.0) --- updated-dependencies: - dependency-name: geoip2 dependency-version: 5.2.0 dependency-type: direct:production ... Signed-off-by: Mario Behling <[email protected]>
…ia#1329) Updates the requirements on [redis](https://github.com/redis/redis-py) to permit the latest version. - [Release notes](https://github.com/redis/redis-py/releases) - [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES) - [Commits](redis/redis-py@v7.0.0b1...v7.1.0) --- updated-dependencies: - dependency-name: redis dependency-version: 7.1.0 dependency-type: direct:production ... Signed-off-by: Mario Behling <[email protected]>
* Fix HTTP 500 error handling during room deletion * fix on basis of sourcery review * Address reviewd exception handling --------- Co-authored-by: Srivatsav Auswin <[email protected]> Co-authored-by: Mario Behling <[email protected]>
* Fix fossasia#1252: HTTP 500 error when using gift cards in checkout - Changed from .get() to .filter(secret__iexact=...).first() - Added explicit null check: if not gc: raise GiftCard.DoesNotExist() - Case-insensitive matching now works (YSV9AYRKW7HP == ysv9ayrkw7hp) - More robust querying on annotated querysets - Consistent with voucher code handling - GiftCardPayment.checkout_prepare (line ~1257) - GiftCardPayment.payment_prepare (line ~1338) -Backward compatible * refactor: Sourcery suggestions Instead of raising GiftCard.DoesNotExist and catching it in except block, handle the not-found case inline with immediate user feedback. This: - Provides more direct error handling flow - Reduces exception overhead - Improves code readability - Maintains the voucher vs gift card check logic Changes: - Handle gc=None case inline with messages.error/warning - Remove now-redundant GiftCard.DoesNotExist except blocks - Keep GiftCard.MultipleObjectsReturned handling - Preserve voucher detection logic * Fix gift card payment: case-sensitive lookup and proper error handling * Remove generic Exception handlers --------- Co-authored-by: Mario Behling <[email protected]>
* Fix CSV Export Returns 500 Error * refactor minor fixes * fix logging usage --------- Co-authored-by: Mario Behling <[email protected]>
* Export orders with Wikimedia username * Avoid logic of finding column index to insert --------- Co-authored-by: Mario Behling <[email protected]>
* image rescaling fix * implemented copilot suggestions --------- Co-authored-by: Mario Behling <[email protected]>
…s components (fossasia#1259) * fix(ui): match top menu bar between Eventyay Talk and Tickets components * update font weight --------- Co-authored-by: Mario Behling <[email protected]>
Fixes #1212
Problem (Root Cause)
When users exist in the system with
Noneas their email address (which can happen with certain authentication backends or data migrations), the admin interface displayed several issues:This created a poor user experience and could lead to confusion when managing users in the admin panel.
Solution
This PR implements a comprehensive fix across both the form logic and template rendering:
1. Form Handling (
app/eventyay/control/forms/users.py)UserEditForm.__init__()to detect when an existing user hasNoneemailNoneemail values to empty strings in the form initial data, so the form shows an empty field instead of "None"clean_email()to:None.get()with default to safely handle missing email values2. Template Display (
app/eventyay/control/templates/pretixcontrol/admin/users/)default:"—"instead ofdefault_if_none:""for consistent placeholder displayChanges Made
app/eventyay/control/forms/users.py: Enhanced form initialization and email validationapp/eventyay/control/templates/pretixcontrol/admin/users/form.html: Added default filter for email displayapp/eventyay/control/templates/pretixcontrol/admin/users/index.html: Added default filters for email and fullname displayTesting
Noneemail now display "—" in the admin interfaceRelated Issue
Before:

After:

Summary by Sourcery
Improve the Django admin user interface and form logic to properly handle users with null email addresses by displaying placeholders and adjusting form requirements and validation
Bug Fixes:
Enhancements: