Coverage for app/venv/lib/python3.14/site-packages/weblate/wladmin/middleware.py: 83%
41 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
« 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
5from __future__ import annotations
7import multiprocessing
8import time
9from random import randint
10from threading import Thread
11from typing import TYPE_CHECKING
13from django.conf import settings
14from django.core.cache import cache
15from django.shortcuts import redirect
16from django.urls import reverse
18from weblate.accounts.models import AuditLog
19from weblate.runner import main
21if TYPE_CHECKING: 21 ↛ 22line 21 didn't jump to line 22 because the condition on line 21 was never true
22 from weblate.auth.models import AuthenticatedHttpRequest
24CHECK_CACHE_KEY = "weblate-health-check"
27class ManageMiddleware:
28 """
29 Middleware to trigger periodic management tasks.
31 These have to be triggered from the UWSGI context to be able to detect differences
32 between Celery and UWSGI environments.
33 """
35 def __init__(self, get_response=None) -> None:
36 self.get_response = get_response
38 @staticmethod
39 def trigger_check() -> None:
40 if not settings.BACKGROUND_ADMIN_CHECKS: 40 ↛ 41line 40 didn't jump to line 41 because the condition on line 40 was never true
41 return
42 # Update last execution timestamp
43 cache.set(CHECK_CACHE_KEY, time.time())
45 # Use safer spawn method
46 context = multiprocessing.get_context("spawn")
48 # Spawn a management process to do a configuration health check
49 # - using threads causes problems with a database connections
50 # (SSL initialization and keeping open persistent connections)
51 # - spawning directly the method using multiprocessing is not easy
52 # because of missing invocation of django.setup()
53 process = context.Process(
54 target=main, kwargs={"argv": ["weblate", "configuration_health_check"]}
55 )
56 process.start()
58 # Make sure we catch SIGCHLD from the spawned process
59 thread = Thread(target=process.join)
60 thread.start()
62 def __call__(self, request: AuthenticatedHttpRequest):
63 if request.session.pop("redirect_to_donate", False): 63 ↛ 64line 63 didn't jump to line 64 because the condition on line 63 was never true
64 AuditLog.objects.create(request.user, request, "donate")
65 return redirect(reverse("donate"))
66 response = self.get_response(request)
67 if ( 67 ↛ 72line 67 didn't jump to line 72 because the condition on line 67 was never true
68 request.resolver_match
69 and request.resolver_match.view_name == "manage-performance"
70 ):
71 # Always trigger on the performance page
72 self.trigger_check()
73 elif randint(0, 100) == 1: # noqa: S311
74 # Trigger when last check is too old
75 last_run = cache.get(CHECK_CACHE_KEY)
76 now = time.time()
77 if last_run is None or now - last_run > 900:
78 self.trigger_check()
80 return response