Skip to content

Commit

Permalink
add ForumStatWeekArchiveView
Browse files Browse the repository at this point in the history
  • Loading branch information
vincentporte committed Jul 1, 2024
1 parent bd713df commit cebc306
Show file tree
Hide file tree
Showing 5 changed files with 433 additions and 6 deletions.
96 changes: 96 additions & 0 deletions lacommunaute/stats/tests/__snapshots__/tests_views.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,102 @@
</nav>
'''
# ---
# name: TestForumStatWeekArchiveView.test_header_and_breadcrumb[breadcrumb]
'''
<nav aria-label="Fil d'ariane" class="c-breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">Retourner vers</li>
<li class="breadcrumb-item">
<a href="/statistiques/">Statistiques</a>
</li>
</ol>
</nav>
'''
# ---
# name: TestForumStatWeekArchiveView.test_header_and_breadcrumb[title-01]
'''
<section class="s-title-01 mt-lg-5">
<div class="s-title-01__container container">
<div class="s-title-01__row row">
<div class="s-title-01__col col-12">
<h1 class="s-title-01__title h1">
<strong>Partenariat Academie France Travail x La communauté de l'inclusion</strong>
<br/>
Statistiques de la semaine du 20 mai 2024 au 26 mai 2024
</h1>
</div>
</div>
</div>
</section>
'''
# ---
# name: TestForumStatWeekArchiveView.test_most_rated_forums[most_rated_forums]
'''
<div class="s-section__row row" id="most_rated">
<div class="s-section__col col-12">
<div class="c-box mb-3 mb-md-5">
<h2>Les 1 fiches pratiques les plus notées sur la période</h2>
<table class="table">
<thead>
<tr>
<th scope="col">Fiche Pratique</th>
<th scope="col">Nouvelles otations sur la période</th>
<th scope="col">Evaluation globale</th>
</tr>
</thead>
<tbody>

<tr>
<th scope="row">Forum A</th>
<td>2</td>
<td>3,00</td>
</tr>

</tbody>
</table>
</div>
</div>
</div>
'''
# ---
# name: TestForumStatWeekArchiveView.test_most_viewed_forums[most_viewed_forums]
'''
<div class="s-section__row row" id="most_viewed">
<div class="s-section__col col-12">
<div class="c-box mb-3 mb-md-5">
<h2>Les 2 fiches pratiques les plus lues sur la période</h2>
<table class="table">
<thead>
<tr>
<th scope="col">Fiche Pratique</th>
<th scope="col">Visiteurs uniques</th>
<th scope="col">Visiteurs uniques entrants</th>
<th scope="col">Temps de lecture total</th>
</tr>
</thead>
<tbody>

<tr>
<th scope="row">Forum B</th>
<td>17</td>
<td>5</td>
<td>1978 secondes</td>
</tr>

<tr>
<th scope="row">Forum A</th>
<td>10</td>
<td>8</td>
<td>1000 secondes</td>
</tr>

</tbody>
</table>
</div>
</div>
</div>
'''
# ---
# name: TestMonthlyVisitorsView.test_navigation[breadcrumb]
'''
<nav aria-label="Fil d'ariane" class="c-breadcrumb">
Expand Down
105 changes: 103 additions & 2 deletions lacommunaute/stats/tests/tests_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
from django.utils.timezone import localdate
from faker import Faker
from machina.core.loading import get_class
from pytest_django.asserts import assertContains
from pytest_django.asserts import assertContains, assertNotContains

from lacommunaute.forum.factories import ForumFactory, ForumRatingFactory
from lacommunaute.stats.enums import Period
from lacommunaute.stats.factories import StatFactory
from lacommunaute.stats.factories import ForumStatFactory, StatFactory
from lacommunaute.surveys.factories import DSPFactory
from lacommunaute.utils.math import percent
from lacommunaute.utils.testing import parse_response_to_soup
Expand Down Expand Up @@ -243,3 +244,103 @@ def test_navigation(self, client, db, snapshot):
response = client.get(url)
assert response.status_code == 200
assert str(parse_response_to_soup(response, selector=".c-breadcrumb")) == snapshot(name="breadcrumb")


class TestForumStatWeekArchiveView:
def get_url_from_date(self, date):
return reverse(
"stats:forum_stat_week_archive", kwargs={"year": date.strftime("%Y"), "week": date.strftime("%W")}
)

def test_header_and_breadcrumb(self, client, db, snapshot):
response = client.get(self.get_url_from_date(ForumStatFactory(for_snapshot=True).date))
assert response.status_code == 200
assert str(parse_response_to_soup(response, selector=".s-title-01")) == snapshot(name="title-01")
assert str(parse_response_to_soup(response, selector=".c-breadcrumb")) == snapshot(name="breadcrumb")

def test_navigation(self, client, db):
weeks = [date.today() - relativedelta(weeks=i) for i in range(15, 10, -1)]
for week in weeks[1:4]:
ForumStatFactory(date=week, for_snapshot=True)

test_cases = [
{"test_week": weeks[1], "not_contains": [weeks[0]], "contains": [weeks[2]]},
{"test_week": weeks[2], "not_contains": [], "contains": [weeks[1], weeks[3]]},
{"test_week": weeks[3], "not_contains": [weeks[4]], "contains": [weeks[2]]},
]

for test_case in test_cases:
response = client.get(self.get_url_from_date(test_case["test_week"]))
for week in test_case["not_contains"]:
assertNotContains(response, self.get_url_from_date(week))
for week in test_case["contains"]:
assertContains(response, self.get_url_from_date(week))

# out of bound
for week in [weeks[0], weeks[4]]:
response = client.get(self.get_url_from_date(week))
assert response.status_code == 404

