Skip to content

Commit

Permalink
Add new interface to retrieve Tag dashboard data
Browse files Browse the repository at this point in the history
  • Loading branch information
mathjazz committed Feb 20, 2024
1 parent 0afb7d7 commit cb49997
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 48 deletions.
38 changes: 19 additions & 19 deletions pontoon/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,25 @@ class AggregatedStats(models.Model):
class Meta:
abstract = True

@classmethod
def get_chart_dict(cls, obj):
"""Get chart data dictionary"""
if obj.total_strings:
return {
"total_strings": obj.total_strings,
"approved_strings": obj.approved_strings,
"pretranslated_strings": obj.pretranslated_strings,
"strings_with_errors": obj.strings_with_errors,
"strings_with_warnings": obj.strings_with_warnings,
"unreviewed_strings": obj.unreviewed_strings,
"approved_share": round(obj.approved_percent),
"pretranslated_share": round(obj.pretranslated_percent),
"errors_share": round(obj.errors_percent),
"warnings_share": round(obj.warnings_percent),
"unreviewed_share": round(obj.unreviewed_percent),
"completion_percent": int(math.floor(obj.completed_percent)),
}

@classmethod
def get_stats_sum(cls, qs):
"""
Expand Down Expand Up @@ -1837,25 +1856,6 @@ def get_chart(cls, self, extra=None):

return chart

@classmethod
def get_chart_dict(cls, obj):
"""Get chart data dictionary"""
if obj.total_strings:
return {
"total_strings": obj.total_strings,
"approved_strings": obj.approved_strings,
"pretranslated_strings": obj.pretranslated_strings,
"strings_with_errors": obj.strings_with_errors,
"strings_with_warnings": obj.strings_with_warnings,
"unreviewed_strings": obj.unreviewed_strings,
"approved_share": round(obj.approved_percent),
"pretranslated_share": round(obj.pretranslated_percent),
"errors_share": round(obj.errors_percent),
"warnings_share": round(obj.warnings_percent),
"unreviewed_share": round(obj.unreviewed_percent),
"completion_percent": int(math.floor(obj.completed_percent)),
}

def aggregate_stats(self):
TranslatedResource.objects.filter(
resource__project=self.project,
Expand Down
11 changes: 2 additions & 9 deletions pontoon/localizations/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import math
from operator import attrgetter
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db.models import Q
Expand All @@ -20,7 +19,7 @@
)
from pontoon.contributors.views import ContributorsMixin
from pontoon.insights.utils import get_insights
from pontoon.tags.utils import TagsTool
from pontoon.tags.utils import Tags


def localization(request, code, slug):
Expand Down Expand Up @@ -159,13 +158,7 @@ def ajax_tags(request, code, slug):
if not project.tags_enabled:
raise Http404

tags_tool = TagsTool(
locales=[locale],
projects=[project],
priority=True,
)

tags = sorted(tags_tool, key=attrgetter("priority"), reverse=True)
tags = Tags(project=project, locale=locale).get()

return render(
request,
Expand Down
4 changes: 4 additions & 0 deletions pontoon/projects/templates/projects/includes/teams.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
{% set locale_projects = project.available_locales_list() %}

{% for locale in locales %}
{% if not tag %}
{% set main_link = url('pontoon.projects.project', project.slug) %}
{% set chart_link = url('pontoon.translate', locale.code, project.slug, 'all-resources') %}
{% set latest_activity = locale.get_latest_activity(project) %}
{% set chart = locale.get_chart(project) %}
{% endif %}
{% if locale.code in locale_projects %}
{% set class = 'limited' %}
{% if chart %}
Expand All @@ -35,6 +37,8 @@
{% if tag %}
{% set main_link = url('pontoon.projects.project', project.slug) + '?tag=' + tag.slug %}
{% set chart_link = url('pontoon.translate', locale.code, project.slug, 'all-resources') + '?tag=' + tag.slug %}
{% set latest_activity = locale.latest_activity %}
{% set chart = locale.chart %}
{% if chart %}
{% set main_link = chart_link %}
{% endif %}
Expand Down
10 changes: 2 additions & 8 deletions pontoon/projects/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import uuid
from operator import attrgetter
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
Expand All @@ -19,7 +18,7 @@
from pontoon.contributors.views import ContributorsMixin
from pontoon.insights.utils import get_insights
from pontoon.projects import forms
from pontoon.tags.utils import TagsTool
from pontoon.tags.utils import Tags


def projects(request):
Expand Down Expand Up @@ -107,12 +106,7 @@ def ajax_tags(request, slug):
if not project.tags_enabled:
raise Http404

tags_tool = TagsTool(
projects=[project],
priority=True,
)

tags = sorted(tags_tool, key=attrgetter("priority"), reverse=True)
tags = Tags(project=project).get()

return render(
request,
Expand Down
2 changes: 1 addition & 1 deletion pontoon/tags/templates/tags/tag.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ <h1>
</ul>

{{ HeadingInfo.progress_chart() }}
{{ HeadingInfo.progress_chart_legend(tag) }}
{{ HeadingInfo.progress_chart_legend(tag.chart) }}
</div>
</section>
{% endblock %}
Expand Down
5 changes: 2 additions & 3 deletions pontoon/tags/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.urls import reverse

from pontoon.base.models import Priority
from pontoon.tags.utils import TaggedLocale, TagTool
from pontoon.tags.utils import TagTool


@pytest.mark.django_db
Expand Down Expand Up @@ -170,7 +170,7 @@ def test_view_project_tag_locales(client, project_a, tag_a):


@pytest.mark.django_db
def test_view_project_tag_locales_ajax(client, project_a, project_locale_a, tag_a):
def test_view_project_tag_locales_ajax(client, project_a, tag_a):
url = reverse(
"pontoon.tags.ajax.teams",
kwargs=dict(project=project_a.slug, tag=tag_a.slug),
Expand All @@ -192,7 +192,6 @@ def test_view_project_tag_locales_ajax(client, project_a, project_locale_a, tag_

for i, locale in enumerate(locales):
locale = response.context_data["locales"][i]
assert isinstance(locale, TaggedLocale)
assert locale.code == locales[i].locale.code
assert locale.name == locales[i].locale.name

Expand Down
2 changes: 2 additions & 0 deletions pontoon/tags/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from .stats import TagsStatsTool
from .tagged import TaggedLocale
from .tag import TagTool
from .utils import Tags
from .tags import TagsTool
from .translations import TagsLatestTranslationsTool

Expand All @@ -16,6 +17,7 @@
"TagsLatestTranslationsTool",
"TagsResourcesTool",
"TagsStatsTool",
"Tags",
"TagsTool",
"TagTool",
)
121 changes: 121 additions & 0 deletions pontoon/tags/utils/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
from django.db.models import Q, Max, Sum

from pontoon.base.models import TranslatedResource, Translation
from pontoon.tags.models import Tag


class Tags:
"""This provides an API for retrieving related ``Tags`` for given filters,
providing statistical information and latest activity data.
"""

def __init__(self, **kwargs):
self.project = kwargs.get("project")
self.locale = kwargs.get("locale")
self.slug = kwargs.get("slug")
self.tag = Tag.objects.filter(project=self.project, slug=self.slug).first()

def get(self):
tags = (
Tag.objects.filter(project=self.project, resources__isnull=False)
.distinct()
.order_by("-priority", "name")
)

chart = self.chart(Q(), "resource__tag")
latest_activity = self.latest_activity(Q(), "resource__tag")
for tag in tags:
tag.chart = chart.get(tag.pk)
tag.latest_activity = latest_activity.get(tag.pk)

return tags

def get_tag_locales(self):
tag = self.tag

if tag is None:
return None

chart = self.chart(Q(resource__tag=self.tag), "resource__tag")
tag.chart = chart.get(tag.pk)
tag.locales = self.project.locales.all()

locale_chart = self.chart(Q(resource__tag=self.tag), "locale")
locale_latest_activity = self.latest_activity(
Q(resource__tag=self.tag), "locale"
)
for locale in tag.locales:
locale.chart = locale_chart.get(locale.pk)
locale.latest_activity = locale_latest_activity.get(locale.pk)

return tag

def chart(self, query, group_by):
trs = (
self.translated_resources.filter(query)
.values(group_by)
.annotate(
total_strings=Sum("resource__total_strings"),
approved_strings=Sum("approved_strings"),
pretranslated_strings=Sum("pretranslated_strings"),
strings_with_errors=Sum("strings_with_errors"),
strings_with_warnings=Sum("strings_with_warnings"),
unreviewed_strings=Sum("unreviewed_strings"),
)
)

return {
tr[group_by]: TranslatedResource.get_chart_dict(
TranslatedResource(
**dict([(key, tr[key]) for key in list(tr.keys())[1:]])
)
)
for tr in trs
}

def latest_activity(self, query, group_by):
latest_activity = {}
dates = {}
translations = Translation.objects.none()

trs = (
self.translated_resources.exclude(latest_translation__isnull=True)
.filter(query)
.values(group_by)
.annotate(
date=Max("latest_translation__date"),
approved_date=Max("latest_translation__approved_date"),
)
)

for tr in trs:
if tr["approved_date"] is not None and tr["approved_date"] > tr["date"]:
date = "approved_date"
else:
date = "date"

dates[tr[date]] = tr[group_by]
prefix = "entity__" if group_by == "resource__tag" else ""

# Find translations with matching date and tag/locale
translations |= Translation.objects.filter(
Q(**{date: tr[date], f"{prefix}{group_by}": tr[group_by]})
).prefetch_related("user", "approved_user")

for t in translations:
key = dates[t.latest_activity["date"]]
latest_activity[key] = t.latest_activity

return latest_activity

@property
def translated_resources(self):
trs = TranslatedResource.objects

if self.project is not None:
trs = trs.filter(resource__project=self.project)

if self.locale is not None:
trs = trs.filter(locale=self.locale)

return trs
14 changes: 6 additions & 8 deletions pontoon/tags/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from django.http import Http404

from .utils import TagsTool
from pontoon.base.models import Project
from pontoon.base.utils import is_ajax
from pontoon.tags.utils import Tags

from django.views.generic import DetailView

Expand All @@ -29,18 +29,16 @@ def get_AJAX(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)

def get_context_data(self, **kwargs):
try:
tag = TagsTool(
projects=[self.object],
priority=True,
)[self.kwargs["tag"]].get()
except IndexError:
tags = Tags(project=self.object, slug=self.kwargs["tag"])
tag = tags.get_tag_locales()

if not tag:
raise Http404

if is_ajax(self.request):
return dict(
project=self.object,
locales=list(tag.iter_locales()),
locales=tag.locales,
tag=tag,
)

Expand Down

0 comments on commit cb49997

Please sign in to comment.