Coverage for src/mesh/views/views_user.py: 35%

67 statements  

« prev     ^ index     » next       coverage.py v7.7.0, created at 2025-04-28 07:45 +0000

1from typing import Any 

2 

3from django.contrib import messages 

4from django.contrib.auth import REDIRECT_FIELD_NAME, authenticate, login, logout 

5from django.contrib.auth.mixins import LoginRequiredMixin 

6from django.http import Http404, HttpRequest, HttpResponse, HttpResponseRedirect 

7from django.urls import reverse_lazy 

8from django.utils.translation import gettext_lazy as _ 

9from django.views.generic import FormView, View 

10 

11from mesh.model.roles.editor import Editor 

12from mesh.model.roles.journal_manager import JournalManager 

13from mesh.model.user.user_interfaces import ImpersonateData, UserInfo 

14from mesh.views.forms.user_forms import UserForm 

15from mesh.views.mixins import RoleMixin 

16 

17from ..models.user_models import USER_TOKEN_QUERY_PARAM 

18from .components.breadcrumb import get_base_breadcrumb 

19 

20 

21class InitImpersonateSessionView(RoleMixin, FormView): 

22 form_class = UserForm 

23 template_name = "mesh/forms/form_full_page.html" 

24 restricted_roles = [JournalManager, Editor] 

25 

26 def restrict_dispatch(self, request: HttpRequest, *args, **kwargs): 

27 """ 

28 Check that the user is not currently in impersonate mode (deny 

29 recursively impersonating user, too messy). 

30 """ 

31 if "impersonate_target_id" in self.request.session: 

32 return True 

33 return not self.role_handler.check_rights("can_impersonate") 

34 

35 def get_form_kwargs(self) -> dict[str, Any]: 

36 """ 

37 Adds the _users queryset of availabe users for impersonating when instantiating 

38 the form. 

39 """ 

40 kwargs = super().get_form_kwargs() 

41 kwargs["_users"] = self.role_handler.get_attribute("managed_users") 

42 

43 return kwargs 

44 

45 def get_success_url(self) -> str: 

46 return reverse_lazy("mesh:home") 

47 

48 def form_valid(self, form: UserForm) -> HttpResponse: 

49 """ 

50 Serializes the impersonate data in the current session. 

51 """ 

52 user = form.cleaned_data["user"] 

53 

54 user_info = UserInfo.from_user(self.request.user) # type:ignore 

55 

56 data = ImpersonateData(source=user_info, target_id=user.pk) 

57 data.serialize(self.request.session) 

58 

59 return super().form_valid(form) 

60 

61 def get_context_data(self, *args, **kwargs): 

62 context = super().get_context_data(*args, **kwargs) 

63 

64 context["page_title"] = _("Choose user to impersonate") 

65 

66 # Generate breadcrumb data 

67 breadcrumb = get_base_breadcrumb() 

68 breadcrumb.add_item(title=_("Impersonate user"), url=reverse_lazy("mesh:impersonate_init")) 

69 context["breadcrumb"] = breadcrumb 

70 return context 

71 

72 

73class CloseImpersonateSessionView(LoginRequiredMixin, View): 

74 """ 

75 Cleans the current session of all impersonating related variables. 

76 """ 

77 

78 def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: 

79 ImpersonateData.clean_session(request.session) 

80 redirect_url = request.headers.get("referer", reverse_lazy("mesh:home")) 

81 return HttpResponseRedirect(redirect_url) 

82 

83 

84# @method_decorator(rate_limit(action="token_authentication"), name="dispatch") 

85# We would like to protect this view with a rate limit mechanism. 

86# Unfortunately the django-allauth rate limiter does not support GET requests.. 

87class TokenLoginView(View): 

88 """ 

89 View to login using an `UserToken`. 

90 """ 

91 

92 def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: 

93 token = request.GET.get(USER_TOKEN_QUERY_PARAM) 

94 if not token: 

95 raise Http404 

96 

97 response = HttpResponseRedirect(reverse_lazy("mesh:home")) 

98 

99 user = authenticate(request, token=token) 

100 if not user: 

101 messages.warning( 

102 request, 

103 _( 

104 "The given authentication token is invalid, expired or " 

105 "you're not allowed to use token authentication." 

106 ), 

107 ) 

108 return response 

109 

110 # Check for redirection 

111 redirect_uri = request.GET.get(REDIRECT_FIELD_NAME) 

112 if redirect_uri: 

113 response = HttpResponseRedirect(redirect_uri) 

114 

115 # Handle already populated user instance by the default `AuthenticationMiddleware` 

116 if hasattr(request, "user"): 

117 # Same user requesting authentication -> Nothing to do. 

118 if request.user.is_authenticated and request.user.pk == user.pk: 

119 return response 

120 

121 logout(request) 

122 

123 request.user = user 

124 login(request, user) 

125 

126 return response