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

69 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 

5import requests 

6from django.core.cache import cache 

7from django.db.models import Sum 

8from django.utils.translation import gettext, gettext_lazy 

9from django.views.generic import TemplateView 

10 

11from weblate.accounts.models import Profile 

12from weblate.metrics.models import Metric 

13from weblate.utils.requests import request 

14from weblate.utils.requirements import get_versions_list 

15from weblate.utils.stats import GlobalStats 

16from weblate.vcs.gpg import get_gpg_public_key, get_gpg_sign_key 

17from weblate.vcs.ssh import get_all_key_data 

18 

19MENU = ( 

20 ("index", "about", gettext_lazy("About Weblate")), 

21 ("stats", "stats", gettext_lazy("Statistics")), 

22 ("keys", "keys", gettext_lazy("Keys")), 

23 ("donate", "donate", gettext_lazy("Support Weblate")), 

24) 

25 

26REPO_URL = "https://api.github.com/repos/WeblateOrg/weblate" 

27ACTIVITY_URL = "https://api.github.com/repos/WeblateOrg/weblate/stats/commit_activity" 

28FALLBACK_STATS = { 

29 "stars": 4082, 

30 "issues": 447, 

31 "commits": 663, 

32} 

33 

34 

35class AboutView(TemplateView): 

36 page = "index" 

37 

38 def page_context(self, context) -> None: 

39 context.update( 

40 { 

41 "title": gettext("About Weblate"), 

42 "versions": get_versions_list(), 

43 "allow_index": True, 

44 } 

45 ) 

46 

47 def get_context_data(self, **kwargs): 

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

49 

50 context["menu_items"] = MENU 

51 context["menu_page"] = self.page 

52 

53 self.page_context(context) 

54 

55 return context 

56 

57 def get_template_names(self): 

58 return [f"about/{self.page}.html"] 

59 

60 

61class StatsView(AboutView): 

62 page = "stats" 

63 

64 def page_context(self, context) -> None: 

65 context["title"] = gettext("Weblate statistics") 

66 

67 stats = GlobalStats() 

68 

69 totals = Profile.objects.aggregate(Sum("translated")) 

70 metrics = Metric.objects.get_current_metric(None, Metric.SCOPE_GLOBAL, 0) 

71 

72 context["total_translations"] = totals["translated__sum"] 

73 context["stats"] = stats 

74 context["metrics"] = metrics 

75 

76 context["top_users"] = top_users = ( 

77 Profile.objects.order_by("-translated") 

78 .filter(user__is_bot=False, user__is_active=True)[:10] 

79 .select_related("user") 

80 ) 

81 translated_max = max(user.translated for user in top_users) 

82 for user in top_users: 

83 if translated_max: 

84 user.translated_width = 100 * user.translated // translated_max 

85 else: 

86 user.translated_width = 0 

87 

88 

89class KeysView(AboutView): 

90 page = "keys" 

91 

92 def page_context(self, context) -> None: 

93 context.update( 

94 { 

95 "title": gettext("Weblate keys"), 

96 "gpg_key_id": get_gpg_sign_key(), 

97 "gpg_key": get_gpg_public_key(), 

98 "public_ssh_keys": get_all_key_data(), 

99 "allow_index": True, 

100 } 

101 ) 

102 

103 

104class DonateView(AboutView): 

105 page = "donate" 

106 cache_key = "weblate-repo-stats" 

107 

108 def fetch_url(self, url: str): 

109 response = request("get", url) 

110 return response.json() 

111 

112 def get_stats(self) -> dict[str, int]: 

113 result = cache.get(self.cache_key) 

114 if result is None: 

115 try: 

116 repo = self.fetch_url(REPO_URL) 

117 activity = self.fetch_url(ACTIVITY_URL) 

118 except requests.exceptions.RequestException: 

119 return FALLBACK_STATS 

120 activity = sorted(activity, key=lambda item: -item["week"]) 

121 result = { 

122 "stars": repo["stargazers_count"], 

123 "issues": repo["open_issues_count"], 

124 "commits": sum(item["total"] for item in activity[:8]), 

125 } 

126 cache.set(self.cache_key, result, 24 * 3600) 

127 return result 

128 

129 def page_context(self, context) -> None: 

130 context["title"] = gettext("Support Weblate") 

131 context.update(self.get_stats())