Repository: zestedesavoir/zds-site

Issue:
Il n'y a plus d'alertes sur les messages non lus
Je n'ai plus d'alertes (entendez par là la petite boite rouge sur l'icone des messages) qui m'indique le nombre de MP non lus.

Il s'agit d'une regression introduit avec la 1.5 que je qualifierait de bloquante quand même car la fonctionnalité est très utilisée.

Screen : 

![new_member](https://cloud.githubusercontent.com/assets/6066015/5916651/a31a48e6-a613-11e4-8a76-d9a4382dc2fe.PNG)



Discussion:
@firm1 j'ai bien le nombre sur la version de dev et la préprod ...

Screen or it didn't happen :)

Quand j'envoie des mp avec les différents utilisateurs de ma version dev ça fonctionne. Par contre lorsque que je publie un article ou un tutoriel je retrouve le bug pour l'auteur de la publi, le mp est marqué non lu mais pas d'alerte sur la top bar.

On dirait que la PR qui a cassé la fonctionnalité [est la suivante](https://github.com/zestedesavoir/zds-site/pull/2093), si ça peut aider

La encore, si on ne trouve pas de solution je peux fournir le revert...

Ouais, enfin... entre le bout de code qui est en train d'exploser le serveur et celui qui n'affiche pas de notification dans certains cas, je ne suis pas certain de savoir lequel je préfère...

En tout cas je confirme, c'est bien ca qui fout le boxon (j'ai fait le revert en local, tout est rentré dans l'ordre)

D'autre part, je ne m'explique pas la différence qu'il peut y avoir entre un "vrai" MP et un MP auto. Parce que si j'ai bien compris, c'est les notifications des MP auto qui déconnent.

Ce qui sous-entendrait qu'on a un problème dans l'envoi de MP auto qui ne fonctionne pas comme prévu.

PS : Je ne nie pas que le problème est apparu avec ma PR hein.

Par contre je me demande vraiment :
- Si le problème vient de la "nouvelle" méthode de récupération des MP non lus ou s'il vient de la méthode d'envoi des MP automatiques.
- S'il vaut mieux avoir cette fonctionnalité ou s'il vaut mieux alléger la charge du serveur.

Les deux questions sont de vraies questions ; je me penche sur la première ce WE si personne n'y touche d'ici là.

D'après mon enquête (2-3 tests en preprod) il s'avère que le problème ne survient pas "pour les mp automatiques" mais plutot **pour les MPs ou je suis le seul participant**.

Donc les MP autos rentrent dans la clause, mais si quelqu'un envoi un mp puis se désinscrit, il tombe dans la même case et le bug apparait.

My 2 cents

Ah tiens oui je confirme que c'est juste le MP auto qui déconne... Du coup c'est "moins grave mais dommage quand meme".

Petit tip pour pas faire deux fois la requete (d'apres ton commentaire),

```
    topics = list(privatetopics_unread)
    return {'unread': topics, 'total': len(topics)}
```

Comme ca `list` fera la requete et ensuite `len` fera le comptage du truc récupéré

Ok j'arrive à reproduire le bug partout, il suffit de créer un nouveau mp avec un participant et de le quitter.

Merci @Eskimon  pour le tip.

@firm1 ah oui, j'avais complètement oublié qu'un MP pouvait avoir un seul participant. sans être lu... du coup ça ne m'étonne pas que ce cas ne soit pas géré. Merci pour l'info, maintenant qu'on sait d'où ça vient ça va être beaucoup plus simple à corriger !

> pour les MPs ou je suis le seul participant.

Je confirme completement ce point... J'ai fait un MP avec admin et user, envoyé une réponse avec user puis virer user de la conversation. Je rafraichit alors l'accueil pour admin et je ne vois pas la notif.

good job tout le monde les gens !

Note : on peut aussi accéder à la taille d'une `list` ou d'un `dict` (et d'un `tuple` / `str`) via `{{ foor|lenght }}` dans les templates. Ça reste toujours moins performant qu'un `len()`.


Resolving patch:
diff --git a/zds/utils/templatetags/interventions.py b/zds/utils/templatetags/interventions.py
--- a/zds/utils/templatetags/interventions.py
+++ b/zds/utils/templatetags/interventions.py
@@ -137,7 +137,7 @@ def interventions_privatetopics(user):
         '''
         select distinct t.*
         from mp_privatetopic t
-        inner join mp_privatetopic_participants p on p.privatetopic_id = t.id
+        left outer join mp_privatetopic_participants p on p.privatetopic_id = t.id
         left outer join mp_privatetopicread r on r.user_id = %s and r.privatepost_id = t.last_message_id
         where (t.author_id = %s or p.user_id = %s)
           and r.id is null
@@ -145,7 +145,8 @@ def interventions_privatetopics(user):
         [user.id, user.id, user.id])
 
     # "total" re-do the query, but there is no other way to get the length as __len__ is not available on raw queries.
-    return {'unread': privatetopics_unread, 'total': len(list(privatetopics_unread))}
+    topics = list(privatetopics_unread)
+    return {'unread': topics, 'total': len(topics)}
 
 
 @register.filter(name='alerts_list')


Test patch:
diff --git a/zds/utils/templatetags/tests/tests_interventions.py b/zds/utils/templatetags/tests/tests_interventions.py
new file mode 100644
--- /dev/null
+++ b/zds/utils/templatetags/tests/tests_interventions.py
@@ -0,0 +1,38 @@
+# coding: utf-8
+
+from django.test import TestCase
+
+from zds.member.factories import ProfileFactory
+from zds.mp.factories import PrivateTopicFactory, PrivatePostFactory
+from zds.utils.templatetags.interventions import interventions_privatetopics
+
+
+class InterventionsTest(TestCase):
+
+    def setUp(self):
+        self.author = ProfileFactory()
+        self.user = ProfileFactory()
+        self.topic = PrivateTopicFactory(author=self.author.user)
+        self.topic.participants.add(self.user.user)
+        self.post = PrivatePostFactory(
+            privatetopic=self.topic,
+            author=self.author.user,
+            position_in_topic=1)
+
+    def test_interventions_privatetopics(self):
+        result = interventions_privatetopics(self.author)
+        self.assertEqual(result['total'], 1)
+
+        result = interventions_privatetopics(self.user)
+        self.assertEqual(result['total'], 1)
+
+    def test_interventions_privatetopics_author_leave(self):
+
+        # profile1 (author) leave topic
+        move = self.topic.participants.first()
+        self.topic.author = move
+        self.topic.participants.remove(move)
+        self.topic.save()
+
+        result = interventions_privatetopics(self.user)
+        self.assertEqual(result['total'], 1)