def test_most_viewed_forums(self, client, db, snapshot):
forums_stats = [
ForumStatFactory(for_snapshot=True, visits=10, entry_visits=8, time_spent=1000, forum__name="Forum A"),
ForumStatFactory(for_snapshot=True, visits=17, entry_visits=5, time_spent=1978, forum__name="Forum B"),
]

response = client.get(self.get_url_from_date(forums_stats[0].date))
assert response.status_code == 200
assert str(
parse_response_to_soup(
response, selector="#most_viewed", replace_in_href=[fs.forum for fs in forums_stats]
)
) == snapshot(name="most_viewed_forums")

def test_paginated_most_viewed_forums(self, client, db):
ForumStatFactory.create_batch(16, for_snapshot=True)
response = client.get(reverse("stats:forum_stat_week_archive", kwargs={"year": 2024, "week": 21}))
assert response.status_code == 200
assert len(response.context_data["forum_stats"]) == 15

def test_most_rated_forums(self, client, db, snapshot):
fs = ForumStatFactory(for_snapshot=True, forum__name="Forum A")

# rating within range
ForumRatingFactory.create_batch(2, rating=5, forum=fs.forum, set_created=fs.date)
# rating out of range
ForumRatingFactory.create_batch(2, rating=1, forum=fs.forum)

# undesired forum
ForumFactory()

# undesired rating
ForumRatingFactory(rating=4)

response = client.get(self.get_url_from_date(fs.date))
assert response.status_code == 200
assert str(parse_response_to_soup(response, selector="#most_rated")) == snapshot(name="most_rated_forums")

def test_visitors(self, client, db, snapshot):
fs = ForumStatFactory(for_snapshot=True)

# relevant
relevant_dates = [
fs.date,
fs.date + relativedelta(days=6),
fs.date + relativedelta(days=6) - relativedelta(days=89),
]
visitors = [10, 11, 12]
for stat_date, visitor_count in zip(relevant_dates, visitors):
StatFactory(date=stat_date, name="nb_uniq_visitors", value=visitor_count)

# undesired
for stat_date in [fs.date + relativedelta(weeks=1), fs.date + relativedelta(days=6) - relativedelta(days=90)]:
StatFactory(date=stat_date, name="nb_uniq_visitors", value=99)

response = client.get(self.get_url_from_date(fs.date))
assert response.status_code == 200
expected_stats = {
"date": ["2024-02-27", "2024-05-20", "2024-05-26"],
"nb_uniq_visitors": [12, 10, 11],
"nb_uniq_engaged_visitors": [],
}
assert response.context_data["stats"] == expected_stats
3 changes: 2 additions & 1 deletion lacommunaute/stats/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.urls import path

from lacommunaute.stats.views import DailyDSPView, MonthlyVisitorsView, StatistiquesPageView
from lacommunaute.stats.views import DailyDSPView, ForumStatWeekArchiveView, MonthlyVisitorsView, StatistiquesPageView


app_name = "stats"
Expand All @@ -9,4 +9,5 @@
path("", StatistiquesPageView.as_view(), name="statistiques"),
path("monthly-visitors/", MonthlyVisitorsView.as_view(), name="monthly_visitors"),
path("dsp/", DailyDSPView.as_view(), name="dsp"),
path("aft/<int:year>/<int:week>/", ForumStatWeekArchiveView.as_view(), name="forum_stat_week_archive"),
]
47 changes: 44 additions & 3 deletions lacommunaute/stats/views.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import datetime
import logging

from dateutil.relativedelta import relativedelta
from django.db.models import CharField
from django.db.models import Avg, CharField, Count, Q
from django.db.models.functions import Cast
from django.utils import timezone
from django.utils.dateformat import format
from django.utils.timezone import localdate
from django.views.generic.base import TemplateView
from django.views.generic.dates import WeekArchiveView

from lacommunaute.stats.models import Stat
from lacommunaute.forum.models import Forum
from lacommunaute.stats.models import ForumStat, Stat
from lacommunaute.surveys.models import DSP
from lacommunaute.utils.json import extract_values_in_list
from lacommunaute.utils.math import percent
Expand Down Expand Up @@ -119,3 +121,42 @@ class DailyDSPView(BaseDetailStatsView):
indicator_names = ["dsp"]
period = "day"
months = 3


class ForumStatWeekArchiveView(WeekArchiveView):
template_name = "stats/forum_stat_week_archive.html"
date_field = "date"
queryset = ForumStat.objects.filter(period="week").select_related("forum")
week_format = "%W"
make_object_list = True
context_object_name = "forum_stats"
ordering = ["date", "-visits"]
paginate_by = 15

def get_dates_of_the_week(self):
start_date = datetime.date(self.get_year(), 1, 1) + datetime.timedelta(weeks=self.get_week() - 1)
return start_date, start_date + datetime.timedelta(days=6)

def get_most_rated_forums(self, start_date, end_date):
return (
Forum.objects.annotate(avg_rating=Avg("forumrating__rating"))
.filter(avg_rating__isnull=False)
.annotate(
rating_count=Count(
"forumrating",
filter=Q(
forumrating__created__gte=start_date, forumrating__created__lt=end_date + relativedelta(days=1)
),
)
)
.filter(rating_count__gt=1)
.order_by("-rating_count", "avg_rating", "id")
)

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
start_date, end_date = self.get_dates_of_the_week()
context["end_date"] = end_date
context["stats"] = get_daily_visits_stats(from_date=end_date - relativedelta(days=89), to_date=end_date)
context["rated_forums"] = self.get_most_rated_forums(start_date, end_date)
return context
Loading

0 comments on commit cebc306

Please sign in to comment.