Skip to content

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 theme key
  • 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_save on User (creation only)
  • Action: Auto-creates Profile for new users with last_seen_version set to the current application version

save_profile

  • Trigger: post_save on 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, or all
  • 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