Coverage for sm/views_onboarding.py: 74%

46 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-10-24 19:06 +0000

1from django.contrib import messages 

2from django.contrib.auth.mixins import LoginRequiredMixin 

3from django.shortcuts import redirect 

4from django.utils.translation import gettext as _ 

5from django.views.generic import TemplateView 

6from typing import Any 

7 

8from .models import Invitation 

9from uuid import UUID 

10 

11 

12def user_has_real_groups(user) -> bool: 

13 """ 

14 A user is considered on-boarded once they are a member of at least one 

15 group that is not their automatically-created personal workspace. 

16 """ 

17 for group in user.groups.all(): 

18 if not group.name.endswith("'s Workspace"): 

19 return True 

20 return False 

21 

22 

23class GroupOnboardingView(LoginRequiredMixin, TemplateView): 

24 template_name = "group/onboarding.html" 

25 

26 def get_context_data(self, **kwargs: Any) -> Any: 

27 context = super().get_context_data(**kwargs) 

28 context["onboarding_needed"] = not user_has_real_groups(self.request.user) 

29 return context 

30 

31 def post(self, request: Any, *args: Any, **kwargs: Any) -> Any: 

32 action = request.POST.get("action") 

33 if action == "join": 

34 token = request.POST.get("token", "").strip() 

35 try: 

36 UUID(token) 

37 except (ValueError, TypeError): 

38 messages.error(request, _("Invalid invitation token.")) 

39 return self.get(request, *args, **kwargs) 

40 invitation = Invitation.objects.filter(token=token).first() 

41 if invitation is None: 

42 messages.error(request, _("Invalid invitation token.")) 

43 return self.get(request, *args, **kwargs) 

44 return redirect("accept_invitation", token=token) 

45 if action == "create": 

46 return redirect("group_create") 

47 messages.warning(request, _("Please choose an action.")) 

48 return self.get(request, *args, **kwargs) 

49 

50 

51class OnboardingBannerContext: 

52 """ 

53 Small helper so templates can render an onboarding banner via the 

54 ``onboarding_needed`` context variable. 

55 """ 

56 

57 def __init__(self, request): 

58 self.request = request 

59 

60 @property 

61 def needs_onboarding(self) -> bool: 

62 user = getattr(self.request, "user", None) 

63 if user is None or not user.is_authenticated: 

64 return False 

65 return not user_has_real_groups(user)