Skip to content

Commit

Permalink
refactor(stats): déplacer la vue StatistiquesPageView (#654)
Browse files Browse the repository at this point in the history
## Description

🎸 Pour préparer l'ajout de futures pages de statistiques, déplacement de
la vue `StatistiquesPageView` dans l'application `forum_stats`

## Type de changement

🚧 technique
  • Loading branch information
vincentporte authored Jun 4, 2024
1 parent 7cc5d14 commit cf9bc6e
Show file tree
Hide file tree
Showing 12 changed files with 197 additions and 177 deletions.
2 changes: 2 additions & 0 deletions config/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from lacommunaute.forum_conversation.forum_polls import urls as forum_polls_extension_urls
from lacommunaute.forum_member import urls as forum_member_urls
from lacommunaute.forum_moderation import urls as forum_moderation_urls
from lacommunaute.forum_stats import urls as forum_stats_urls
from lacommunaute.forum_upvote import urls as forum_upvote_urls
from lacommunaute.inclusion_connect import urls as inclusion_connect_urls
from lacommunaute.pages import urls as pages_urls
Expand Down Expand Up @@ -38,6 +39,7 @@
path("", include(forum_moderation_urls)),
path("calendar/", include(event_urls)),
path("surveys/", include(surveys_urls)),
path("statistiques/", include(forum_stats_urls)),
# machina legacy
path("", include(conversation_urlpatterns_factory.urlpatterns)),
path("moderation/", include(moderation_urlpatterns_factory.urlpatterns)),
Expand Down
2 changes: 1 addition & 1 deletion lacommunaute/forum/tests/test_categoryforum_listview.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def test_context(client, db):
url = reverse("forum_extension:documentation")
response = client.get(url)
assert "forum/category_forum_list.html" == response.templates[0].name
assertContains(response, reverse("pages:statistiques"), status_code=200)
assertContains(response, reverse("forum_stats:statistiques"), status_code=200)


def test_queryset(client, db):
Expand Down
Empty file.
File renamed without changes.
112 changes: 112 additions & 0 deletions lacommunaute/forum_stats/tests/tests_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
from django.test import TestCase
from django.urls import reverse
from django.utils import timezone
from django.utils.dateformat import format
from django.utils.timezone import localdate
from faker import Faker
from machina.core.loading import get_class

from lacommunaute.forum_stats.enums import Period
from lacommunaute.forum_stats.factories import StatFactory
from lacommunaute.utils.math import percent


faker = Faker()
assign_perm = get_class("forum_permission.shortcuts", "assign_perm")


class StatistiquesPageTest(TestCase):
def test_context_data(self):
url = reverse("forum_stats:statistiques")
date = timezone.now()
names = ["nb_uniq_engaged_visitors", "nb_uniq_visitors", "nb_uniq_active_visitors"]
for name in names:
StatFactory(name=name, date=date)
undesired_period_stat = StatFactory(
period=Period.WEEK, date=date - timezone.timedelta(days=7), name="nb_uniq_engaged_visitors"
)
undesired_date_stat = StatFactory(
period=Period.DAY, date=date - timezone.timedelta(days=91), name="nb_uniq_engaged_visitors"
)

response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "forum_stats/statistiques.html")

# expected values
self.assertIn("stats", response.context)
self.assertIn("date", response.context["stats"])
self.assertIn("nb_uniq_engaged_visitors", response.context["stats"])
self.assertIn("nb_uniq_visitors", response.context["stats"])
self.assertIn("nb_uniq_active_visitors", response.context["stats"])
self.assertEqual(response.context["stats"]["date"][0], date.strftime("%Y-%m-%d"))

# undesired values
self.assertNotIn(undesired_period_stat.date.strftime("%Y-%m-%d"), response.context["stats"]["date"])
self.assertNotIn(undesired_date_stat.date.strftime("%Y-%m-%d"), response.context["stats"]["date"])

def test_month_datas_in_context(self):
today = localdate()
url = reverse("forum_stats:statistiques")

# no data
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["period"], None)
self.assertEqual(response.context["nb_uniq_visitors"], 0)
self.assertEqual(response.context["nb_uniq_active_visitors"], 0)
self.assertEqual(response.context["nb_uniq_engaged_visitors"], 0)
self.assertEqual(response.context["activation_percent"], 0)
self.assertEqual(response.context["engagement_percent"], 0)

# undesired data
StatFactory(name="nb_uniq_engaged_visitors", period=Period.DAY, date=today)
StatFactory(name=faker.word(), period=Period.MONTH, date=today)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["period"], None)
self.assertEqual(response.context["nb_uniq_visitors"], 0)
self.assertEqual(response.context["nb_uniq_active_visitors"], 0)
self.assertEqual(response.context["nb_uniq_engaged_visitors"], 0)
self.assertEqual(response.context["activation_percent"], 0)
self.assertEqual(response.context["engagement_percent"], 0)

