Merge branch 'master' of git://github.com/melinath/philo
[philo.git] / contrib / waldo / models.py
index 4f0cd8c..efb6504 100644 (file)
@@ -6,11 +6,12 @@ from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm, Passwo
 from django.contrib.auth.models import User
 from django.contrib.auth.tokens import default_token_generator as password_token_generator
 from django.contrib.sites.models import Site
 from django.contrib.auth.models import User
 from django.contrib.auth.tokens import default_token_generator as password_token_generator
 from django.contrib.sites.models import Site
-from django.core.mail import send_mail
+from django.core.mail import EmailMultiAlternatives, send_mail
 from django.core.urlresolvers import reverse
 from django.db import models
 from django.http import Http404, HttpResponseRedirect
 from django.shortcuts import render_to_response, get_object_or_404
 from django.core.urlresolvers import reverse
 from django.db import models
 from django.http import Http404, HttpResponseRedirect
 from django.shortcuts import render_to_response, get_object_or_404
+from django.template.defaultfilters import striptags
 from django.utils.http import int_to_base36, base36_to_int
 from django.utils.translation import ugettext_lazy, ugettext as _
 from django.views.decorators.cache import never_cache
 from django.utils.http import int_to_base36, base36_to_int
 from django.utils.translation import ugettext_lazy, ugettext as _
 from django.views.decorators.cache import never_cache
@@ -81,7 +82,7 @@ class LoginMultiView(MultiView):
                        if host != request.get_host():
                                referrer = None
                        else:
                        if host != request.get_host():
                                referrer = None
                        else:
-                               redirect = ''.join(referrer[2:])
+                               redirect = '%s?%s' % (referrer[2], referrer[4])
                
                if referrer is None:
                        redirect = node.get_absolute_url()
                
                if referrer is None:
                        redirect = node.get_absolute_url()
@@ -107,6 +108,9 @@ class LoginMultiView(MultiView):
                """
                Displays the login form for the given HttpRequest.
                """
                """
                Displays the login form for the given HttpRequest.
                """
+               if request.user.is_authenticated():
+                       return HttpResponseRedirect(node.get_absolute_url())
+               
                context = self.get_context(extra_context)
                
                from django.contrib.auth.models import User
                context = self.get_context(extra_context)
                
                from django.contrib.auth.models import User
@@ -172,16 +176,25 @@ class LoginMultiView(MultiView):
                return inner
        
        def send_confirmation_email(self, subject, email, page, extra_context):
                return inner
        
        def send_confirmation_email(self, subject, email, page, extra_context):
-               message = page.render_to_string(extra_context=extra_context)
+               text_content = page.render_to_string(extra_context=extra_context)
                from_email = 'noreply@%s' % Site.objects.get_current().domain
                from_email = 'noreply@%s' % Site.objects.get_current().domain
-               send_mail(subject, message, from_email, [email])
+               
+               if page.template.mimetype == 'text/html':
+                       msg = EmailMultiAlternatives(subject, striptags(text_content), from_email, [email])
+                       msg.attach_alternative(text_content, 'text/html')
+                       msg.send()
+               else:
+                       send_mail(subject, text_content, from_email, [email])
        
        def password_reset(self, request, node=None, extra_context=None, token_generator=password_token_generator):
        
        def password_reset(self, request, node=None, extra_context=None, token_generator=password_token_generator):
+               if request.user.is_authenticated():
+                       return HttpResponseRedirect(node.get_absolute_url())
+               
                if request.method == 'POST':
                        form = PasswordResetForm(request.POST)
                        if form.is_valid():
                if request.method == 'POST':
                        form = PasswordResetForm(request.POST)
                        if form.is_valid():
+                               current_site = Site.objects.get_current()
                                for user in form.users_cache:
                                for user in form.users_cache:
-                                       current_site = Site.objects.get_current()
                                        token = token_generator.make_token(user)
                                        link = 'http://%s/%s/%s/' % (current_site.domain, node.get_absolute_url().strip('/'), reverse('password_reset_confirm', urlconf=self, kwargs={'uidb36': int_to_base36(user.id), 'token': token}).strip('/'))
                                        context = {
                                        token = token_generator.make_token(user)
                                        link = 'http://%s/%s/%s/' % (current_site.domain, node.get_absolute_url().strip('/'), reverse('password_reset_confirm', urlconf=self, kwargs={'uidb36': int_to_base36(user.id), 'token': token}).strip('/'))
                                        context = {
@@ -257,7 +270,7 @@ class LoginMultiView(MultiView):
                                }
                                self.send_confirmation_email('Confirm account creation at %s' % current_site.name, user.email, self.register_confirmation_email, context)
                                messages.add_message(request, messages.SUCCESS, 'An email has been sent to %s with details on activating your account.' % user.email, fail_silently=True)
                                }
                                self.send_confirmation_email('Confirm account creation at %s' % current_site.name, user.email, self.register_confirmation_email, context)
                                messages.add_message(request, messages.SUCCESS, 'An email has been sent to %s with details on activating your account.' % user.email, fail_silently=True)
-                               return HttpResponseRedirect('')
+                               return HttpResponseRedirect(node.get_absolute_url())
                else:
                        form = RegistrationForm()
                
                else:
                        form = RegistrationForm()
                
@@ -307,7 +320,8 @@ class AccountMultiView(LoginMultiView):
        to include in the account, and fields from the account profile to use in
        the account.
        """
        to include in the account, and fields from the account profile to use in
        the account.
        """
