Coverage for app/venv/lib/python3.14/site-packages/weblate/legal/middleware.py: 0%

27 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-07 07:15 +0000

1# Copyright © Michal Čihař <michal@weblate.org> 

2# 

3# SPDX-License-Identifier: GPL-3.0-or-later 

4 

5from __future__ import annotations 

6 

7import re 

8from typing import TYPE_CHECKING 

9 

10from django.shortcuts import redirect 

11from django.urls import reverse 

12from django.utils.http import urlencode 

13from django.utils.translation import gettext 

14 

15from weblate.legal.models import Agreement 

16from weblate.utils import messages 

17 

18if TYPE_CHECKING: 

19 from weblate.auth.models import AuthenticatedHttpRequest 

20 

21 

22class RequireTOSMiddleware: 

23 """Middleware to enforce TOS confirmation on certain requests.""" 

24 

25 def __init__(self, get_response=None) -> None: 

26 self.get_response = get_response 

27 # Ignored paths regexp, mostly covers API and legal pages 

28 self.matcher = re.compile( 

29 r"^/(legal|about|contact|api|static|widget|data|hooks|avatar|healthz|js|css)/" 

30 ) 

31 

32 def process_view( 

33 self, request: AuthenticatedHttpRequest, view_func, view_args, view_kwargs 

34 ): 

35 """Check request whether user has agreed to TOS.""" 

36 # We intercept only GET requests for authenticated users 

37 if request.method != "GET" or not request.user.is_authenticated: 

38 return None 

39 

40 # Some paths are ignored 

41 if self.matcher.match(request.path): 

42 return None 

43 

44 # Check TOS agreement 

45 agreement = Agreement.objects.get_or_create(user=request.user)[0] 

46 if not agreement.is_current(): 

47 messages.info( 

48 request, 

49 gettext( 

50 "We have an updated version of the General Terms and Conditions document, " 

51 "please read it and confirm that you agree with it." 

52 ), 

53 ) 

54 return redirect( 

55 "{}?{}".format( 

56 reverse("legal:confirm"), 

57 urlencode({"next": request.get_full_path()}), 

58 ) 

59 ) 

60 

61 # Explicitly return None for all non-matching requests 

62 return None 

63 

64 def __call__(self, request: AuthenticatedHttpRequest): 

65 return self.get_response(request)