text: # Copyright (c) 2012-2016 Seafile Ltd.
  try:
      from urllib.parse import urlencode
  except ImportError:
      from urllib.parse import urlencode
  
  from django.urls import reverse
  from django.template.response import TemplateResponse
  from seahub.auth import REDIRECT_FIELD_NAME
  from django.core.exceptions import PermissionDenied
  from django.shortcuts import redirect
  
  from seahub.two_factor.models import default_device
  
  
  class OTPRequiredMixin(object):
      """
      View mixin which verifies that the user logged in using OTP.
  
      .. note::
         This mixin should be the left-most base class.
      """
      raise_anonymous = False
      """
      Whether to raise PermissionDenied if the user isn't logged in.
      """
  
      login_url = None
      """
      If :attr:`raise_anonymous` is set to `False`, this defines where the user
      will be redirected to. Defaults to ``two_factor:login``.
      """
  
      redirect_field_name = REDIRECT_FIELD_NAME
      """
      URL query name to use for providing the destination URL.
      """
  
      raise_unverified = False
      """
      Whether to raise PermissionDenied if the user isn't verified.
      """
  
      verification_url = None
      """
      If :attr:`raise_unverified` is set to `False`, this defines where the user
      will be redirected to. If set to ``None``, an explanation will be shown to
      the user on why access was denied.
      """
  
      def get_login_url(self):
          """
          Returns login url to redirect to.
          """
          return self.login_url and str(self.login_url) or reverse('two_factor:login')
  
      def get_verification_url(self):
          """
          Returns verification url to redirect to.
          """
          return self.verification_url and str(self.verification_url)
  
      def dispatch(self, request, *args, **kwargs):
          if not request.user.is_authenticated() or \
                  (not request.user.is_verified() and default_device(request.user)):
              # If the user has not authenticated raise or redirect to the login
              # page. Also if the user just enabled two-factor authentication and
              # has not yet logged in since should also have the same result. If
              # the user receives a 'you need to enable TFA' by now, he gets
              # confuses as TFA has just been enabled. So we either raise or
              # redirect to the login page.
              if self.raise_anonymous:
                  raise PermissionDenied()
              else:
                  return redirect('%s?%s' % (
                      self.get_login_url(),
                      urlencode({self.redirect_field_name: request.get_full_path()})
                  ))
  
          if not request.user.is_verified():
              if self.raise_unverified:
                  raise PermissionDenied()
              elif self.get_verification_url():
                  return redirect('%s?%s' % (
                      self.verification_url,
                      urlencode({self.redirect_field_name: request.get_full_path()})
                  ))
              else:
                  return TemplateResponse(
                      request=request,
                      template='two_factor/core/otp_required.html',
                      status=403,
                  )
          return super(OTPRequiredMixin, self).dispatch(request, *args, **kwargs)
  