-       manage_account_page = models.ForeignKey(Page, related_name='%(app_label)s_%(class)s_manage_account_page')
+       manage_account_page = models.ForeignKey(Page, related_name='%(app_label)s_%(class)s_manage_account_related')
+       email_change_confirmation_email = models.ForeignKey(Page, related_name='%(app_label)s_%(class)s_email_change_confirmation_email_related')
        user_fields = ['first_name', 'last_name', 'email']
        required_user_fields = user_fields
        account_profile = None
        user_fields = ['first_name', 'last_name', 'email']
        required_user_fields = user_fields
        account_profile = None
@@ -317,7 +331,8 @@ class AccountMultiView(LoginMultiView):
        def urlpatterns(self):
                urlpatterns = super(AccountMultiView, self).urlpatterns
                urlpatterns += patterns('',
        def urlpatterns(self):
                urlpatterns = super(AccountMultiView, self).urlpatterns
                urlpatterns += patterns('',
-                       url(r'^account/$', self.login_required(self.account_view), name='account')
+                       url(r'^account/$', self.login_required(self.account_view), name='account'),
+                       url(r'^account/email/(?P<uidb36>\w+)/(?P<email>[\w.]+[+][\w.]+)/(?P<token>[^/]+)/$', self.email_change_confirm, name='email_change_confirm')
                )
                return urlpatterns
        
                )
                return urlpatterns
        
@@ -348,14 +363,33 @@ class AccountMultiView(LoginMultiView):
                
                return form_instances
        
                
                return form_instances
        
-       def account_view(self, request, node=None, extra_context=None):
+       def account_view(self, request, node=None, extra_context=None, token_generator=email_token_generator, *args, **kwargs):
                if request.method == 'POST':
                        form_instances = self.get_account_form_instances(request.user, request.POST)
                if request.method == 'POST':
                        form_instances = self.get_account_form_instances(request.user, request.POST)
+                       current_email = request.user.email
                        
                        for form in form_instances:
                                if not form.is_valid():
                                        break
                        else:
                        
                        for form in form_instances:
                                if not form.is_valid():
                                        break
                        else:
+                               # When the user_form is validated, it changes the model instance, i.e. request.user, in place.
+                               email = request.user.email
+                               if current_email != email:
+                                       
+                                       request.user.email = current_email
+                                       
+                                       for form in form_instances:
+                                               form.cleaned_data.pop('email', None)
+                                       
+                                       current_site = Site.objects.get_current()
+                                       token = token_generator.make_token(request.user, email)
+                                       link = 'http://%s/%s/%s/' % (current_site.domain, node.get_absolute_url().strip('/'), reverse('email_change_confirm', urlconf=self, kwargs={'uidb36': int_to_base36(request.user.id), 'email': email.replace('@', '+'), 'token': token}).strip('/'))
+                                       context = {
+                                               'link': link
+                                       }
+                                       self.send_confirmation_email('Confirm account email change at %s' % current_site.domain, email, self.email_change_confirmation_email, context)
+                                       messages.add_message(request, messages.SUCCESS, "An email has be sent to %s to confirm the email change." % email)
+                                       
                                for form in form_instances:
                                        form.save()
                                messages.add_message(request, messages.SUCCESS, "Account information saved.", fail_silently=True)
                                for form in form_instances:
                                        form.save()
                                messages.add_message(request, messages.SUCCESS, "Account information saved.", fail_silently=True)
@@ -386,7 +420,8 @@ class AccountMultiView(LoginMultiView):
        def account_required(self, view):
                def inner(request, *args, **kwargs):
                        if not self.has_valid_account(request.user):
        def account_required(self, view):
                def inner(request, *args, **kwargs):
                        if not self.has_valid_account(request.user):
-                               messages.add_message(request, messages.ERROR, "You need to add some account information before you can post listings.", fail_silently=True)
+                               if not request.method == "POST":
+                                       messages.add_message(request, messages.ERROR, "You need to add some account information before you can access this page.", fail_silently=True)
                                return self.account_view(request, *args, **kwargs)
                        return view(request, *args, **kwargs)
                
                                return self.account_view(request, *args, **kwargs)
                        return view(request, *args, **kwargs)
                
@@ -397,5 +432,32 @@ class AccountMultiView(LoginMultiView):
                messages.add_message(request, messages.INFO, 'Welcome! Please fill in some more information.', fail_silently=True)
                return HttpResponseRedirect('/%s/%s/' % (node.get_absolute_url().strip('/'), reverse('account', urlconf=self).strip('/')))
        
                messages.add_message(request, messages.INFO, 'Welcome! Please fill in some more information.', fail_silently=True)
                return HttpResponseRedirect('/%s/%s/' % (node.get_absolute_url().strip('/'), reverse('account', urlconf=self).strip('/')))
        
+       def email_change_confirm(self, request, node=None, extra_context=None, uidb36=None, token=None, email=None, token_generator=email_token_generator):
+               """
+               Checks that a given hash in an email change link is valid. If so, changes the email and redirects to the account page.
+               """
+               assert uidb36 is not None and token is not None and email is not None
+               
+               try:
+                       uid_int = base36_to_int(uidb36)
+               except:
+                       raise Http404
+               
+               user = get_object_or_404(User, id=uid_int)
+               
+               email = '@'.join(email.rsplit('+', 1))
+               
+               if email == user.email:
+                       # Then short-circuit.
+                       raise Http404
+               
+               if token_generator.check_token(user, email, token):
+                       user.email = email
+                       user.save()
+                       messages.add_message(request, messages.SUCCESS, 'Email changed successfully.')
+                       return HttpResponseRedirect('/%s/%s/' % (node.get_absolute_url().strip('/'), reverse('account', urlconf=self).strip('/')))
+               
+               raise Http404
+       
        class Meta:
                abstract = True
\ No newline at end of file
        class Meta:
                abstract = True
\ No newline at end of file