Users App Reference¶
The Users app extends Django's built-in authentication with user profiles, language preferences, theme selection, MFA enforcement, changelog tracking, and profile image management. Authentication is handled by django-allauth.
Overview¶
Location: app/users/
Purpose: User profiles, language/theme preferences, MFA enforcement, changelog notifications
Key Model: Profile
Dependencies: django-allauth, django-invitations, Pillow
File Structure¶
users/
├── models.py # Profile model
├── views.py # Profile, language, theme, and changelog views
├── forms.py # UserUpdateForm, ProfileUpdateForm
├── signals.py # Auto-create/save profile
├── changelog_signals.py # Changelog notification on login
├── services.py # Changelog version tracking service
├── utils.py # Registration config utility
├── adapters.py # Custom allauth, MFA, and invitation adapters
├── middleware.py # MFA enforcement middleware
├── admin.py # Django admin config
├── apps.py # AppConfig (registers signals)
└── templates/users/ # Profile templates
Models¶
Profile¶
Location: app/users/models.py:8
Extends Django's User model with additional preferences.
Fields:
| Field | Type | Description |
|---|---|---|
user |
OneToOneField(User) | CASCADE |
image |
ImageField | Profile picture, auto-resized to 300x300 |
language |
CharField(7) | Preferred language: en or de |
theme_preference |
CharField(10) | UI theme: light, dark, or system |
last_seen_version |
CharField(20) | Last changelog version seen by user |
default_report_date_range |
CharField(20) | Default date range for reports: current_year or last_365_days |
Save Hook: Automatically resizes images to 300x300 pixels using Pillow.
Views¶
profile(request)¶
Display and update user profile.
- Location:
app/users/views.py:25 - Authentication: Required
- Template:
users/profile.html - Forms:
UserUpdateForm,ProfileUpdateForm
Activates the user's language preference when the profile is saved. Handles both user info and profile updates in a single view.
set_language_and_save(request)¶
POST-only view to change the UI language.
- Location:
app/users/views.py:59 - Sets Django language cookie
- Saves preference to user profile (if authenticated)
- Returns redirect to previous page
set_theme(request)¶
POST-only AJAX endpoint for theme switching.
- Location:
app/users/views.py:97 - Accepts JSON body with
themekey - Validates theme against allowed values (light, dark, system)
- Saves preference to user profile (if authenticated)
- Returns JSON response with success status
dismiss_changelog(request)¶
POST-only AJAX endpoint to dismiss changelog notification.
- Location:
app/users/views.py:134 - Authentication: Required
- Marks the current version's changelog as seen for the logged-in user
- Returns JSON response
Forms¶
UserUpdateForm¶
- Fields:
username,email
ProfileUpdateForm¶
- Fields:
image,language,theme_preference,default_report_date_range
Signals¶
Location: app/users/signals.py
create_profile¶
- Trigger:
post_saveon User (creation only) - Action: Auto-creates Profile for new users with
last_seen_versionset to the current application version
save_profile¶
- Trigger:
post_saveon User - Action: Auto-saves Profile when User is saved
Location: app/users/changelog_signals.py
handle_changelog_on_login¶
- Trigger:
user_logged_in - Action: Creates a system notification when the application version has changed since the user last logged in
- Error-safe: exceptions are caught and logged, never blocking the login flow
Services¶
Location: app/users/services.py
Changelog Version Tracking¶
| Function | Purpose |
|---|---|
should_show_changelog(user) |
Check if user has not yet seen the current version's changelog |
mark_changelog_seen(user) |
Update user's profile to record that they saw the current version |
create_changelog_notification(user) |
Create a system notification about the new version with a link to the changelog |
Adapters (django-allauth)¶
Location: app/users/adapters.py
CustomAccountAdapter¶
| Method | Purpose |
|---|---|
is_open_for_signup() |
Controls self-registration via bifolk.json config; always allows invitation flow |
save_user() |
Auto-detects and saves browser language on registration |
get_login_redirect_url() |
Redirects to home after login |
get_signup_redirect_url() |
Redirects to home after signup |
CustomInvitationsAdapter¶
Custom invitation support for organization invitations. Integrates the invitation system with django-allauth.
CustomMFAAdapter¶
| Method | Purpose |
|---|---|
get_totp_issuer() |
Returns the TOTP issuer name shown in authenticator apps |
is_mfa_enabled() |
Check if user has any active MFA authenticators |
can_delete_authenticator() |
Prevents deletion of last authenticator when MFA is required by global or organization policy |
Middleware¶
Location: app/users/middleware.py
MFAEnforcementMiddleware¶
Enforces MFA requirements based on global settings and organization-level policies.
- Global MFA settings (
MFA_REQUIRED):none(default),staff, orall - Organization policy: Organizations can require MFA for their members
- Grace period: Users get a configurable number of days to set up MFA after account creation (default: 7 days)
- Exempt paths: MFA setup pages, logout, static/media files, admin panel, API endpoints
- OIDC bypass: Users authenticated via OIDC/social providers are exempt (their identity provider handles MFA)
Utilities¶
get_allow_self_registration()¶
Location: app/users/utils.py:10
Reads ALLOW_SELF_REGISTRATION from bifolk.json config file. Returns boolean (default: True).
URL Configuration¶
Authentication is handled by django-allauth. The Users app has no custom urls.py.
Profile, language, theme, and changelog views are registered in the main URL configuration (bifolk/urls.py):
| URL | View | Name |
|---|---|---|
/set-language/ |
set_language_and_save |
set_language |
/profile/ |
profile |
profile |
/set-theme/ |
set_theme |
set_theme |
/changelog/dismiss/ |
dismiss_changelog |
dismiss_changelog |
See Also¶
- Profile User Guide
- Translation & i18n
- Database Models - Profile
- Organizations App - Manages user memberships