From fa3ccdab70240cbce2fbe65f14561fe7ecd443f7 Mon Sep 17 00:00:00 2001 From: Calum Mackervoy Date: Mon, 17 Jun 2024 18:58:08 +0200 Subject: [PATCH 1/3] =?UTF-8?q?feat(forum=5Fstats):=20mod=C3=A8les=20pour?= =?UTF-8?q?=20le=20stockage=20des=20recherches?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0002_searchcollectionperiod_usersearch.py | 49 ++++++++++++++++++ lacommunaute/forum_stats/models.py | 37 +++++++++++++ .../tests/tests_search_collection.py | 0 locale/fr/LC_MESSAGES/django.mo | Bin 15155 -> 15789 bytes locale/fr/LC_MESSAGES/django.po | 41 +++++++++++++++ 5 files changed, 127 insertions(+) create mode 100644 lacommunaute/forum_stats/migrations/0002_searchcollectionperiod_usersearch.py create mode 100644 lacommunaute/forum_stats/tests/tests_search_collection.py diff --git a/lacommunaute/forum_stats/migrations/0002_searchcollectionperiod_usersearch.py b/lacommunaute/forum_stats/migrations/0002_searchcollectionperiod_usersearch.py new file mode 100644 index 000000000..1e6bb599b --- /dev/null +++ b/lacommunaute/forum_stats/migrations/0002_searchcollectionperiod_usersearch.py @@ -0,0 +1,49 @@ +# Generated by Django 5.0.6 on 2024-06-17 16:54 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("forum_stats", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="SearchCollectionPeriod", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("name", models.CharField(max_length=256, verbose_name="Name")), + ("start_date", models.DateField(help_text="The start of the period", verbose_name="Start date")), + ("end_date", models.DateField(help_text="The end of the period", verbose_name="End date")), + ], + options={ + "verbose_name": "Search Collection Period", + "verbose_name_plural": "Search Collection Periods", + "ordering": ["-end_date", "-start_date"], + "unique_together": {("start_date", "end_date")}, + }, + ), + migrations.CreateModel( + name="SearchQuery", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("label", models.TextField(help_text="The search query made by the user")), + ("nb_visits", models.PositiveIntegerField(verbose_name="Number visits")), + ( + "period", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="searches", + to="forum_stats.searchcollectionperiod", + ), + ), + ], + options={ + "verbose_name": "Search Query", + "verbose_name_plural": "Search Queries", + "ordering": ["-period", "label"], + }, + ), + ] diff --git a/lacommunaute/forum_stats/models.py b/lacommunaute/forum_stats/models.py index dd01c2cba..8857653f9 100644 --- a/lacommunaute/forum_stats/models.py +++ b/lacommunaute/forum_stats/models.py @@ -1,4 +1,5 @@ from django.db import models +from django.utils.translation import gettext_lazy as _ from lacommunaute.forum_stats.enums import Period @@ -31,3 +32,39 @@ def __str__(self): return f"{self.name} - {self.date} - {self.period}" objects = StatQuerySet().as_manager() + + +class SearchCollectionPeriod(models.Model): + name = models.CharField(max_length=256, verbose_name=_("Name")) + start_date = models.DateField(verbose_name=_("Start date"), help_text=_("The start of the period")) + end_date = models.DateField(verbose_name=_("End date"), help_text=_("The end of the period")) + + class Meta: + verbose_name = _("Search Collection Period") + verbose_name_plural = _("Search Collection Periods") + ordering = ["-end_date", "-start_date"] + unique_together = ("start_date", "end_date") + + def __str__(self): + return f"Period {str(self.name)} ({str(self.start_date)} - {str(self.end_date)})" + + +class SearchQuery(models.Model): + """ + Matomo logs for us the searches made by users visiting the site. + We collect searches made during a period and store them for interpretation + """ + + label = models.TextField(help_text=_("The search query made by the user")) + period = models.ForeignKey( + SearchCollectionPeriod, related_name="searches", on_delete=models.CASCADE, db_index=True + ) + nb_visits = models.PositiveIntegerField(verbose_name=_("Number visits")) + + class Meta: + verbose_name = _("Search Query") + verbose_name_plural = _("Search Queries") + ordering = ["-period", "label"] + + def __str__(self): + return f"Search from {str(self.period)}" diff --git a/lacommunaute/forum_stats/tests/tests_search_collection.py b/lacommunaute/forum_stats/tests/tests_search_collection.py new file mode 100644 index 000000000..e69de29bb diff --git a/locale/fr/LC_MESSAGES/django.mo b/locale/fr/LC_MESSAGES/django.mo index 00fb78b10cbaf59c1c6e50de8296566b3ea68779..6729052621242dc19ab98ae08ca023611b0ec5f1 100644 GIT binary patch delta 5207 zcmZYC33OD|0mku52nkyPN!TM{*a@o;49KD^DT_jgfPoZQvP{T87BX4b)KNeXM4$w; z4F(VafeIA|P*$r!qy}&ymaV0&_TV{EJ%CFsEj|5z@7<}}JACuI@6MaM&j7*ly^8}^ zW5YKZt}Em&@^yqUo$DBLCQ7x&%!)OpH)i79xDNZ`Td3#1!ZFx1&X{JHVJ*al+%LsO zxCYx{B~Hg9c+{AHX~n0GQ&EdCxW2hDO>jFl#RK;K9n_dU#%TN$Bk>kC#@pBfBU>2L z9g|S^GjJ@f!bGgK@Bh~^KxIq!!O2*k2cAHUcqOWXjmTh46{@5C))S}!)nHG&gd;Gb zmD|o(WHHS|)POTk6U##u%`CuH^lzS_z+lXF)CwF$&HOBC09P>_uVF{Lj%v6`Yj;2` zPy_C0@B5%WHw3i>DX5MoSZ87b?u#&>h8I#$!;hmzwhc9)gQy43pl1F@WR=aQsFnH` zY9L{4jH!nWP%F{|HK4Yr2_>SQ8;nUf!rqs+(f(8M7!?}fbEui`M9tuJ)BxW^b#M~( z+w^%MApg1(ogtuY?(Undp=Y@^HCFB)`9ic zNS~)d9aN$2w_$hOg__ZM)FBMxS1K6?VG=~iS-{-$C$rSaW56!yBKp1=HUHUiS%tQ<5awZ+UxYL?%|q)+T*3DAEq^!h?{W^ zp2mHc)XkVz@e|Zxt>7WPcxHcqf==l<)RKILTC&@yj_R@u4X`C@kK1EkOt$7BkD5wM z!;{zpoAWXZhodI81htaKQ0-qw4LI;Mg=h-lJ&j>Qi(QPlT( z32M(bqgEh@O|S;l@D#7+(Ip7efC2ih(`^eAF6{9SQjUtR&bJie>TQ)Ki|3vIhUpiWAHTU`OE#-f9>6u zROl4{2i0+xBzG%@SjVF}oPpYsxu}`VM>V(>HS-ryOMM8nqE}Ie^cr@?o2Y(T_Gh(m zcz@P^EQLc46SS~V=fLTnTITb6ARWViA3eO`4+WZ4`INS2&RsB%xgXySm%W~9`u10Oa z7E}j2Q3F4U&RMYa*HA0=Z;YjX(`JzSFP~l*&Ks%N5+`9a&b9Z8@E6>#M{U7H>)%l` zyMdbdZPd&g4|bQ@gKBq(bvSB;M`0rUo9PsK;tJFX96+|qe2zV^{SbFX<1vx@EYwf% zYFvgNAP3t#Jk)J?C5Cao6*aJzkiX-czw>p5^ch`z%mfzjGMDhH>MUzloIyS$xkT4O zGK{n#p)11{G?0&pX7mA}FXwuf*YPBtOmk}7!9PLyO>&&vul?6`h@2pN{hfbEti)YJ z`#Fl}92AmQiLU3#DW}B$9q=w&-h(@BdAaqcoTEb9>t6J~)E51CkmzfogVTxp@Zubr z`L<#L>JXhKm9}mzYX5aTOZGV>ckf@a<<_{JOeSN<6wSYabR@dc$!OA!^d^5Gp=%BW z9l+m{*T`9Nl>CN-u4gE0BITh9)Y;HEx@_yl;T4ic0^4}mPu7uHRL&hrc8RajYtkTK-Q2Nl2114{B@@A6lp~!lDcFusYgOw-Xwp1Q-X$!nO%GR*K_qlFqp-u? zJcMn@%j6vrMII-iE0)4;@|>**T9a|TEf27Y!(=PTCb|Okd6`G<{i&Q=V$?e}#kHa+tX%_-ss7WMpBECnvMi8|>D4 zOITEDSwWW9?m?jo_3NmxNo~(t= zGi4=Szj2-@&7_?leKI(r-Q4I#DNMt|2XcLd!B={X3Xe%GD#-FXRnCOGCBd70Z-=E% z^k(OInSs}nR=ry@avsTc=jk=yzs(z=CrZ@t&mSrI{^{W7{X5i&4vitFdUsY?X+@*t z**W7fH6ndJKhrbM_GqZ}dyC7e_qb#B|9?#0++3Esta>-glIi#4cP%UR<@-vQTbbXC RW2jEcKWQ#locwn9{{S0NYUls} delta 4585 zcmYkUL&1_&Da`UhIQSsO!7NnU&%|Ou#B<4MuSsz}EN{cE&?^ z1O9}&%{(iOH`~LBFz%*J+mCIq5!>Ro?)XnspIWvzi^X`1z;ukpUYLc2*b67QfBSSq@4F}A`wRFB_4J>US+M>~Rg(AUmiQ5`yu*%;ZuY%ms}+PM>% zOk0HNa20A`Pa%W1ZJ5OKZ8sI#utwAjoJEcNA5;foljt=jVpr^lYPbZ|p<$>FU+s>^ zqwbrDT7tQ#2Yb%t7|HQE^we-I6*asA)w7RL9r_M+;oqnSg(sUaix!XSKqj`tT+~by zpgJ-HHIQ=DbrZ24PIJd=ktS_ZGV8CN?csz*d<50=FHs%)9`%5;sOy?g9SlkFj}uTG z?1s87$C-zk@?z8sl)3YxP|vA!&PZYYwYGP=6V<2=Y;ec5sFByB9@Kzp@EGd4Q||a% z)X0BBb^JVP4_HUvNYs6CsCGJ`I?}_Vq6ZYY3x=X@EJyycvHa0U=Aj<27sdC55Q5}5}HNYBV;GS)zqRq3@eXt*O;RpT&cHAAGcAi20 zv)}on4#r;KKQJEEP710cJyA2;*I9y^q03Pn9Ea_BzD=g0DOrf!a1Clt>_tswBdS9` zqDI<;dcfcAIGmf+U^~?LB-AENM|CJ4)A3SdHEas1-9?z=QCUqzQ*{v4dy)zZ{TF=2eT#B9=e4C1FK&{P(s0Kep zHTXShM1P<<8cuKYfN0clJM4uWFb4;t_RuUWz*^M%e;UfH=E9hLfnDRVI5ZV@Hbm%Pyg304b{*9)QpV5RyYmypxLNBumrWn)z}9& zJ5OLH$C3Og$9^7_EGmm}Al9Kq)`XhMEatTpR-$@531e{%(nni_nyFg%c|B^+975fH z3NOXhJR}N7qL#W6b)7enih4fRop=~E!e=lU1I{C;>wZ8ra2~_4MK-S(MqwllKz&aP zM?GLXYNlqP2C^8n2bLl2d$z`1u*-e$9;)F_P&4rbvb@&eLf`(Vj@*bE`8?E2EWv2p zj;*mC*(P=nwd;REULXr$T6A3(?4$QThl+mHCLqgg^HDvoL4DEGp?ZE4HS!bK62C&d z&)=ceI;6Kh@3! z#&BGL>`NPudTe8?u@TkqJIH>sQ>a}Y%@?_5Bo4KUGf)j>qdGPS^`M*F`I)Hi_WM!yt;aMBU>G)H z2RwV`9@ugth&zO8T!vXAU@RKsm9_J5SRqdJy}{3Zqe?SC8c zBWG_Anz8GNUOg4Ctc{Nz`AF3(bO@@=P?))}n((I@^K7{X* z$H{22lBm2)LW4D4S=6X|5^YqK&BW7MtRkB7X=DL;p9~>Skq3#US8F|oJWXbjF+@c_ z+u9e~$qI50sU%O5<}%k+SP8p?tRbDr0ImP?RF;wEq8U+n!YBCm1y>(|TgZjvJ@Ob? zNEVUiaxIk{GKH`*!JprUu!Lx1{=Yn@^;g+RUL!R+plIDy(#QdFC()j$CASk5eJ|`M z0Uc1{i8h$ZYVr}8K-LqLD6*VruO*UXa-W_*nT#ST2gxHOLkE;+eS-hXtmb0{J(7AU?~|&?sp%|!+LUz1jo;NXemTxlaEbx_HahvRj%I5J5;hr9l4pj zNxBk!)0GpI!#;L7K1^;TH<5K@iF>|1%E2I_l0;gPiKKz36#LjKcq`dRrjr-RY;uIC zOdrdK}*U8mHWrmN9!;Y>#60daiway2y6Df7a zcVHPA=8na6B$9kc_L2ES<)vKybR+T_(w?ZiMS7FFNepQ&vjR87t&Iq@NLd>i*pXTp ty7HRN$5-a3T@^TyHZ?XdqW93Sz=nQ*g$9}mx`eFkQZyy-bJ4!A{{Vblt|$Ni diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 07b07876b..063dedc77 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -46,6 +46,46 @@ msgstr "Motif du blocage" msgid "Poster" msgstr "Auteur" +#: lacommunaute/forum_stats/models.py +msgid "Start date" +msgstr "Date de début" + +#: lacommunaute/forum_stats/models.py +msgid "The start of the period" +msgstr "Le début de la période" + +#: lacommunaute/forum_stats/models.py +msgid "End date" +msgstr "Date de fin" + +#: lacommunaute/forum_stats/models.py +msgid "The end of the period" +msgstr "La fin de la période" + +#: lacommunaute/forum_stats/models.py +msgid "Search Collection Period" +msgstr "Recherche Période de collecte" + +#: lacommunaute/forum_stats/models.py +msgid "Search Collection Periods" +msgstr "Recherche de Périodes de collecte" + +#: lacommunaute/forum_stats/models.py +msgid "The search query made by the user" +msgstr "La requête de recherche effectuée par l'utilisateur" + +#: lacommunaute/forum_stats/models.py +msgid "Number visits" +msgstr "Nombre de visites" + +#: lacommunaute/forum_stats/models.py +msgid "Search Query" +msgstr "Recherche" + +#: lacommunaute/forum_stats/models.py +msgid "Search Queries" +msgstr "Recherches" + #: lacommunaute/search/forms.py:24 msgid "Keywords or phrase" msgstr "Mots clés ou phrase" @@ -77,6 +117,7 @@ msgid "Global forum permissions" msgstr "Autorisations globales des communautés" #: lacommunaute/templates/admin/forum/forum/change_list_table.html:9 +#: lacommunaute/forum_stats/models.py msgid "Name" msgstr "Nom" From 5d6dc1e6aa14ab5a51c2a477e449242c267fe48d Mon Sep 17 00:00:00 2001 From: Calum Mackervoy Date: Tue, 18 Jun 2024 10:29:08 +0200 Subject: [PATCH 2/3] feat(forum_stats): ajout des recherches au site admin --- lacommunaute/forum_stats/admin.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lacommunaute/forum_stats/admin.py b/lacommunaute/forum_stats/admin.py index ad7d441cf..66197245e 100644 --- a/lacommunaute/forum_stats/admin.py +++ b/lacommunaute/forum_stats/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from lacommunaute.forum_stats.models import Stat +from lacommunaute.forum_stats.models import SearchCollectionPeriod, SearchQuery, Stat class StatAdmin(admin.ModelAdmin): @@ -8,4 +8,14 @@ class StatAdmin(admin.ModelAdmin): list_filter = ("name", "date", "period") +class SearchCollectionPeriodAdmin(admin.ModelAdmin): + list_display = ("name", "start_date", "end_date") + + +class SearchQueryAdmin(admin.ModelAdmin): + list_display = ("period", "nb_visits") + + admin.site.register(Stat, StatAdmin) +admin.site.register(SearchCollectionPeriod, SearchCollectionPeriodAdmin) +admin.site.register(SearchQuery, SearchQueryAdmin) From 8752857f9f82cfbf47e2f14239ec30ca3e8c1a96 Mon Sep 17 00:00:00 2001 From: Calum Mackervoy Date: Tue, 18 Jun 2024 10:38:53 +0200 Subject: [PATCH 3/3] feat(forum_stats): SearchQueryFactory --- config/settings/base.py | 5 +++++ lacommunaute/forum_stats/factories.py | 27 ++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/config/settings/base.py b/config/settings/base.py index aaa01876b..6e66ad4a7 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -449,3 +449,8 @@ "sync-xhr": [], "usb": [], } + +# forum_stats +# --------------------------------------- + +SEARCH_COLLECTION_PERIOD_DAYS = 30 diff --git a/lacommunaute/forum_stats/factories.py b/lacommunaute/forum_stats/factories.py index 645cca2b6..d7771e30d 100644 --- a/lacommunaute/forum_stats/factories.py +++ b/lacommunaute/forum_stats/factories.py @@ -2,9 +2,10 @@ import factory import factory.django +from django.conf import settings from lacommunaute.forum_stats.enums import Period -from lacommunaute.forum_stats.models import Stat +from lacommunaute.forum_stats.models import SearchCollectionPeriod, SearchQuery, Stat class StatFactory(factory.django.DjangoModelFactory): @@ -23,3 +24,27 @@ class Params: value=46, period="day", ) + + +class SearchCollectionPeriodFactory(factory.django.DjangoModelFactory): + class Meta: + model = SearchCollectionPeriod + + name = factory.Faker("word") + start_date = factory.Faker("date") + + @factory.lazy_attribute + def end_date(self): + return ( + datetime.datetime.strptime(self.start_date, "%Y-%m-%d") + + datetime.timedelta(days=settings.SEARCH_COLLECTION_PERIOD_DAYS) + ).date() + + +class SearchQueryFactory(factory.django.DjangoModelFactory): + class Meta: + model = SearchQuery + + label = factory.Faker("word") + period = factory.SubFactory(SearchCollectionPeriodFactory) + nb_visits = factory.Faker("random_int", min=1, max=10)