Source code for accounts.forms

from crispy_forms.bootstrap import FormActions
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Div, Field, Fieldset, Layout, Row, Submit, Hidden
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.conf import settings
from django.db.models import Q
from django import forms

from data.forms import FieldAccessForm, FieldAccessLevel
from meetings.models import MeetingType
from .models import Officer, ProfilePhoto, carrier_choices, event_fields, UserPreferences
from .ldap import get_student_id


[docs]class LoginForm(AuthenticationForm): def __init__(self, *args, **kwargs): super(LoginForm, self).__init__(*args, **kwargs) self.helper = FormHelper() self.helper.add_input(Submit('submit', 'Log In', css_class="btn btn-lg btn-block btn-warning"))
[docs]class UserEditForm(FieldAccessForm): title = forms.ModelChoiceField(queryset=Officer.objects.filter(user__isnull=True), required=False) def __init__(self, *args, **kwargs): request_user = kwargs['request_user'] instance_user = kwargs['instance'] self.helper = FormHelper() self.helper.form_class = "form-horizontal" self.helper.label_class = 'col-lg-2' self.helper.field_class = 'col-lg-8' password = None if instance_user == request_user or request_user.is_superuser: password = HTML("""<div class="col-lg-offset-2 col-lg-8"> <a href="{% url 'accounts:password' object.pk %}">Set a password for non-SSO login</a></div>""") layout = [ Fieldset("User Info", 'first_name', 'last_name', 'username', 'email', 'nickname', 'pronouns', password), Fieldset("Contact Info", 'phone', 'carrier', Field('addr', rows=3)), ] if request_user.is_lnl: layout.extend([ Fieldset("Student Info", 'wpibox', 'class_year', 'student_id'), Fieldset("Internal Info", 'title', 'mdc', 'groups', 'away_exp'), ]) layout.append( FormActions( Submit('save', 'Update Member and Return'), ) ) self.helper.layout = Layout(*layout) super(UserEditForm, self).__init__(*args, **kwargs) if request_user.is_lnl and instance_user.is_lnl: self.fields['class_year'].required = True self.fields['title'].queryset = Officer.objects.filter(Q(user__isnull=True) | Q(user=instance_user)) self.fields['title'].initial = Officer.objects.filter(user=instance_user).first()
[docs] def clean_student_id(self): student_id = self.cleaned_data.get('student_id', None) if not student_id and self.instance.is_lnl and settings.SYNC_STUDENT_ID: uid = get_student_id(self.instance.username) if uid: return int(uid) return student_id
[docs] def save(self, commit=True): super(UserEditForm, self).save(commit) if 'title' in self.changed_data: officer_info = Officer.objects.filter(user=self.instance).first() if officer_info: officer_info.user = None officer_info.img = None officer_info.save() if self.cleaned_data['title']: officer_info = Officer.objects.get(pk=self.cleaned_data['title'].pk) officer_info.user = self.instance profile_photo = ProfilePhoto.objects.filter(officer=self.instance).first() officer_info.img = profile_photo officer_info.save() return self.instance
[docs] class Meta: model = get_user_model() fields = ['username', 'email', 'first_name', 'last_name', 'nickname', 'pronouns', 'groups', 'addr', 'wpibox', 'mdc', 'phone', 'class_year', 'student_id', 'away_exp', 'carrier', 'title']
[docs] class FieldAccess: def __init__(self): pass thisisme = FieldAccessLevel( lambda user, instance: (user == instance) and not user.locked, enable=('email', 'first_name', 'last_name', 'addr', 'wpibox', 'phone', 'class_year', 'nickname', 'carrier', 'pronouns') ) hasperm = FieldAccessLevel( lambda user, instance: (user != instance) and user.has_perm('accounts.change_user', instance), enable=('email', 'first_name', 'last_name', 'addr', 'wpibox', 'phone', 'class_year') ) edit_groups = FieldAccessLevel( lambda user, instance: user.has_perm('accounts.change_membership', instance), enable=('groups', 'away_exp', 'title') ) edit_mdc = FieldAccessLevel( lambda user, instance: user.has_perm('accounts.edit_mdc', instance), enable=('mdc',) ) edit_student_id = FieldAccessLevel( lambda user, instance: (user == instance) and (not instance.student_id or not settings.SYNC_STUDENT_ID), enable=('student_id',) ) unaffiliated = FieldAccessLevel( lambda user, instance: not user.is_lnl, exclude=('wpibox', 'class_year', 'student_id', 'mdc', 'groups',) )
[docs]class UserAddForm(UserCreationForm): error_messages = { 'password_mismatch': "The two password fields didn't match.", }
[docs] class Meta: model = get_user_model() fields = ['username', 'email', 'first_name', 'last_name']
def __init__(self, *args, **kwargs): self.base_fields['password1'].required = False self.base_fields['password2'].required = False self.helper = FormHelper() self.helper.form_method = 'post' self.helper.form_action = '' self.helper.form_class = "form-horizontal" self.helper.layout = Layout( HTML('<div class="alert alert-warning">\ This form should not be used under normal circumstances. \ When everything is working properly, an account will be created \ automatically when someone logs into the DB with Microsoft SSO for the first time \ or when crew hours or attendance are entered for the person. \ This form should only be used when the automatic \ account creation is broken (which has happened before).</div>'), Row(Div('first_name', css_class='col-md-6'), Div('last_name', css_class='col-md-6')), 'username', 'email', Row(Div('password1', css_class='col-md-6'), Div('password2', css_class='col-md-6')), FormActions( Submit('save', 'Save Changes'), ) ) super(UserAddForm, self).__init__(*args, **kwargs) # the rest is to make passwords optional.
[docs] def clean_password2(self): if self.cleaned_data['password1'] or self.cleaned_data['password2']: return super(UserAddForm, self).clean_password2() else: return ""
[docs] def save(self, commit=True): # we want to bypass UserCreationForm's save. user = forms.ModelForm.save(self, commit=False) # only set a pass if the form is filled if self.cleaned_data['password1']: user.set_password(self.cleaned_data["password1"]) if commit: user.save() return user
[docs]class UserPreferencesForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(UserPreferencesForm, self).__init__(*args, **kwargs) if self.instance.rt_token not in [None, '']: self.Meta.layout.pop(-2) self.Meta.layout.insert(-1, ( "Text", "<button class=\"ui red small button\" type=\"submit\" name=\"submit\" " "value=\"rt-delete\">Delete Token</button>" )) else: self.Meta.layout.pop(-2) self.Meta.layout.insert(-1, ( "Text", "<a href=\"/support/connect/rt/\" class=\"ui green small button\">Connect Account</a>" )) if 'Inactive' in self.instance.user.group_str or 'Unclassified' in self.instance.user.group_str: self.Meta.layout[8] = ("Text", "</div><div class=\"title\"><i class=\"dropdown icon\"></i>" "Crew Chief Needed Notifications</div><div class=\"content\">" "<p class=\"ui help\">Receive an alert whenever the VP needs crew chiefs " "to run an event. These messages may be sent to either " "<em>gr-lnl-needcc@wpi.edu</em> or <em>lnl-active@wpi.edu</em>. You may " "unsubscribe from these messages at any time through Outlook.</p>") self.Meta.layout[9] = ( "Text", "<a href=\"https://lnl.wpi.edu/legal/opt-out/\" class=\"ui blue basic button\">Opt out</a>" ) else: self.Meta.layout[8] = ("Text", "</div><div class=\"title\"><i class=\"dropdown icon\"></i>" "Crew Chief Needed Notifications</div><div class=\"content\">" "<p class=\"ui help\">Receive an alert whenever the VP needs crew chiefs " "to run an event.</p>") self.Meta.layout[9] = ("Field", "cc_needed_subscriptions") self.fields['cc_needed_subscriptions'].initial = ['email', 'slack'] event_fields_required = [ ('location', 'Location'), ('datetime_setup_complete', 'Datetime setup complete'), ('datetime_start', 'Datetime start'), ('datetime_end', 'Datetime end') ] event_fields_optional = [] for field in event_fields: if field not in event_fields_required: event_fields_optional.append(field) self.fields['event_edited_field_subscriptions'].choices = event_fields_optional self.fields['ignore_user_action'].widget.attrs['_style'] = 'toggle' self.fields['ignore_user_action'].widget.attrs['_help'] = True self.fields['meeting_invites'].widget.attrs['_style'] = 'toggle' self.fields['meeting_invites'].widget.attrs['_help'] = True cc_add_subscriptions = forms.MultipleChoiceField( choices=(('email', 'Email'), ('slack', 'Slack Notification')), required=False, widget=forms.CheckboxSelectMultiple(attrs={ '_no_required': True, 'style': 'margin: 0.5% 0.5% 0 0; cursor: pointer', '_no_label': True }) ) cc_report_reminders = forms.ChoiceField( choices=(('email', 'Email'), ('slack', 'Slack Notification'), ('all', 'Both')), widget=forms.RadioSelect(attrs={ '_no_required': True, 'style': 'margin: 0.5% 0.5% 0 0; cursor: pointer', '_no_label': True }) ) cc_needed_subscriptions = forms.MultipleChoiceField( choices=(('email', 'Email'), ('slack', 'Slack Notification')), required=False, widget=forms.CheckboxSelectMultiple( attrs={'_no_required': True, 'style': 'margin: 0.5% 0.5% 0 0; cursor: pointer', '_no_label': True, 'disabled': True} ) ) event_edited_notification_methods = forms.ChoiceField( choices=(('email', 'Email'), ('slack', 'Slack Notification'), ('all', 'Both')), widget=forms.RadioSelect(attrs={ '_no_required': True, 'style': 'margin: 0.5% 0.5% 0 0; cursor: pointer', '_no_label': True }) ) event_edited_field_subscriptions = forms.MultipleChoiceField( choices=event_fields, required=False, widget=forms.SelectMultiple(attrs={'_no_required': True, '_no_label': True, 'placeholder': 'Add more'}) ) meeting_invites = forms.BooleanField( label="Receive calendar invites for meetings", required=False, help_text="Opt-in to receiving calendar invites for meetings (separate from meeting notices)" ) meeting_invite_subscriptions = forms.ModelMultipleChoiceField( queryset=MeetingType.objects.all(), required=False, widget=forms.SelectMultiple(attrs={'_no_required': True, '_no_label': True}) ) ignore_user_action = forms.BooleanField(label="Ignore my actions", required=False, help_text="Avoid sending me notifications for actions that I initiate") srv = forms.MultipleChoiceField( choices=(('email', 'Email'), ('slack', 'Slack Notification'), ('sms', 'SMS (Text Message)')), initial=['email', 'slack', 'sms'], required=False, widget=forms.CheckboxSelectMultiple( attrs={'_no_required': True, 'style': 'margin: 0.5% 0.5% 0 0', '_no_label': True, 'disabled': True} ) )
[docs] class Meta: model = UserPreferences fields = ('theme', 'cc_add_subscriptions', 'cc_report_reminders', 'event_edited_notification_methods', 'event_edited_field_subscriptions', 'ignore_user_action', 'meeting_invites', 'meeting_invite_subscriptions') layout = [ ("Text", "<div class=\"ui secondary segment\"><h4 class=\"ui dividing header\">Appearance</h4>"), ("Field", "theme"), ("Text", "</div><div class=\"ui secondary segment nobullet\"><h4 class=\"ui dividing header\">" "Communications</h4><div class=\"ui styled accordion\" style=\"width: 100%\"><div class=\"title\">" "<i class=\"dropdown icon\"></i>LNL News</div><div class=\"content\"><p class=\"ui help\">" "General club information, advertisements and meeting notices. This content will typically be " "sent to the <em>lnl-news@wpi.edu</em> email alias. You may opt out of receiving these messages " "at any time through Outlook.</p>"), ("Text", "<a href=\"https://lnl.wpi.edu/legal/opt-out/\" class=\"ui blue basic button\">Opt out</a>"), ("Text", "</div><div class=\"title\"><i class=\"dropdown icon\"></i>Crew Chief Add Notifications</div>" "<div class=\"content\"><p class=\"ui help\">Receive a notification whenever you are added as a " "Crew Chief for a new event.</p>"), ("Field", "cc_add_subscriptions"), ("Text", "</div><div class=\"title\"><i class=\"dropdown icon\"></i>Crew Chief Report Reminders</div>" "<div class=\"content\"><p class=\"ui help\">Receive reminders for missing crew chief reports.</p>"), ("Field", "cc_report_reminders"), ("Text", "</div><div class=\"title\"><i class=\"dropdown icon\"></i>Crew Chief Needed Notifications</div>" "<div class=\"content\"><p class=\"ui help\">Receive an alert whenever the VP needs crew chiefs " "to run an event.</p>"), ("Field", "cc_needed_subscriptions"), ("Text", "</div><div class=\"title\"><i class=\"dropdown icon\"></i>Event Edit Notifications</div>" "<div class=\"content\"><p class=\"ui help\">Receive alerts whenever details for an event you are " "involved with have changed.</p>"), ("Field", "event_edited_notification_methods"), ("Text", "<br><hr style='border: 1px dashed gray'><br>" "<p class\"ui help\">Notify me of changes to any of the following fields:<br><br>" "<span class=\"ui label\">Location</span><span class=\"ui label\">Event Setup Time</span>" "<span class=\"ui label\">Event Start</span><span class=\"ui label\">Event End</span></p>"), ("Field", "event_edited_field_subscriptions"), ("Text", "</div><div class=\"title\"><i class=\"dropdown icon\"></i>Web Service Notifications</div>" "<div class=\"content\"><p class=\"ui help\">General account and system-wide notices. You may not " "unsubscribe from these messages.</p>"), ("Field", "srv"), ("Text", "</div></div><br><div class=\"ui styled accordion\" style=\"width: 100%\">" "<div class=\"title\"><i class=\"dropdown icon\"></i>Calendar Invites - Meetings</div>" "<div class=\"content\">"), ("Field", "meeting_invites"), ("Text", "<br><hr style='border: 1px dashed gray'>" "<p class\"ui help\">Automatically send me invites for the following types of meetings:<br>"), ("Field", "meeting_invite_subscriptions"), ("Text", "</div></div><div class=\"ui segment\">"), ("Field", "ignore_user_action"), ("Text", "</div></div><div class=\"ui secondary segment\">" "<h4 class=\"ui dividing header\">Request Tracker</h4>"), ("Text", "<a href=\"/support/connect/rt/\" class=\"ui green basic button\">Connect Account</a>"), ("Text", "</div>") ]
[docs]class OfficerPhotoForm(forms.ModelForm): def __init__(self, *args, **kwargs): self.helper = FormHelper() self.helper.form_class = "form-horizontal" self.helper.label_class = "col-lg-2" self.helper.field_class = "col-lg-8" self.helper.layout = Layout( Fieldset('Officer Photo - {{ officer.get_full_name }}', 'img'), FormActions( Submit('save', 'Save Changes'), HTML('<input type="submit" name="save" value="Remove" class="btn btn-danger"></input>')) ) super(OfficerPhotoForm, self).__init__(*args, **kwargs)
[docs] class Meta: model = ProfilePhoto fields = ['img']
[docs]class SMSOptInForm(forms.ModelForm): phone = forms.CharField(required=True, min_length=10, max_length=10) carrier = forms.ChoiceField(choices=carrier_choices[1:], required=True) def __init__(self, *args, **kwargs): exists = kwargs.pop('exists') request = kwargs.pop('request') self.helper = FormHelper() if not exists: self.helper.layout = Layout( Field('phone'), Field('carrier'), FormActions( Submit('save', 'Continue') ) ) else: self.helper.layout = Layout( Hidden('phone', value=request.user.phone), Hidden('carrier', value=request.user.carrier), FormActions( HTML('<a class="btn btn-secondary mr-2" ' 'href="{% url \'accounts:detail\' request.user.pk %}">Edit</a>'), Submit('save', 'Continue') ) ) super(SMSOptInForm, self).__init__(*args, **kwargs)
[docs] class Meta: model = get_user_model() fields = ('phone', 'carrier')