import logging
import djcrud
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 djcrud.errors import not_found_response
from djcrud.model import ModelMixin
from djcrud.redirect import FULL_PAGE_LINK_ATTRIBUTES, full_page_redirect_home
from djcrud.views.form import FormMixin
from djcrud.views.object import ObjectMixin
from djcrud.views.template import TemplateViewMixin
logger = logging.getLogger(__name__)
User = get_user_model()
[docs]
class LoginView(djcrud.views.FormView):
form_class = AuthenticationForm
tags = [djcrud.tags.TOPBAR, djcrud.tags.NAVIGATION]
icon = "box-arrow-in-right"
@property
def form_attributes(self):
"""HTML attributes for the login form; targets the full page body."""
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(djcrud.views.FormView):
tags = [djcrud.tags.TOPBAR, djcrud.tags.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 = [djcrud.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.router.find_route("detail")
if detail_route:
return type(detail_route)(
request=self.request,
object=self.object,
).url
list_route = self.router.find_route("list")
if list_route:
return type(list_route)(request=self.request).url
return "/"
[docs]
class BecomeUser(ObjectMixin, ModelMixin, djcrud.View):
tags = [djcrud.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(djcrud.View):
tags = [djcrud.tags.TOPBAR, djcrud.tags.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 GroupRouter(
djcrud.ModelRouter.clone(
model=Group,
icon="collection",
routes=djcrud.ModelRouter.routes
+ [
djcrud.views.ListView.clone(
table_fields=["id", "name"],
),
],
)
):
"""CRUD for auth groups; autocomplete endpoint used by User form filters."""
[docs]
def get_queryset(self, *, user, model, action, perm, obj=None):
return (
super()
.get_queryset(user=user, model=model, action=action, perm=perm, obj=obj)
.order_by("name")
)
[docs]
class UserCreateView(djcrud.views.CreateView):
[docs]
class UserUpdateView(djcrud.views.UpdateView):
[docs]
class UserRouter(
djcrud.ModelRouter.clone(
model=User,
icon="people",
routes=djcrud.ModelRouter.routes
+ [
djcrud.views.ListView.clone(
table_fields=[
"id",
"username",
"email",
"is_active",
"actions",
],
filter_fields=["groups"],
),
UserCreateView,
UserUpdateView,
PasswordView,
BecomeUser,
],
)
):
pass
[docs]
class AuthRouter(djcrud.Router):
routes = [
LoginView,
LogoutView,
Become,
GroupRouter,
UserRouter,
]