adapter.py 7.16 KB
Newer Older
1
# standard library imports
2
from __future__ import absolute_import, print_function
Daniel W Bond's avatar
Daniel W Bond committed
3
# core django imports
4
from django.core.urlresolvers import reverse
5 6
from django.contrib import messages
from django.http import HttpResponseRedirect
7 8
from django.views.generic import FormView
from django.forms import Form
9
# third party imports
10
from allauth.account.adapter import get_adapter as get_account_adapter
11
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
12 13
from allauth.socialaccount.models import SocialAccount
from allauth.socialaccount.signals import social_account_removed
14
from allauth.exceptions import ImmediateHttpResponse
15
from braces.views import LoginRequiredMixin
16

Daniel W Bond's avatar
pep8 me  
Daniel W Bond committed
17

18
class AccountAdapter(DefaultSocialAccountAdapter):
19
    """A custom implementation of a portion of the allauth social media package.
20

21 22 23 24 25 26
    We're overriding a number of aspects of the allauth account adapter to support
    our special use of the package. We are using CAS, not Django's built-in
    authentication. Accordingly we change the where directed when successfully
    connecting an account and how errors are dealt with. Additionally, we are not using
    the social media accounts to verify or overwrite any aspect of the User model.
    """
27

28 29
    # the request processed by the adapter is one from the successful oauth callback
    # uncomment this method to print what URL you are arriving from
Daniel W Bond's avatar
pep8 me  
Daniel W Bond committed
30 31
    # def pre_social_login(self, request, sociallogin):
    #     print(request.get_full_path(), 'pre_login')
32

33
    def populate_user(self, request, sociallogin, data):
34 35 36
        # This is a hook to populate User attributes, but we expressly don't actually
        # want to overwrite anything from the social media account user. It's intended
        # in the package for when you are using social media for login.
37 38 39 40 41
        user = sociallogin.user
        return user

    def get_connect_redirect_url(self, request, socialaccount):
        # where the user is sent if the social account is indeed authenticated
42
        assert request.user.is_authenticated()
43

44 45
        # we are approximating that if a user has not completed the welcome walkthough,
        # it is likely the page on which they started-- see the pre_social_login method
46
        if not request.user.student.completedSocial:
47
            return reverse('welcomeSocial')
48
        else:
49
            return reverse('update_student', kwargs={
50
                'slug': request.user.username,
51 52 53 54
            })

    def authentication_error(self, request, provider_id, error=None, exception=None,
                             extra_context=None):
55
        """Adds a custom message to the message queue if social media auth fails."""
56 57 58 59 60

        error_message = """Looks like something went awry with your social
                           authentication. Wait a moment and try your username and
                           password again. If things are still broken, let us know by
                           sending an email to roomlist@lists.srct.gmu.edu."""
61

62
        if not request.user.student.completedSocial:
63 64
            # as a reminder, here is how django handles messages
            # https://docs.djangoproject.com/en/1.8/ref/contrib/messages/
65
            messages.add_message(request, messages.ERROR, error_message)
66
            social_redirect = HttpResponseRedirect(reverse('welcomeSocial'))
67 68 69
            raise ImmediateHttpResponse(social_redirect)
        else:
            messages.add_message(request, messages.ERROR, error_message)
Daniel W Bond's avatar
Daniel W Bond committed
70 71
            update_redirect = HttpResponseRedirect(reverse('update_student',
                                                           kwargs={'slug': request.user.username, }))
72
            raise ImmediateHttpResponse(update_redirect)
73

Daniel W Bond's avatar
pep8 me  
Daniel W Bond committed
74

75
class RemoveSocialConfirmationView(LoginRequiredMixin, FormView):
76 77 78 79
    """To customize where users are sent when removing their social media connections.
    We have written our own template to handle this feature that is much prettier than
    the one provided by allauth."""

80 81 82
    # we're not using this, but we're not allowed to have None
    form_class = Form

83
    template_name = "social/remove_social.html"
84 85 86
    login_url = 'login'

    def get(self, request, *args, **kwargs):
87 88 89 90 91 92 93 94 95
        current_url = self.request.get_full_path()
        # [u'', u'accounts', u'student', u'dbond2', u'settings', u'social', u'github', u'remove', u'']
        social_application = current_url.split('/')[6]

        connected_accounts = [account.provider
                              for account in request.user.socialaccount_set.all()]

        # first, check that the user has an account of the type specified in the url
        if not(social_application in connected_accounts):
96
            # no social media accounts? back to the settings page with you!
97 98 99
            messages.add_message(self.request,
                                 messages.INFO,
                                 "Select a social media icon to connect an account.")
100
            return HttpResponseRedirect(reverse('update_student',
Daniel W Bond's avatar
pep8 me  
Daniel W Bond committed
101
                                        kwargs={'slug': self.request.user.username}))
102 103 104
        else:
            return super(RemoveSocialConfirmationView, self).get(request, *args, **kwargs)

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
    def get_context_data(self, **kwargs):
        context = super(RemoveSocialConfirmationView, self).get_context_data(**kwargs)

        current_url = self.request.get_full_path()
        social_application = current_url.split('/')[6]

        for account in self.request.user.socialaccount_set.all():
            if account.provider == social_application:
                branding = account.get_provider().name

        context['branding'] = branding
        context['application'] = social_application
        return context

    def post(self, request, *args, **kwargs):
        current_url = self.request.get_full_path()
        social_application = current_url.split('/')[6]

        for account in request.user.socialaccount_set.all():
            if account.provider == social_application:
                social_account = account
                branding = account.get_provider().name

        # we do not need to use validate_disconnect, because accounts are not
        # associated with being able to log in
        try:
            social_account.delete()
            social_account_removed.send(sender=SocialAccount,
                                        request=request,
                                        socialaccount=social_account)
Daniel W Bond's avatar
Daniel W Bond committed
135
            message = "%s has been successfully disconnected." % branding
136 137 138 139 140 141 142 143 144 145 146
            messages.add_message(self.request,
                                 messages.SUCCESS,
                                 message)
        # if multiple posts went in, there won't be any 'social_account' or 'branding'
        # basically, that means it's already gone and it already works
        except UnboundLocalError:
            get_account_adapter().add_message(self.request,
                                              messages.SUCCESS,
                                              'socialaccount/messages/'
                                              'account_disconnected.txt')

147
        return HttpResponseRedirect(self.get_success_url())
148 149

    def get_success_url(self):
150
        return reverse('update_student',
Daniel W Bond's avatar
Daniel W Bond committed
151
                       kwargs={'slug': self.request.user.username})