uniq_visitors = StatFactory(name="nb_uniq_visitors", period=Period.MONTH, date=today)
uniq_active_visitors = StatFactory(name="nb_uniq_active_visitors", period=Period.MONTH, date=today)
uniq_engaged_visitors = StatFactory(name="nb_uniq_engaged_visitors", period=Period.MONTH, date=today)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["period"], format(today, "F Y"))
self.assertEqual(response.context["nb_uniq_visitors"], uniq_visitors.value)
self.assertEqual(response.context["nb_uniq_active_visitors"], uniq_active_visitors.value)
self.assertEqual(response.context["nb_uniq_engaged_visitors"], uniq_engaged_visitors.value)
self.assertEqual(
response.context["activation_percent"], percent(uniq_active_visitors.value, uniq_visitors.value)
)
self.assertEqual(
response.context["engagement_percent"], percent(uniq_engaged_visitors.value, uniq_active_visitors.value)
)

def test_impact_in_context_data(self):
url = reverse("forum_stats:statistiques")
today = localdate()
empty_res = {"date": [], "nb_uniq_visitors_returning": []}

# no data
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["impact"], empty_res)

# undesired data
StatFactory(name="nb_uniq_visitors_returning", period=Period.DAY, date=today)
StatFactory(name=faker.word(), period=Period.MONTH, date=today)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["impact"], empty_res)

# desired data
StatFactory(name="nb_uniq_visitors_returning", period=Period.MONTH, date=today, value=1)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["impact"]["date"][0], today.strftime("%Y-%m-%d"))
self.assertEqual(response.context["impact"]["nb_uniq_visitors_returning"][0], 1)
8 changes: 8 additions & 0 deletions lacommunaute/forum_stats/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.urls import path

from lacommunaute.forum_stats.views import StatistiquesPageView


app_name = "forum_stats"

urlpatterns = [path("", StatistiquesPageView.as_view(), name="statistiques")]
73 changes: 73 additions & 0 deletions lacommunaute/forum_stats/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import logging

from django.db.models import CharField
from django.db.models.functions import Cast
from django.utils import timezone
from django.utils.dateformat import format
from django.views.generic.base import TemplateView

from lacommunaute.forum_stats.models import Stat
from lacommunaute.utils.json import extract_values_in_list
from lacommunaute.utils.math import percent


logger = logging.getLogger(__name__)


class StatistiquesPageView(TemplateView):
template_name = "forum_stats/statistiques.html"

def get_funnel_data(self):
qs = Stat.objects.current_month_datas()

stats = {
"period": None,
"nb_uniq_visitors": 0,
"nb_uniq_active_visitors": 0,
"nb_uniq_engaged_visitors": 0,
}

if qs.filter(name="nb_uniq_visitors").exists():
stats["period"] = format(qs.get(name="nb_uniq_visitors")["date"], "F Y")
stats["nb_uniq_visitors"] = qs.get(name="nb_uniq_visitors")["value"]

if qs.filter(name="nb_uniq_active_visitors").exists():
stats["nb_uniq_active_visitors"] = qs.get(name="nb_uniq_active_visitors")["value"]

if qs.filter(name="nb_uniq_engaged_visitors").exists():
stats["nb_uniq_engaged_visitors"] = qs.get(name="nb_uniq_engaged_visitors")["value"]

stats["activation_percent"] = percent(stats["nb_uniq_active_visitors"], stats["nb_uniq_visitors"])
stats["engagement_percent"] = percent(stats["nb_uniq_engaged_visitors"], stats["nb_uniq_active_visitors"])
return stats

def get_daily_stats(self):
indicator_names = [
"nb_uniq_visitors",
"nb_uniq_active_visitors",
"nb_uniq_engaged_visitors",
]
after_date = timezone.now() - timezone.timedelta(days=90)
datas = (
Stat.objects.filter(period="day", name__in=indicator_names, date__gte=after_date)
.values("name", "value")
.annotate(date=Cast("date", CharField()))
)
return extract_values_in_list(datas, indicator_names)

def get_monthly_visitors(self):
indicator_names = ["nb_uniq_visitors_returning"]
datas = (
Stat.objects.filter(period="month", name__in=indicator_names)
.values("name", "value")
.annotate(date=Cast("date", CharField()))
)
return extract_values_in_list(datas, indicator_names)

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["stats"] = self.get_daily_stats()
context["impact"] = self.get_monthly_visitors()
context = {**context, **self.get_funnel_data()}

return context
109 changes: 0 additions & 109 deletions lacommunaute/pages/tests/tests.py
Original file line number Diff line number Diff line change
@@ -1,116 +1,7 @@
from django.test import TestCase
from django.urls import reverse
from django.utils import timezone
from django.utils.dateformat import format
from django.utils.timezone import localdate
from faker import Faker
from machina.core.loading import get_class

