diff --git a/pontoon/api/urls.py b/pontoon/api/urls.py index e4b85a57c0..6394030133 100644 --- a/pontoon/api/urls.py +++ b/pontoon/api/urls.py @@ -1,7 +1,8 @@ from graphene_django.views import GraphQLView -from django.urls import re_path +from django.urls import include, path, re_path +from pontoon.api import views from pontoon.api.schema import schema from pontoon.settings import DEV @@ -13,4 +14,26 @@ r"^graphql/?$", GraphQLView.as_view(schema=schema, graphiql=DEV), ), + # API v1 + path( + "api/v1/", + include( + [ + path( + # User actions + "user-actions/", + include( + [ + # In a given project + path( + "/project//", + views.get_user_actions, + name="pontoon.api.get_user_actions.project", + ), + ] + ), + ), + ] + ), + ), ] diff --git a/pontoon/api/views.py b/pontoon/api/views.py new file mode 100644 index 0000000000..a69d93c6a7 --- /dev/null +++ b/pontoon/api/views.py @@ -0,0 +1,100 @@ +from datetime import datetime, timedelta + +from django.contrib.auth.decorators import login_required +from django.http import JsonResponse +from django.utils.timezone import make_aware +from django.views.decorators.http import require_GET + +from pontoon.actionlog.models import ActionLog +from pontoon.base.models import Project + + +@require_GET +@login_required(redirect_field_name="", login_url="/403") +def get_user_actions(request, date, slug): + try: + start_date = make_aware(datetime.strptime(date, "%Y-%m-%d")) + except ValueError: + return JsonResponse( + { + "error": "Invalid date format. Please use YYYY-MM-DD.", + }, + status=400, + ) + + end_date = start_date + timedelta(days=1) + + try: + project = Project.objects.get(slug=slug) + except Project.DoesNotExist: + return JsonResponse( + { + "error": "Project not found. Please use a valid project slug.", + }, + status=404, + ) + + actions = ActionLog.objects.filter( + action_type__startswith="translation:", + created_at__gte=start_date, + created_at__lt=end_date, + translation__entity__resource__project=project, + ) + + actions = actions.prefetch_related( + "performed_by__profile", + "translation__entity__resource", + "translation__errors", + "translation__warnings", + "translation__locale", + "entity__resource", + "locale", + ) + + output = [] + + for action in actions: + user = action.performed_by + locale = action.locale or action.translation.locale + entity = action.entity or action.translation.entity + resource = entity.resource + + data = { + "type": action.action_type, + "date": action.created_at, + "user": { + "pk": user.pk, + "name": user.display_name, + "system_user": user.profile.system_user, + }, + "locale": { + "pk": locale.pk, + "code": locale.code, + "name": locale.name, + }, + "entity": { + "pk": entity.pk, + "key": entity.key, + }, + "resource": { + "pk": resource.pk, + "path": resource.path, + "format": resource.format, + }, + } + + if action.translation: + data["translation"] = action.translation.serialize() + + output.append(data) + + return JsonResponse( + { + "actions": output, + "project": { + "pk": project.pk, + "slug": project.slug, + "name": project.name, + }, + } + ) diff --git a/pontoon/urls.py b/pontoon/urls.py index 947f71d806..e848b570e7 100644 --- a/pontoon/urls.py +++ b/pontoon/urls.py @@ -68,9 +68,9 @@ class LocaleConverter(StringConverter): path("", include("pontoon.contributors.urls")), path("", include("pontoon.localizations.urls")), path("", include("pontoon.base.urls")), + path("", include("pontoon.api.urls")), path("", include("pontoon.translate.urls")), path("", include("pontoon.batch.urls")), - path("", include("pontoon.api.urls")), path("", include("pontoon.homepage.urls")), path("", include("pontoon.uxactionlog.urls")), # Team page: Must be at the end