def edit_visibility(request, public=True): """Render and process a form for the currently authenticated user to modify his visibility settings. Optional parameters: - public => whether to edit the user's public or chapter visibility settings (as a boolean): defaults to public """ viz = request.user.get_profile().public_visibility if public else request.user.get_profile().chapter_visibility if request.method == 'POST': if public: form = PublicVisibilityForm(request.POST, instance=viz) else: form = ChapterVisibilityForm(request.POST, instance=viz) if form.is_valid(): form.save() return HttpResponseRedirect(reverse('visibility')) else: if public: form = PublicVisibilityForm(instance=viz) else: form = ChapterVisibilityForm(instance=viz) fields = _get_fields_from_profile(request.user.get_profile()) vis_type = 'public' if public else 'chapter' message = get_message('visibility.edit.public') if public else get_message('visibility.edit.chapter') full_name_msg = get_message('visibility.fullname') return render(request, 'brothers/edit_visibility.html', {'form': form, 'fields': fields, 'type': vis_type, 'message': message, 'name_msg': full_name_msg}, context_instance=RequestContext(request))
def add_group(request): """Render and process a form to create a new user group.""" log_page_view(request, 'Add User Group') error = None initial_name = '' # empty string, not None (otherwise 'None' will appear in the form input) if request.method == 'POST': ids = [] group_name = None for name, value in request.POST.items(): if name.find('perm_') > -1: ids.append(int(value)) elif name == 'group_name': # validate group names for format and uniqueness initial_name = value if match(r'^[a-zA-Z0-9_]+[a-zA-Z0-9_ ]*[a-zA-Z0-9]+$', value) is None: error = get_message('group.name.invalid') elif Group.objects.filter(name=value).count() > 0: error = get_message('group.name.exists') else: group_name = value if error is None: if group_name is None: error = get_message('group.name.nonempty') elif not len(ids): error = get_message('group.perms.nonempty') else: group = Group.objects.create(name=group_name) group.permissions = Permission.objects.filter(id__in=ids) group.save() log.info('%s (%s) created user group \'%s\'', request.user.username, request.user.get_full_name(), group_name) return HttpResponseRedirect(reverse('view_group', kwargs={'name': group.name})) perms = _get_available_permissions() choices = [[perm.id, perm.name] for perm in perms] return render(request, 'brothers/add_group.html', {'error': error, 'name': initial_name, 'perms': choices}, context_instance=RequestContext(request))
def change_password(request): """Render and process a form for the currently authenticated user to change his password.""" log_page_view(request, 'Change Password') user = request.user profile = user.get_profile() reset = profile.has_bit(STATUS_BITS['PASSWORD_RESET']) if request.method == 'POST': form = ChangePasswordForm(request.POST) form.user = user if form.is_valid(): user.set_password(form.cleaned_data['password']) user.save() if reset: profile.clear_bit(STATUS_BITS['PASSWORD_RESET']) profile.save() else: send_mail(get_message('email.new_password.subject'), get_message('email.new_password.body', args=(user.first_name,)), settings.EMAIL_HOST_USER, [user.email]) log.info('User %s (%s) changed his password', user.username, user.get_full_name()) return HttpResponseRedirect(reverse('change_password_success')) else: form = ChangePasswordForm() form.user = user return render(request, 'brothers/change_password.html', {'form': form, 'message': (get_message('profile.password.reset') if reset else None)}, context_instance=RequestContext(request))
def _send_contact_emails(contact): """Send an email to a visitor who submitted a contact form; email brothers who want to be notified. Required parameters: - contact => the contact record for which to email """ date = contact.created.strftime('%B %d, %Y at %I:%M %p') # message to the person who submitted the information card message = EmailMessage(get_message('email.contact.subject'), get_message('email.contact.body', args=(contact.name, date, contact.to_string())), to=[contact.email]) # message to the webmaster and everyone who has selected to be notified about new contact forms notification = EmailMessage(get_message('notify.contact.subject'), get_message('notify.contact.body', args=(date, contact.to_string())), to=['*****@*****.**'], bcc=UserProfile.all_emails_with_bit( STATUS_BITS['EMAIL_NEW_CONTACT'])) # open a connection to the SMTP backend so we can send two messages over the same connection conn = get_connection() conn.open() conn.send_messages([message, notification]) conn.close()
def _send_info_card_emails(card): """Send an email thanking a potential for submitting an information card; email brothers who want to be notified. Required parameters: - card => the information card about which to email """ date = card.created.strftime('%B %d, %Y at %I:%M %p') # message to the person who submitted the information card message = EmailMessage(get_message('email.infocard.subject'), get_message('email.infocard.body', args=(card.name, date, card.to_string())), to=[card.email]) # message to the Membership Chair and everyone who has selected to be notified about new info cards notification = EmailMessage( get_message('notify.infocard.subject'), get_message('notify.infocard.body', args=(date, card.to_string(), settings.URI_PREFIX)), to=['*****@*****.**'], bcc=UserProfile.all_emails_with_bit(STATUS_BITS['EMAIL_NEW_INFOCARD'])) # open a connection to the SMTP backend so we can send two messages over the same connection conn = get_connection() conn.open() conn.send_messages([message, notification]) conn.close()
def reset_password(request, id): """Reset a user's password to a random string and email the user the new password. Required parameters: - id => the unique ID of the user whose password should be reset (as an integer) """ log_page_view(request, 'Reset Password') if request.user.is_authenticated( ) and not request.user.get_profile().is_admin(): return HttpResponseRedirect(reverse( 'forbidden')) # non-admins should use the 'change password' form user = get_object_or_404(User, id=id) anonymous = request.user.is_anonymous() if request.method == 'POST': password = User.objects.make_random_password( length=8, allowed_chars=settings.PASSWORD_RESET_CHARS) user.set_password(password) user.save() profile = user.get_profile() profile.set_bit(STATUS_BITS['PASSWORD_RESET']) profile.save() reset_message = get_message('email.password.reset' if anonymous else 'email.password.admin.reset') message = get_message('email.password.body', args=(profile.preferred_name(), reset_message, password)) user.email_user(get_message('email.password.subject'), message) if anonymous: log.info( 'Password reset for %s (%s) - temporary password emailed to %s', user.username, user.get_full_name(), user.email) redirect = reverse('reset_password_success') else: log.info( 'Admin %s (#%d) reset password for %s (%s) - temporary password emailed to %s', request.user.get_full_name(), request.user.get_profile().badge, user.username, user.get_full_name(), user.email) redirect = reverse('manage_users') return HttpResponseRedirect(redirect) return render(request, 'public/reset_password.html', { 'anon': anonymous, 'username': user.username, 'user_id': id }, context_instance=RequestContext(request))
def sign_in(request): """Render and process a form for users to sign into their accounts.""" log_page_view(request, 'Sign In') if request.user.is_authenticated(): return HttpResponseRedirect(reverse('home')) # you can't sign in once you're signed in ... if 'login_attempts' not in request.session: request.session['login_attempts'] = 1 if 'username' not in request.session: request.session['username'] = '' error = None if request.method == 'POST': username = request.POST.get('username', '') if username != request.session['username']: request.session['username'] = username request.session['login_attempts'] = 1 try: user = User.objects.get(username=username) except User.DoesNotExist: error = get_message('login.account.invalid') else: profile = user.get_profile() if profile.has_bit(STATUS_BITS['LOCKED_OUT']): error = get_message('login.account.locked') elif request.session['login_attempts'] > settings.MAX_LOGIN_ATTEMPTS: error = get_message('login.account.locked') profile.set_bit(STATUS_BITS['LOCKED_OUT']) profile.save() log.info('User %s (%s) is now locked out', profile.user.username, profile.common_name()) else: user = authenticate(username=username, password=request.POST.get('password')) if user is None: error = get_message('login.account.invalid') request.session['login_attempts'] += 1 # invalid password; increment login attempts elif not user.is_active: error = get_message('login.account.disabled') else: log.info('User %s (%s) signed in - last login was %s', user.username, user.get_full_name(), user.last_login.strftime('%m/%d/%Y %I:%M %p')) login(request, user) del request.session['login_attempts'], request.session['username'], request.session['group_perms'] return HttpResponseRedirect(_get_redirect_destination(request.META[REFERRER], user.get_profile())) else: username = '' return render(request, 'public/login.html', {'username': username, 'error': error}, context_instance=RequestContext(request))
def add_officer(request): """Render and process a form for administrators to add chapter officers (until all offices are added).""" log_page_view(request, 'Add Officer') error = None if request.method == 'POST': office = request.POST.get('office') found = False for key, value in OFFICER_CHOICES: if key == office: found = True break if found and not ChapterOfficer.objects.filter(office=office).count(): badge = int(request.POST.get('brother')) try: brother = UserProfile.objects.get(badge=badge) except UserProfile.DoesNotExist: error = get_message('officer.brother.invalid') else: officer = ChapterOfficer.objects.create(office=office, brother=brother, updated=date.today()) officer.save() return HttpResponseRedirect(reverse('show_officers')) else: error = get_message('officer.office.invalid') missing = [] for key, value in OFFICER_CHOICES: try: ChapterOfficer.objects.get(office=key) except ChapterOfficer.DoesNotExist: missing.append((key, value)) if not len(missing): return HttpResponseRedirect( reverse('forbidden')) # all offices have already been added brothers = [] for brother in UserProfile.objects.filter(status='U'): brothers.append((brother.badge, brother.common_name())) return render(request, 'officers/add_officer.html', { 'offices': missing, 'brothers': brothers, 'error': error }, context_instance=RequestContext(request))
def add_group(request): """Render and process a form to create a new user group.""" log_page_view(request, 'Add User Group') error = None initial_name = '' # empty string, not None (otherwise 'None' will appear in the form input) if request.method == 'POST': ids = [] group_name = None for name, value in request.POST.items(): if name.find('perm_') > -1: ids.append(int(value)) elif name == 'group_name': # validate group names for format and uniqueness initial_name = value if match(r'^[a-zA-Z0-9_]+[a-zA-Z0-9_ ]*[a-zA-Z0-9]+$', value) is None: error = get_message('group.name.invalid') elif Group.objects.filter(name=value).count() > 0: error = get_message('group.name.exists') else: group_name = value if error is None: if group_name is None: error = get_message('group.name.nonempty') elif not len(ids): error = get_message('group.perms.nonempty') else: group = Group.objects.create(name=group_name) group.permissions = Permission.objects.filter(id__in=ids) group.save() log.info('%s (%s) created user group \'%s\'', request.user.username, request.user.get_full_name(), group_name) return HttpResponseRedirect( reverse('view_group', kwargs={'name': group.name})) perms = _get_available_permissions() choices = [[perm.id, perm.name] for perm in perms] return render(request, 'brothers/add_group.html', { 'error': error, 'name': initial_name, 'perms': choices }, context_instance=RequestContext(request))
def _send_info_card_emails(card): """Send an email thanking a potential for submitting an information card; email brothers who want to be notified. Required parameters: - card => the information card about which to email """ date = card.created.strftime('%B %d, %Y at %I:%M %p') # message to the person who submitted the information card message = EmailMessage(get_message('email.infocard.subject'), get_message('email.infocard.body', args=(card.name, date, card.to_string())), to=[card.email]) # message to the Membership Chair and everyone who has selected to be notified about new info cards notification = EmailMessage(get_message('notify.infocard.subject'), get_message('notify.infocard.body', args=(date, card.to_string(), settings.URI_PREFIX)), to=['*****@*****.**'], bcc=UserProfile.all_emails_with_bit(STATUS_BITS['EMAIL_NEW_INFOCARD'])) # open a connection to the SMTP backend so we can send two messages over the same connection conn = get_connection() conn.open() conn.send_messages([message, notification]) conn.close()
def add_officer(request): """Render and process a form for administrators to add chapter officers (until all offices are added).""" log_page_view(request, 'Add Officer') error = None if request.method == 'POST': office = request.POST.get('office') found = False for key, value in OFFICER_CHOICES: if key == office: found = True break if found and not ChapterOfficer.objects.filter(office=office).count(): badge = int(request.POST.get('brother')) try: brother = UserProfile.objects.get(badge=badge) except UserProfile.DoesNotExist: error = get_message('officer.brother.invalid') else: officer = ChapterOfficer.objects.create(office=office, brother=brother, updated=date.today()) officer.save() return HttpResponseRedirect(reverse('show_officers')) else: error = get_message('officer.office.invalid') missing = [] for key, value in OFFICER_CHOICES: try: ChapterOfficer.objects.get(office=key) except ChapterOfficer.DoesNotExist: missing.append((key, value)) if not len(missing): return HttpResponseRedirect(reverse('forbidden')) # all offices have already been added brothers = [] for brother in UserProfile.objects.filter(status='U'): brothers.append((brother.badge, brother.common_name())) return render(request, 'officers/add_officer.html', {'offices': missing, 'brothers': brothers, 'error': error}, context_instance=RequestContext(request))
def _send_contact_emails(contact): """Send an email to a visitor who submitted a contact form; email brothers who want to be notified. Required parameters: - contact => the contact record for which to email """ date = contact.created.strftime('%B %d, %Y at %I:%M %p') # message to the person who submitted the information card message = EmailMessage(get_message('email.contact.subject'), get_message('email.contact.body', args=(contact.name, date, contact.to_string())), to=[contact.email]) # message to the webmaster and everyone who has selected to be notified about new contact forms notification = EmailMessage(get_message('notify.contact.subject'), get_message('notify.contact.body', args=(date, contact.to_string())), to=['*****@*****.**'], bcc=UserProfile.all_emails_with_bit(STATUS_BITS['EMAIL_NEW_CONTACT'])) # open a connection to the SMTP backend so we can send two messages over the same connection conn = get_connection() conn.open() conn.send_messages([message, notification]) conn.close()
def reset_password(request, id): """Reset a user's password to a random string and email the user the new password. Required parameters: - id => the unique ID of the user whose password should be reset (as an integer) """ log_page_view(request, 'Reset Password') if request.user.is_authenticated() and not request.user.get_profile().is_admin(): return HttpResponseRedirect(reverse('forbidden')) # non-admins should use the 'change password' form user = get_object_or_404(User, id=id) anonymous = request.user.is_anonymous() if request.method == 'POST': password = User.objects.make_random_password(length=8, allowed_chars=settings.PASSWORD_RESET_CHARS) user.set_password(password) user.save() profile = user.get_profile() profile.set_bit(STATUS_BITS['PASSWORD_RESET']) profile.save() reset_message = get_message('email.password.reset' if anonymous else 'email.password.admin.reset') message = get_message('email.password.body', args=(profile.preferred_name(), reset_message, password)) user.email_user(get_message('email.password.subject'), message) if anonymous: log.info('Password reset for %s (%s) - temporary password emailed to %s', user.username, user.get_full_name(), user.email) redirect = reverse('reset_password_success') else: log.info('Admin %s (#%d) reset password for %s (%s) - temporary password emailed to %s', request.user.get_full_name(), request.user.get_profile().badge, user.username, user.get_full_name(), user.email) redirect = reverse('manage_users') return HttpResponseRedirect(redirect) return render(request, 'public/reset_password.html', {'anon': anonymous, 'username': user.username, 'user_id': id}, context_instance=RequestContext(request))
def change_password(request): """Render and process a form for the currently authenticated user to change his password.""" log_page_view(request, 'Change Password') user = request.user profile = user.get_profile() reset = profile.has_bit(STATUS_BITS['PASSWORD_RESET']) if request.method == 'POST': form = ChangePasswordForm(request.POST) form.user = user if form.is_valid(): user.set_password(form.cleaned_data['password']) user.save() if reset: profile.clear_bit(STATUS_BITS['PASSWORD_RESET']) profile.save() else: send_mail( get_message('email.new_password.subject'), get_message('email.new_password.body', args=(user.first_name, )), settings.EMAIL_HOST_USER, [user.email]) log.info('User %s (%s) changed his password', user.username, user.get_full_name()) return HttpResponseRedirect(reverse('change_password_success')) else: form = ChangePasswordForm() form.user = user return render( request, 'brothers/change_password.html', { 'form': form, 'message': (get_message('profile.password.reset') if reset else None) }, context_instance=RequestContext(request))
def edit_visibility(request, public=True): """Render and process a form for the currently authenticated user to modify his visibility settings. Optional parameters: - public => whether to edit the user's public or chapter visibility settings (as a boolean): defaults to public """ viz = request.user.get_profile( ).public_visibility if public else request.user.get_profile( ).chapter_visibility if request.method == 'POST': if public: form = PublicVisibilityForm(request.POST, instance=viz) else: form = ChapterVisibilityForm(request.POST, instance=viz) if form.is_valid(): form.save() return HttpResponseRedirect(reverse('visibility')) else: if public: form = PublicVisibilityForm(instance=viz) else: form = ChapterVisibilityForm(instance=viz) fields = _get_fields_from_profile(request.user.get_profile()) vis_type = 'public' if public else 'chapter' message = get_message('visibility.edit.public') if public else get_message( 'visibility.edit.chapter') full_name_msg = get_message('visibility.fullname') return render(request, 'brothers/edit_visibility.html', { 'form': form, 'fields': fields, 'type': vis_type, 'message': message, 'name_msg': full_name_msg }, context_instance=RequestContext(request))
class RushEventForm(ModelForm): """A form to create and modify individual rush events, based on the RushEvent model class.""" date = DateField(input_formats=settings.DATE_INPUT_FORMATS) start = TimeField(label='Start time', input_formats=settings.TIME_INPUT_FORMATS, error_messages={'invalid': get_message('time.format.invalid')}) end = TimeField(label='End time', input_formats=settings.TIME_INPUT_FORMATS, error_messages={'invalid': get_message('time.format.invalid')}) def clean_date(self): """Ensure that the rush event's date falls within the rush's date range.""" rush = self.cleaned_data.get('rush') date = self.cleaned_data.get('date') if rush is not None and date is not None and (date < rush.start_date or date > rush.end_date): start = rush.start_date.strftime('%b %d') end = rush.end_date.strftime('%b %d, %Y') self._errors['date'] = self.error_class(['The date is outside the valid range (%s - %s).' % (start, end)]) del self.cleaned_data['date'] return self.cleaned_data['date'] if 'date' in self.cleaned_data else None class Meta: """Associate the form with the RushEvent model.""" model = RushEvent fields = ('title', 'date', 'start', 'end', 'description', 'location', 'link', 'food')
def sign_in(request): """Render and process a form for users to sign into their accounts.""" log_page_view(request, 'Sign In') if request.user.is_authenticated(): return HttpResponseRedirect( reverse('home')) # you can't sign in once you're signed in ... if 'login_attempts' not in request.session: request.session['login_attempts'] = 1 if 'username' not in request.session: request.session['username'] = '' error = None if request.method == 'POST': username = request.POST.get('username', '') if username != request.session['username']: request.session['username'] = username request.session['login_attempts'] = 1 try: user = User.objects.get(username=username) except User.DoesNotExist: error = get_message('login.account.invalid') else: profile = user.get_profile() if profile.has_bit(STATUS_BITS['LOCKED_OUT']): error = get_message('login.account.locked') elif request.session[ 'login_attempts'] > settings.MAX_LOGIN_ATTEMPTS: error = get_message('login.account.locked') profile.set_bit(STATUS_BITS['LOCKED_OUT']) profile.save() log.info('User %s (%s) is now locked out', profile.user.username, profile.common_name()) else: user = authenticate(username=username, password=request.POST.get('password')) if user is None: error = get_message('login.account.invalid') request.session[ 'login_attempts'] += 1 # invalid password; increment login attempts elif not user.is_active: error = get_message('login.account.disabled') else: log.info('User %s (%s) signed in - last login was %s', user.username, user.get_full_name(), user.last_login.strftime('%m/%d/%Y %I:%M %p')) login(request, user) del request.session['login_attempts'], request.session[ 'username'], request.session['group_perms'] return HttpResponseRedirect( _get_redirect_destination(request.META[REFERRER], user.get_profile())) else: username = '' return render(request, 'public/login.html', { 'username': username, 'error': error }, context_instance=RequestContext(request))
def edit_account(request, badge=0): """Render and process a form to modify a user's account. Optional parameters: - badge => the badge number of the user to edit (as an integer): defaults to the currently authenticated user """ log_page_view(request, 'Edit Account') if badge: profile = get_object_or_404(UserProfile, badge=badge) user = profile.user else: user = request.user profile = user.get_profile() own_account = (user == request.user) if not (own_account or request.user.get_profile().is_admin()): return HttpResponseRedirect(reverse('forbidden')) if request.method == 'POST': form = EditAccountForm(request.POST) if form.is_valid(): data = form.cleaned_data # access cleaned form data (normalized to Python objects) through 'data' save_user = False # we only want to save the user instance if one or more of its fields change if data['first_name'] != user.first_name or data[ 'last_name'] != user.last_name: user.first_name = data['first_name'] user.last_name = data['last_name'] save_user = True profile.middle_name = data['middle_name'] profile.nickname = data['nickname'] profile.suffix = data['suffix'] if data['status'] != profile.status: # process change in chapter status (undergraduate/alumnus) old_status = profile.status profile.status = data['status'] save_user = _process_status_change(user, old_status, data['status']) or save_user if data['email'] != user.email: # process change in email address (verify new address) digest = hashlib.sha224( '%d-%s' % (profile.badge, data['email'])).hexdigest() req = EmailChangeRequest(user=user, email=data['email'], hash=digest) req.save() send_mail( get_message('email.change.subject'), get_message('email.change.body', args=(user.first_name, settings.URI_PREFIX, digest)), settings.EMAIL_HOST_USER, [data['email']]) profile.save() if save_user: user.save() if own_account: redirect = reverse('my_profile') else: log.info( 'Admin %s (badge %d) edited account details of %s (%s %s)', request.user.get_full_name(), request.user.get_profile().badge, user.username, data['first_name'], data['last_name']) redirect = profile.get_absolute_url() return HttpResponseRedirect(redirect) else: form = EditAccountForm( initial={ 'first_name': user.first_name, 'middle_name': profile.middle_name, 'last_name': user.last_name, 'nickname': profile.nickname, 'suffix': profile.suffix, 'email': user.email, 'status': profile.status }) badge = profile.badge if ( badge and not own_account ) else None # pass badge if admin editing someone else's account return render(request, 'brothers/edit_account.html', { 'form': form, 'name': user.get_full_name(), 'own_account': own_account, 'badge': badge, 'alum': (profile.status == 'A') }, context_instance=RequestContext(request))
def edit_account(request, badge=0): """Render and process a form to modify a user's account. Optional parameters: - badge => the badge number of the user to edit (as an integer): defaults to the currently authenticated user """ log_page_view(request, 'Edit Account') if badge: profile = get_object_or_404(UserProfile, badge=badge) user = profile.user else: user = request.user profile = user.get_profile() own_account = (user == request.user) if not (own_account or request.user.get_profile().is_admin()): return HttpResponseRedirect(reverse('forbidden')) if request.method == 'POST': form = EditAccountForm(request.POST) if form.is_valid(): data = form.cleaned_data # access cleaned form data (normalized to Python objects) through 'data' save_user = False # we only want to save the user instance if one or more of its fields change if data['first_name'] != user.first_name or data['last_name'] != user.last_name: user.first_name = data['first_name'] user.last_name = data['last_name'] save_user = True profile.middle_name = data['middle_name'] profile.nickname = data['nickname'] profile.suffix = data['suffix'] if data['status'] != profile.status: # process change in chapter status (undergraduate/alumnus) old_status = profile.status profile.status = data['status'] save_user = _process_status_change(user, old_status, data['status']) or save_user if data['email'] != user.email: # process change in email address (verify new address) digest = hashlib.sha224('%d-%s' % (profile.badge, data['email'])).hexdigest() req = EmailChangeRequest(user=user, email=data['email'], hash=digest) req.save() send_mail(get_message('email.change.subject'), get_message('email.change.body', args=(user.first_name, settings.URI_PREFIX, digest)), settings.EMAIL_HOST_USER, [data['email']]) profile.save() if save_user: user.save() if own_account: redirect = reverse('my_profile') else: log.info('Admin %s (badge %d) edited account details of %s (%s %s)', request.user.get_full_name(), request.user.get_profile().badge, user.username, data['first_name'], data['last_name']) redirect = profile.get_absolute_url() return HttpResponseRedirect(redirect) else: form = EditAccountForm(initial={'first_name': user.first_name, 'middle_name': profile.middle_name, 'last_name': user.last_name, 'nickname': profile.nickname, 'suffix': profile.suffix, 'email': user.email, 'status': profile.status}) badge = profile.badge if (badge and not own_account) else None # pass badge if admin editing someone else's account return render(request, 'brothers/edit_account.html', {'form': form, 'name': user.get_full_name(), 'own_account': own_account, 'badge': badge, 'alum': (profile.status == 'A')}, context_instance=RequestContext(request))