from lacommunaute.forum_stats.enums import Period
from lacommunaute.forum_stats.factories import StatFactory
from lacommunaute.users.factories import UserFactory
from lacommunaute.utils.math import percent


faker = Faker()
assign_perm = get_class("forum_permission.shortcuts", "assign_perm")


class StatistiquesPageTest(TestCase):
def test_context_data(self):
url = reverse("pages:statistiques")
date = timezone.now()
names = ["nb_uniq_engaged_visitors", "nb_uniq_visitors", "nb_uniq_active_visitors"]
for name in names:
StatFactory(name=name, date=date)
undesired_period_stat = StatFactory(
period=Period.WEEK, date=date - timezone.timedelta(days=7), name="nb_uniq_engaged_visitors"
)
undesired_date_stat = StatFactory(
period=Period.DAY, date=date - timezone.timedelta(days=91), name="nb_uniq_engaged_visitors"
)

response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "pages/statistiques.html")

# expected values
self.assertIn("stats", response.context)
self.assertIn("date", response.context["stats"])
self.assertIn("nb_uniq_engaged_visitors", response.context["stats"])
self.assertIn("nb_uniq_visitors", response.context["stats"])
self.assertIn("nb_uniq_active_visitors", response.context["stats"])
self.assertEqual(response.context["stats"]["date"][0], date.strftime("%Y-%m-%d"))

# undesired values
self.assertNotIn(undesired_period_stat.date.strftime("%Y-%m-%d"), response.context["stats"]["date"])
self.assertNotIn(undesired_date_stat.date.strftime("%Y-%m-%d"), response.context["stats"]["date"])

def test_month_datas_in_context(self):
today = localdate()
url = reverse("pages:statistiques")

# no data
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["period"], None)
self.assertEqual(response.context["nb_uniq_visitors"], 0)
self.assertEqual(response.context["nb_uniq_active_visitors"], 0)
self.assertEqual(response.context["nb_uniq_engaged_visitors"], 0)
self.assertEqual(response.context["activation_percent"], 0)
self.assertEqual(response.context["engagement_percent"], 0)

# undesired data
StatFactory(name="nb_uniq_engaged_visitors", period=Period.DAY, date=today)
StatFactory(name=faker.word(), period=Period.MONTH, date=today)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["period"], None)
self.assertEqual(response.context["nb_uniq_visitors"], 0)
self.assertEqual(response.context["nb_uniq_active_visitors"], 0)
self.assertEqual(response.context["nb_uniq_engaged_visitors"], 0)
self.assertEqual(response.context["activation_percent"], 0)
self.assertEqual(response.context["engagement_percent"], 0)

uniq_visitors = StatFactory(name="nb_uniq_visitors", period=Period.MONTH, date=today)
uniq_active_visitors = StatFactory(name="nb_uniq_active_visitors", period=Period.MONTH, date=today)
uniq_engaged_visitors = StatFactory(name="nb_uniq_engaged_visitors", period=Period.MONTH, date=today)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["period"], format(today, "F Y"))
self.assertEqual(response.context["nb_uniq_visitors"], uniq_visitors.value)
self.assertEqual(response.context["nb_uniq_active_visitors"], uniq_active_visitors.value)
self.assertEqual(response.context["nb_uniq_engaged_visitors"], uniq_engaged_visitors.value)
self.assertEqual(
response.context["activation_percent"], percent(uniq_active_visitors.value, uniq_visitors.value)
)
self.assertEqual(
response.context["engagement_percent"], percent(uniq_engaged_visitors.value, uniq_active_visitors.value)
)

def test_impact_in_context_data(self):
url = reverse("pages:statistiques")
today = localdate()
empty_res = {"date": [], "nb_uniq_visitors_returning": []}

# no data
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["impact"], empty_res)

# undesired data
StatFactory(name="nb_uniq_visitors_returning", period=Period.DAY, date=today)
StatFactory(name=faker.word(), period=Period.MONTH, date=today)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["impact"], empty_res)

# desired data
StatFactory(name="nb_uniq_visitors_returning", period=Period.MONTH, date=today, value=1)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["impact"]["date"][0], today.strftime("%Y-%m-%d"))
self.assertEqual(response.context["impact"]["nb_uniq_visitors_returning"][0], 1)


class LandingPagesListViewTest(TestCase):
Expand Down
1 change: 0 additions & 1 deletion lacommunaute/pages/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

urlpatterns = [
path("", views.HomeView.as_view(), name="home"),
path("statistiques/", views.StatistiquesPageView.as_view(), name="statistiques"),
path("accessibilite/", views.accessibilite, name="accessibilite"),
path("mentions-legales/", views.mentions_legales, name="mentions_legales"),
path("politique-de-confidentialite/", views.politique_de_confidentialite, name="politique_de_confidentialite"),
Expand Down
Loading

0 comments on commit cf9bc6e

Please sign in to comment.