diff --git a/bugsink/urls.py b/bugsink/urls.py index 86da762..100acd2 100644 --- a/bugsink/urls.py +++ b/bugsink/urls.py @@ -8,7 +8,7 @@ from alerts.views import debug_email as debug_alerts_email from users.views import debug_email as debug_users_email from teams.views import debug_email as debug_teams_email from bugsink.app_settings import get_settings -from users.views import signup, confirm_email, resend_confirmation, request_reset_password, reset_password +from users.views import signup, confirm_email, resend_confirmation, request_reset_password, reset_password, preferences from .views import home, trigger_error, favicon, settings_view @@ -31,6 +31,8 @@ urlpatterns = [ path("accounts/login/", auth_views.LoginView.as_view(template_name="bugsink/login.html"), name="login"), path("accounts/logout/", auth_views.LogoutView.as_view(template_name="users/logged_out.html"), name="logout"), + path("accounts/preferences/", preferences, name="preferences"), + path('api/', include('ingest.urls')), path('projects/', include('projects.urls')), diff --git a/theme/templates/base.html b/theme/templates/base.html index 814bd05..1acc3ef 100644 --- a/theme/templates/base.html +++ b/theme/templates/base.html @@ -34,7 +34,7 @@ {% if logged_in_user.is_anonymous %}
Login
{# I don't think this is actually ever shown in practice, because you must always be logged in #} {% else %} -
Profile
+
Preferences
{% csrf_token %}
{% endif %} diff --git a/users/forms.py b/users/forms.py index ee6442d..090d837 100644 --- a/users/forms.py +++ b/users/forms.py @@ -11,6 +11,12 @@ from django.forms import ModelForm from django.utils.html import escape, mark_safe +TRUE_FALSE_CHOICES = ( + (True, 'Yes'), + (False, 'No') +) + + def _(x): # dummy gettext return x @@ -101,3 +107,13 @@ class SetPasswordForm(BaseSetPasswordForm): self.fields['new_password1'].help_text = "At least 8 characters" self.fields['new_password2'].help_text = None # "Confirm password" is descriptive enough + + +class PreferencesForm(ModelForm): + # I haven't gotten a decent display for checkboxes in forms yet; the quickest hack around this is a ChoiceField + send_email_alerts = forms.ChoiceField( + label=_("Send email alerts"), choices=TRUE_FALSE_CHOICES, required=False, widget=forms.Select()) + + class Meta: + model = UserModel + fields = ("send_email_alerts",) diff --git a/users/templates/users/preferences.html b/users/templates/users/preferences.html new file mode 100644 index 0000000..25374ba --- /dev/null +++ b/users/templates/users/preferences.html @@ -0,0 +1,37 @@ +{% extends "base.html" %} +{% load static %} +{% load tailwind_forms %} + +{% block title %}User Preferences ยท {{ site_title }}{% endblock %} + +{% block content %} + + +
+ +
+
+ {% csrf_token %} + + {% if messages %} +
    + {% for message in messages %} + {# if we introduce different levels we can use{% message.level == DEFAULT_MESSAGE_LEVELS.SUCCESS %} #} +
  • {{ message }}
  • + {% endfor %} +
+ {% endif %} + +
+

User Preferences

+
+ + {% tailwind_formfield form.send_email_alerts %} + + +
+ +
+
+ +{% endblock %} diff --git a/users/views.py b/users/views.py index ed0dd6b..cbbd1f3 100644 --- a/users/views.py +++ b/users/views.py @@ -5,10 +5,13 @@ from django.shortcuts import render, redirect, reverse from django.contrib.auth import get_user_model from django.http import Http404 from django.utils import timezone +from django.contrib import messages +from django.contrib.auth.decorators import login_required from bugsink.app_settings import get_settings, CB_ANYBODY +from bugsink.decorators import atomic_for_request_method -from .forms import UserCreationForm, ResendConfirmationForm, RequestPasswordResetForm, SetPasswordForm +from .forms import UserCreationForm, ResendConfirmationForm, RequestPasswordResetForm, SetPasswordForm, PreferencesForm from .models import EmailVerification from .tasks import send_confirm_email, send_reset_email @@ -150,6 +153,28 @@ def reset_password(request, token=None): return render(request, "users/reset_password.html", {"form": form, "next": next}) +@atomic_for_request_method +# in the general case this is done by Middleware but we're under /accounts/. not security-critical because we simply +# get a failure on request.user if this wasn't there, but still the "right thing" +@login_required +def preferences(request): + user = request.user + if request.method == 'POST': + form = PreferencesForm(request.POST, instance=user) + + if form.is_valid(): + form.save() + messages.success(request, "Updated preferences") + return redirect('preferences') + + else: + form = PreferencesForm(instance=user) + + return render(request, 'users/preferences.html', { + 'form': form, + }) + + DEBUG_CONTEXTS = { "confirm_email": { "site_title": get_settings().SITE_TITLE,