# -*- coding: utf-8 -*- # Copyright (C) 1998-2015 by the Free Software Foundation, Inc. # # This file is part of Postorius. # # Postorius is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) # any later version. # # Postorius is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # Postorius. If not, see <http://www.gnu.org/licenses/>. from django.forms.formsets import formset_factory from django.contrib import messages from django.contrib.auth.decorators import (login_required,user_passes_test) from django.shortcuts import redirect, render from django.template import RequestContext from django.utils.decorators import method_decorator from django.utils.translation import gettext as _ from django.views.generic import TemplateView from django.http import Http404 try: from urllib2 import HTTPError except ImportError: from urllib.error import HTTPError from postorius import utils from postorius.models import MailmanConnectionError, AddressConfirmationProfile from postorius.forms import * from postorius.auth.decorators import * from postorius.views.generic import MailmanUserView from smtplib import SMTPException import errno from socket import error as socket_error class UserMailmanSettingsView(MailmanUserView): """The logged-in user's global Mailman Preferences.""" @method_decorator(login_required) def post(self, request): try: mm_user = MailmanUser.objects.get(address=request.user.email) form = UserPreferences(request.POST) if form.is_valid(): preferences = mm_user.preferences for key in form.fields.keys(): if form.cleaned_data[key] is not None: # None: nothing set yet. Remember to remove this test # when Mailman accepts None as a "reset to default" # value. preferences[key] = form.cleaned_data[key] preferences.save() messages.success(request, _('Your preferences have been updated.')) else: messages.error(request, _('Something went wrong.')) except MailmanApiError: return utils.render_api_error(request) except Mailman404Error as e: messages.error(request, e.msg) return redirect("user_mailmansettings") @method_decorator(login_required) def get(self, request): try: mm_user = MailmanUser.objects.get_or_create_from_django(request.user) except MailmanApiError: return utils.render_api_error(request) settingsform = UserPreferences(initial=mm_user.preferences) return render(request, 'postorius/user/mailman_settings.html', {'mm_user': mm_user, 'settingsform': settingsform}) class UserAddressPreferencesView(MailmanUserView): """The logged-in user's address-based Mailman Preferences.""" @method_decorator(login_required) def post(self, request): try: mm_user = MailmanUser.objects.get(address=request.user.email) formset_class = formset_factory(UserPreferences) formset = formset_class(request.POST) if formset.is_valid(): for form, address in zip(formset.forms, mm_user.addresses): preferences = address.preferences for key in form.fields.keys(): if form.cleaned_data[key] is not None: # None: nothing set yet. Remember to remove this test # when Mailman accepts None as a "reset to default" # value. preferences[key] = form.cleaned_data[key] preferences.save() messages.success(request, _('Your preferences have been updated.')) else: messages.error(request, _('Something went wrong.')) except MailmanApiError: return utils.render_api_error(request) except HTTPError as e: messages.error(request, e.msg) return redirect("user_address_preferences") @method_decorator(login_required) def get(self, request): try: helperform = UserPreferences() mm_user = MailmanUser.objects.get(address=request.user.email) addresses = mm_user.addresses AFormset = formset_factory(UserPreferences, extra=len(addresses)) formset = AFormset() zipped_data = zip(formset.forms, addresses) for form, address in zipped_data: form.initial = address.preferences except MailmanApiError: return utils.render_api_error(request) except Mailman404Error: return render(request, 'postorius/user/address_preferences.html', {'nolists': 'true'}) return render(request, 'postorius/user/address_preferences.html', {'mm_user': mm_user, 'addresses': addresses, 'helperform': helperform, 'formset': formset, 'zipped_data': zipped_data}) @login_required def user_list_options(request, list_id): utils.set_other_emails(request.user) mlist = List.objects.get_or_404(fqdn_listname=list_id) mm_user = MailmanUser.objects.get(address=request.user.email) subscription = None for s in mm_user.subscriptions: if s.role == 'member' and s.list_id == list_id: subscription = s break if not subscription: raise Http404(_('Subscription does not exist')) preferences = subscription.preferences if request.method == 'POST': form = UserPreferences(request.POST) if form.is_valid(): for key in form.cleaned_data.keys(): if form.cleaned_data[key] is not None: # None: nothing set yet. Remember to remove this test # when Mailman accepts None as a "reset to default" # value. preferences[key] = form.cleaned_data[key] preferences.save() messages.success(request, _('Your preferences have been updated.')) return redirect("user_list_options", list_id) else: messages.error(request, _('Something went wrong.')) else: form = UserPreferences(initial=subscription.preferences) user_emails = [request.user.email] + request.user.other_emails subscription_form = ChangeSubscriptionForm(user_emails, initial={'email': subscription.email}) return render(request, 'postorius/user/list_options.html', {'form': form, 'list': mlist, 'change_subscription_form': subscription_form}) class UserSubscriptionPreferencesView(MailmanUserView): """The logged-in user's subscription-based Mailman Preferences.""" @method_decorator(login_required) def post(self, request): try: subscriptions = self._get_memberships() formset_class = formset_factory(UserPreferences) formset = formset_class(request.POST) if formset.is_valid(): for form, subscription in zip(formset.forms, subscriptions): preferences = subscription.preferences for key in form.cleaned_data.keys(): if form.cleaned_data[key] is not None: # None: nothing set yet. Remember to remove this test # when Mailman accepts None as a "reset to default" # value. preferences[key] = form.cleaned_data[key] preferences.save() messages.success(request, _('Your preferences have been updated.')) else: messages.error(request, _('Something went wrong.')) except MailmanApiError: return utils.render_api_error(request) except HTTPError as e: messages.error(request, e.msg) return redirect("user_subscription_preferences") @method_decorator(login_required) def get(self, request): try: subscriptions = self._get_memberships() Mformset = formset_factory( UserPreferences, extra=len(subscriptions)) formset = Mformset() zipped_data = zip(formset.forms, subscriptions) for form, subscription in zipped_data: form.initial = subscription.preferences except MailmanApiError: return utils.render_api_error(request) except Mailman404Error: return render(request, 'postorius/user/subscription_preferences.html', {'nolists': 'true'}) return render(request, 'postorius/user/subscription_preferences.html', {'zipped_data': zipped_data, 'formset': formset}) @login_required def user_subscriptions(request): """Shows the subscriptions of a user.""" utils.set_other_emails(request.user) try: mm_user = MailmanUser.objects.get_or_create_from_django(request.user) except MailmanApiError: return utils.render_api_error(request) memberships = [m for m in mm_user.subscriptions if m.role == 'member'] return render(request, 'postorius/user/subscriptions.html', {'memberships': memberships}) @login_required() def user_profile(request, user_email=None): utils.set_other_emails(request.user) try: mm_user = MailmanUser.objects.get_or_create_from_django(request.user) except MailmanApiError: return utils.render_api_error(request) if request.method == 'POST': form = AddressActivationForm(request.POST) if form.is_valid(): profile = AddressConfirmationProfile.objects.create_profile( email=form.cleaned_data['email'], user=request.user) try: profile.send_confirmation_link(request) messages.success(request, _('Please follow the instructions sent via email to confirm the address')) return redirect('user_profile') except (SMTPException, socket_error) as serr: if not isinstance(serr, SMTPException) and serr.errno != errno.ECONNREFUSED: raise serr profile.delete() messages.error(request, _('Currently emails can not be added, please try again later')) else: form = AddressActivationForm(initial={'user_email': request.user.email}) return render(request, 'postorius/user/profile.html', {'mm_user': mm_user, 'form': form}, context_instance=RequestContext(request)) def _add_address(request, user_email, address): # Add an address to a user record in mailman. try: try: mailman_user = MailmanUser.objects.get(address=user_email) except Mailman404Error: mailman_user = MailmanUser.objects.create(user_email, '') mailman_user.add_address(address) except (MailmanApiError, MailmanConnectionError): messages.error(request, _('The address could not be added.')) def address_activation_link(request, activation_key): """ Checks the given activation_key. If it is valid, the saved address will be added to mailman. Also, the corresponding profile record will be removed. If the key is not valid, it will be ignored. """ try: profile = AddressConfirmationProfile.objects.get( activation_key=activation_key) if not profile.is_expired: _add_address(request, profile.user.email, profile.email) profile.delete() messages.success(request, _('The email address has been activated!')) else: profile.delete() messages.error(request, _('The activation link has expired, please add the email again!')) return redirect('address_activation') except AddressConfirmationProfile.DoesNotExist: messages.error(request, _('The activation link is invalid')) return redirect('list_index')