Coverage for app/venv/lib/python3.14/site-packages/weblate/trans/views/js.py: 41%

62 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 

4from __future__ import annotations 

5 

6from typing import TYPE_CHECKING 

7 

8from django.contrib.auth.decorators import login_required 

9from django.core.exceptions import PermissionDenied 

10from django.db import transaction 

11from django.http import HttpResponse, JsonResponse 

12from django.shortcuts import get_object_or_404, render 

13from django.utils.http import urlencode 

14from django.views.decorators.cache import cache_control 

15from django.views.decorators.http import require_POST 

16 

17from weblate.checks.flags import Flags 

18from weblate.checks.models import Check 

19from weblate.trans.models import Change, Component, Project, Translation, Unit 

20from weblate.trans.util import sort_unicode 

21from weblate.utils.views import parse_path 

22 

23if TYPE_CHECKING: 23 ↛ 24line 23 didn't jump to line 24 because the condition on line 23 was never true

24 from weblate.auth.models import AuthenticatedHttpRequest 

25 

26 

27def get_unit_translations(request: AuthenticatedHttpRequest, unit_id): 

28 """Return unit's other translations.""" 

29 unit = get_object_or_404(Unit, pk=int(unit_id)) 

30 user = request.user 

31 user.check_access_component(unit.translation.component) 

32 

33 return render( 

34 request, 

35 "js/translations.html", 

36 { 

37 "units": sort_unicode( 

38 unit.source_unit.unit_set.exclude(pk=unit.pk) 

39 .prefetch() 

40 .prefetch_full(), 

41 user.profile.get_translation_orderer(request), 

42 ), 

43 "component": unit.translation.component, 

44 }, 

45 ) 

46 

47 

48@require_POST 

49@login_required 

50@transaction.atomic 

51def ignore_check(request: AuthenticatedHttpRequest, check_id): 

52 obj = get_object_or_404(Check.objects.select_for_update(), pk=int(check_id)) 

53 

54 if not request.user.has_perm("unit.check", obj): 

55 raise PermissionDenied 

56 

57 # Mark check for ignoring 

58 obj.set_dismiss(state="revert" not in request.GET) 

59 # response for AJAX 

60 return HttpResponse("ok") 

61 

62 

63@require_POST 

64@login_required 

65@transaction.atomic 

66def ignore_check_source(request: AuthenticatedHttpRequest, check_id): 

67 obj = get_object_or_404(Check, pk=int(check_id)) 

68 unit = obj.unit.source_unit 

69 

70 if not request.user.has_perm("unit.check", obj) or not request.user.has_perm( 

71 "source.edit", unit.translation.component 

72 ): 

73 raise PermissionDenied 

74 

75 # Mark check for ignoring 

76 if obj.check_obj is None: 

77 # Disabled check 

78 ignore = f"ignore-{obj.name.replace('_', '-')}" 

79 else: 

80 ignore = obj.check_obj.ignore_string 

81 flags = Flags(unit.extra_flags) 

82 if ignore not in flags: 

83 flags.merge(ignore) 

84 unit.update_extra_flags(flags.format(), request.user) 

85 

86 # response for AJAX 

87 return JsonResponse( 

88 { 

89 "extra_flags": unit.extra_flags, 

90 "all_flags": obj.unit.all_flags.format(), 

91 "ignore_check": ignore, 

92 } 

93 ) 

94 

95 

96@login_required 

97def git_status(request: AuthenticatedHttpRequest, path): 

98 obj = parse_path(request, path, (Project, Component, Translation)) 

99 if not request.user.has_perm("meta:vcs.status", obj): 

100 raise PermissionDenied 

101 

102 repo_components = obj.all_repo_components 

103 

104 # Filter events from repository 

105 changes = ( 

106 Change.objects.filter( 

107 component__in=repo_components, action__in=Change.ACTIONS_REPOSITORY 

108 ) 

109 .prefetch() 

110 .recent() 

111 ) 

112 

113 # Get push label for the first component 

114 try: 

115 push_label = repo_components[0].repository_class.push_label 

116 except IndexError: 

117 push_label = "" 

118 

119 return render( 

120 request, 

121 "js/git-status.html", 

122 { 

123 "object": obj, 

124 "changes": changes, 

125 "changes_url_query": urlencode( 

126 ("action", action) for action in Change.ACTIONS_REPOSITORY 

127 ), 

128 "repositories": repo_components, 

129 "pending_units": obj.count_pending_units, 

130 "outgoing_commits": sum( 

131 repo.count_repo_outgoing for repo in repo_components 

132 ), 

133 "has_push_branch": any(repo.push_branch for repo in repo_components), 

134 "push_branch_outgoing_commits": sum( 

135 repo.count_push_branch_outgoing 

136 for repo in repo_components 

137 if repo.push_branch 

138 ), 

139 "missing_commits": sum(repo.count_repo_missing for repo in repo_components), 

140 "supports_push": any( 

141 repo.repository_class.supports_push for repo in repo_components 

142 ), 

143 "push_label": push_label, 

144 }, 

145 ) 

146 

147 

148@cache_control(max_age=3600) 

149def matomo(request: AuthenticatedHttpRequest): 

150 return render( 

151 request, "js/matomo.js", content_type='text/javascript; charset="utf-8"' 

152 )