(api) create stats endpoint

create stats endpoint to expose public metrics
This commit is contained in:
Marie PUPO JEAMMET
2025-01-17 10:54:57 +01:00
committed by Marie
parent 0e92c1cafa
commit 870ef424f5
4 changed files with 83 additions and 0 deletions

View File

@@ -10,6 +10,7 @@ and this project adheres to
### Added
- ✨(api) create stats endpoint
- ✨(teams) add Team dependencies #560
- ✨(organization) add admin action for plugin #640
- ✨(anct) fetch and display organization names of communes #583

View File

@@ -1,5 +1,6 @@
"""API endpoints"""
import datetime
import operator
from functools import reduce
@@ -25,6 +26,10 @@ from core.api import permissions
from core.api.client import serializers
from core.utils.raw_sql import gen_sql_filter_json_array
from mailbox_manager import models as domains_models
SIMILARITY_THRESHOLD = 0.04
class NestedGenericViewSet(viewsets.GenericViewSet):
"""
@@ -586,6 +591,28 @@ class ConfigView(views.APIView):
return response.Response(dict_settings)
class StatView(views.APIView):
"""API ViewSet for sharing some public metrics."""
permission_classes = [AllowAny]
def get(self, request):
"""
GET /api/v1.0/stats/
Return a dictionary of public metrics.
"""
context = {
"total_users": models.User.objects.all().count(),
"mau": models.User.objects.filter(
last_login__gte=datetime.datetime.now() - datetime.timedelta(30)
).count(),
"teams": models.Team.objects.all().count(),
"domains": domains_models.MailDomain.objects.all().count(),
"mailboxes": domains_models.Mailbox.objects.all().count(),
}
return response.Response(context)
class ServiceProviderFilter(filters.BaseFilterBackend):
"""
Filter service providers.

View File

@@ -0,0 +1,54 @@
"""
Test stats endpoint
"""
import pytest
from rest_framework import status
from rest_framework.test import APIClient
from core import factories as core_factories
from mailbox_manager import factories as domains_factories
from mailbox_manager import models as domains_models
pytestmark = pytest.mark.django_db
def test_api_stats__anonymous():
"""Stats endpoint should be available even when not connected."""
response = APIClient().get("/api/v1.0/stats/")
assert response.status_code == status.HTTP_200_OK
assert response.json() == {
"total_users": 0,
"mau": 0,
"domains": 0,
"mailboxes": 0,
"teams": 0,
}
def test_api_stats__expected_count():
"""Objects should be correctly counted."""
core_factories.UserFactory.create_batch(4)
logged_in_users = core_factories.UserFactory.create_batch(6)
client = APIClient()
for user in logged_in_users:
client.force_login(user)
core_factories.TeamFactory.create_batch(3)
domains_factories.MailDomainFactory.create_batch(2)
domains_factories.MailboxFactory.create_batch(
10, domain=domains_models.MailDomain.objects.all()[1]
)
response = APIClient().get("/api/v1.0/stats/")
assert response.status_code == status.HTTP_200_OK
assert response.json() == {
"total_users": 10,
"mau": 6,
"domains": 2,
"mailboxes": 10,
"teams": 3,
}

View File

@@ -51,4 +51,5 @@ urlpatterns = [
),
path(f"api/{settings.API_VERSION}/", include("mailbox_manager.urls")),
path(f"api/{settings.API_VERSION}/config/", viewsets.ConfigView.as_view()),
path(f"api/{settings.API_VERSION}/stats/", viewsets.StatView.as_view()),
]