import logging
import djmvc
from django.contrib import messages
from django.contrib.auth import get_user_model, login, logout
from django.contrib.auth.models import Group
from django.contrib.auth.forms import (
AuthenticationForm,
PasswordChangeForm,
SetPasswordForm,
UserChangeForm,
UserCreationForm,
)
from django.utils.translation import gettext as _
from django.views import generic
from djmvc.errors import not_found_response
from djmvc.model import ModelMixin
from djmvc.redirect import FULL_PAGE_LINK_ATTRIBUTES, full_page_redirect_home
from djmvc.views.form import FormMixin
from djmvc.views.object import ObjectMixin
from djmvc.views.template import TemplateViewMixin
logger = logging.getLogger(__name__)
User = get_user_model()
[docs]
class LoginView(djmvc.generic.FormView):
form_class = AuthenticationForm
tags = ['topbar', 'navigation']
icon = 'box-arrow-in-right'
@property
def form_attributes(self):
attrs = dict(FormMixin.form_attributes)
attrs['up-target'] = 'body'
attrs['up-history'] = False
return attrs
@property
def title(self):
return _('Log in')
[docs]
def has_permission(self):
"""Show login only to anonymous users."""
return not self.request.user.is_authenticated
[docs]
class LogoutView(djmvc.generic.FormView):
tags = ['topbar', 'navigation']
icon = 'box-arrow-right'
form_attributes = {
'up-submit': False,
}
@property
def title(self):
return _('Log out')
@property
def message(self):
return _('Are you sure you want to logout?')
[docs]
def has_permission(self):
"""Show logout only to authenticated users."""
return self.request.user.is_authenticated
[docs]
class PasswordView(
ObjectMixin,
ModelMixin,
FormMixin,
TemplateViewMixin,
generic.FormView,
):
tags = ['object']
icon = 'key'
color = 'link'
action = 'click->modal#open'
default_template_name = 'form.html'
@property
def codename(self):
return 'password'
@property
def title(self):
if self.object == self.request.user:
return _('Change password')
return _('Set password')
@property
def submit_button_label(self):
return _('Save')
[docs]
def get_success_url(self):
detail_route = self.controller.find_route('detail')
if detail_route:
return type(detail_route)(
request=self.request,
object=self.object,
).url
list_route = self.controller.find_route('list')
if list_route:
return type(list_route)(request=self.request).url
return '/'
[docs]
class BecomeUser(ObjectMixin, ModelMixin, djmvc.View):
tags = ['object']
icon = 'person-badge'
color = 'danger'
@property
def codename(self):
return 'su'
@property
def title(self):
return _('Become user')
[docs]
def unpoly_attributes(self, context=None):
return FULL_PAGE_LINK_ATTRIBUTES
def get_object(self, queryset=None):
try:
user = super().get_object()
except User.DoesNotExist:
messages.error(
self.request,
_('Could not find user %(pk)s') % {'pk': self.kwargs['pk']},
)
return None
user.backend = 'django.contrib.auth.backends.ModelBackend'
return user
def get(self, request, *args, **kwargs):
if self.object is None:
return full_page_redirect_home(request)
logger.info('BecomeUser by %s', request.user)
become_user_realname = str(request.user)
become_user = request.session.get('become_user', request.user.pk)
login(request, self.object)
request.session.setdefault('become_user_realname', become_user_realname)
request.session['become_user'] = become_user
messages.info(
request,
_('Switched to user %(user)s') % {'user': request.user},
)
return full_page_redirect_home(request)
[docs]
class Become(djmvc.View):
tags = ['topbar', 'navigation']
icon = 'arrow-return-left'
@property
def codename(self):
return 'su'
[docs]
def has_permission(self):
return 'become_user' in self.request.session
@property
def title(self):
realname = self.request.session.get('become_user_realname', '')
return _('Back to your account (%(name)s)') % {'name': realname}
[docs]
def unpoly_attributes(self, context=None):
return FULL_PAGE_LINK_ATTRIBUTES
[docs]
def dispatch(self, *args, **kwargs):
if 'become_user' not in self.request.session:
return not_found_response(self.request, view=self)
return super().dispatch(*args, **kwargs)
def get(self, request, *args, **kwargs):
logger.info('Become by %s', request.user)
user = User.objects.get(pk=request.session['become_user'])
user.backend = 'django.contrib.auth.backends.ModelBackend'
login(request, user)
messages.info(
request,
_('Switched back to your user %(user)s') % {'user': user},
)
request.session.pop('become_user', None)
return full_page_redirect_home(request)
[docs]
class GroupController(djmvc.ModelController.clone(
model=Group,
icon='collection',
routes=djmvc.ModelController.routes + [
djmvc.generic.ListView.clone(
table_fields=['id', 'name'],
site_search=True,
),
],
)):
"""CRUD for auth groups; autocomplete endpoint used by User form filters."""
[docs]
def get_queryset(self, view):
return super().get_queryset(view).order_by('name')
[docs]
class UserCreateView(djmvc.generic.CreateView):
[docs]
class UserUpdateView(djmvc.generic.UpdateView):
[docs]
class AuthController(djmvc.Controller):
routes = [
LoginView,
LogoutView,
Become,
GroupController,
djmvc.ModelController.clone(
model=User,
icon='people',
routes=djmvc.ModelController.routes + [
djmvc.generic.ListView.clone(
table_fields=[
'id',
'username',
'email',
'is_active',
'actions',
],
filter_fields=['groups'],
site_search=True,
),
UserCreateView,
UserUpdateView,
PasswordView,
BecomeUser,
],
),
]