Repository: zestedesavoir/zds-site

Issue:
La date de dernière mise à jour d'un tuto est fausse
La date de dernière mise à jour d'un tuto n'est pas mise à jour lorsqu'on modifie les extraits du tutoriel.

Ce qui fait donc que la date de dernière mise à jour affichée est souvent fausse. Et peut porter à confusion



Discussion:
Je prends.


Resolving patch:
diff --git a/zds/tutorial/views.py b/zds/tutorial/views.py
--- a/zds/tutorial/views.py
+++ b/zds/tutorial/views.py
@@ -1079,7 +1079,6 @@ def add_tutorial(request):
             # add create date
 
             tutorial.create_at = datetime.now()
-            tutorial.pubdate = datetime.now()
 
             # Creating the gallery
 
@@ -2737,6 +2736,8 @@ def maj_repo_part(
 
     repo = Repo(part.tutorial.get_path())
     index = repo.index
+    # update the tutorial last edit date
+    part.tutorial.update = datetime.now()
     if action == "del":
         shutil.rmtree(old_slug_path)
         msg = _(u"Suppresion de la partie : «{}»").format(part.title)
@@ -2798,9 +2799,13 @@ def maj_repo_chapter(
     if chapter.tutorial:
         repo = Repo(os.path.join(settings.ZDS_APP['tutorial']['repo_path'], chapter.tutorial.get_phy_slug()))
         ph = None
+        # update the tutorial last edit date
+        chapter.tutorial.update = datetime.now()
     else:
         repo = Repo(os.path.join(settings.ZDS_APP['tutorial']['repo_path'], chapter.part.tutorial.get_phy_slug()))
         ph = os.path.join(chapter.part.get_phy_slug(), chapter.get_phy_slug())
+        # update the tutorial last edit date
+        chapter.part.tutorial.update = datetime.now()
     index = repo.index
     if action == "del":
         shutil.rmtree(old_slug_path)
@@ -2875,9 +2880,14 @@ def maj_repo_extract(
     if extract.chapter.tutorial:
         repo = Repo(os.path.join(settings.ZDS_APP['tutorial']['repo_path'],
                                  extract.chapter.tutorial.get_phy_slug()))
+        # update the tutorial last edit date
+        extract.chapter.tutorial.update = datetime.now()
+
     else:
         repo = Repo(os.path.join(settings.ZDS_APP['tutorial']['repo_path'],
                                  extract.chapter.part.tutorial.get_phy_slug()))
+        # update the tutorial last edit date
+        extract.chapter.part.tutorial.update = datetime.now()
     index = repo.index
 
     chap = extract.chapter


Test patch:
diff --git a/zds/tutorial/tests/tests.py b/zds/tutorial/tests/tests.py
--- a/zds/tutorial/tests/tests.py
+++ b/zds/tutorial/tests/tests.py
@@ -4,6 +4,8 @@
 import shutil
 import tempfile
 import zipfile
+import datetime
+
 from git import Repo
 try:
     import ujson as json_reader
@@ -2483,6 +2485,126 @@ def test_workflow_archive_tuto(self):
         os.remove(draft_zip_path)
         os.remove(online_zip_path)
 
+    def test_change_update(self):
+        """test the change of `tutorial.update` if part/chapter/extract are modified (ensure #1715) """
+
+        # login with author
+        self.assertEqual(
+            self.client.login(
+                username=self.user_author.username,
+                password='hostel77'),
+            True)
+
+        time_0 = datetime.datetime.fromtimestamp(0)  # way deep in the past
+        tutorial = Tutorial.objects.get(pk=self.bigtuto.pk)
+        tutorial.update = time_0
+        tutorial.save()
+
+        # first, ensure the modification
+        tutorial = Tutorial.objects.get(pk=self.bigtuto.pk)
+        self.assertEqual(tutorial.update, time_0)
+
+        # add part (implicit call to `maj_repo_part()`)
+        result = self.client.post(
+            reverse('zds.tutorial.views.add_part') + '?tutoriel={}'.format(tutorial.pk),
+            {
+                'title': u"Une nouvelle partie",
+                'introduction': "Expérimentation",
+                'conclusion': "C'est terminé",
+                'msg_commit': u"Nouvelle partie"
+            },
+            follow=False)
+
+        tutorial = Tutorial.objects.get(pk=self.bigtuto.pk)
+        self.assertNotEqual(tutorial.update, time_0)
+        tutorial.update = time_0
+        tutorial.save()
+
+        # edit part (implicit call to `maj_repo_part()`)
+        part = Part.objects.filter(tutorial=tutorial).last()
+        result = self.client.post(
+            reverse('zds.tutorial.views.edit_part') + '?partie={}'.format(part.pk),
+            {
+                'title': u"Cette partie a changé de nom",
+                'introduction': u"Expérimentation : edition d'introduction",
+                'conclusion': u"C'est terminé : edition de conlusion",
+                'msg_commit': u"Changement de la partie",
+                "last_hash": compute_hash([os.path.join(part.tutorial.get_path(), part.introduction),
+                                           os.path.join(part.tutorial.get_path(), part.conclusion)])
+            },
+            follow=True)
+        self.assertEqual(result.status_code, 200)
+
+        tutorial = Tutorial.objects.get(pk=self.bigtuto.pk)
+        self.assertNotEqual(tutorial.update, time_0)
+        tutorial.update = time_0
+        tutorial.save()
+
+        # add chapter  (implicit call to `maj_repo_chapter()`)
+        result = self.client.post(
+            reverse('zds.tutorial.views.add_chapter') + '?partie={}'.format(part.pk),
+            {
+                'title': u"Cuisine des agrumes sur ZdS",
+                'introduction': "Mon premier chapitre",
+                'conclusion': "Fin de mon premier chapitre",
+                'msg_commit': u"Initialisation du chapitre 1"
+            },
+            follow=False)
+        self.assertEqual(result.status_code, 302)
+
+        tutorial = Tutorial.objects.get(pk=self.bigtuto.pk)
+        self.assertNotEqual(tutorial.update, time_0)
+        tutorial.update = time_0
+        tutorial.save()
+
+        # edit chapter (implicit call to `maj_repo_chapter()`)
+        chapter = Chapter.objects.filter(part=part).last()
+        result = self.client.post(
+            reverse('zds.tutorial.views.edit_chapter') + '?chapitre={}'.format(chapter.pk),
+            {
+                'title': u"Le respect des agrumes sur ZdS",
+                'introduction': u"Edition d'introduction",
+                'conclusion': u"Edition de conlusion",
+                'msg_commit': u"MàJ du chapitre 2 : le respect des agrumes sur ZdS",
+                "last_hash": compute_hash([
+                    os.path.join(chapter.get_path(), "introduction.md"),
+                    os.path.join(chapter.get_path(), "conclusion.md")])
+            },
+            follow=True)
+        self.assertEqual(result.status_code, 200)
+
+        tutorial = Tutorial.objects.get(pk=self.bigtuto.pk)
+        self.assertNotEqual(tutorial.update, time_0)
+        tutorial.update = time_0
+        tutorial.save()
+
+        # add another extract (implicit call to `maj_repo_extract()`)
+        result = self.client.post(
+            reverse('zds.tutorial.views.add_extract') + '?chapitre={0}'.format(chapter.pk),
+            {
+                'title': u'Un second extrait',
+                'text': u'Comment extraire le jus des agrumes ? Est-ce torturer Clem ?'
+            })
+        self.assertEqual(result.status_code, 302)
+
+        tutorial = Tutorial.objects.get(pk=self.bigtuto.pk)
+        self.assertNotEqual(tutorial.update, time_0)
+        tutorial.update = time_0
+        tutorial.save()
+
+        # edit extract (implicit call to `maj_repo_extract()`)
+        extract = chapter.get_extracts()[0]
+        result = self.client.post(
+            reverse('zds.tutorial.views.edit_extract') + '?extrait={}'.format(extract.pk),
+            {
+                'title': u"Extrait 2 : edition de titre",
+                'text': u"On ne torture pas les agrumes !",
+                "last_hash": compute_hash([os.path.join(extract.get_path())])
+            },
+            follow=True)
+        self.assertEqual(result.status_code, 200)
+        self.assertNotEqual(Tutorial.objects.get(pk=self.bigtuto.pk), time_0)
+
     def tearDown(self):
         if os.path.isdir(settings.ZDS_APP['tutorial']['repo_path']):
             shutil.rmtree(settings.ZDS_APP['tutorial']['repo_path'])
@@ -4030,6 +4152,53 @@ def test_help_to_perfect_tuto(self):
             tutos = response.context['tutorials']
             self.assertEqual(len(tutos), 1)
 
+    def test_change_update(self):
+        """test the change of `tutorial.update` if extract is modified (ensure #1715)"""
+
+        # login with author
+        self.assertEqual(
+            self.client.login(
+                username=self.user_author.username,
+                password='hostel77'),
+            True)
+
+        time_0 = datetime.datetime.fromtimestamp(0)  # way deep in the past
+        tutorial = Tutorial.objects.get(pk=self.minituto.pk)
+        tutorial.update = time_0
+        tutorial.save()
+
+        # first check if this modification is performed :
+        self.assertEqual(Tutorial.objects.get(pk=self.minituto.pk).update, time_0)
+
+        # test adding a new extract (implicit call to `maj_repo_extract()`)
+        result = self.client.post(
+            reverse('zds.tutorial.views.add_extract') +
+            '?chapitre={0}'.format(
+                self.chapter.pk),
+            {
+                'title': u'Un deuxieme extrait',
+                'text': u'Attention aux épines, ça pique !!'
+            })
+        self.assertEqual(result.status_code, 302)
+
+        tutorial = Tutorial.objects.get(pk=self.minituto.pk)
+        self.assertNotEqual(tutorial.update, time_0)
+        tutorial.update = time_0
+        tutorial.save()
+
+        # test the extract edition (also implicit call to `maj_repo_extract()`) :
+        extract = self.chapter.get_extracts().last()
+        result = self.client.post(
+            reverse('zds.tutorial.views.edit_extract') + '?extrait={}'.format(extract.pk),
+            {
+                'title': u"Un autre titre",
+                'text': u"j'ai changé d'avis, je vais mettre un sapin synthétique",
+                "last_hash": compute_hash([extract.get_path()])
+            },
+            follow=True)
+        self.assertEqual(result.status_code, 200)
+        self.assertNotEqual(Tutorial.objects.get(pk=self.minituto.pk).update, time_0)
+
     def tearDown(self):
         if os.path.isdir(settings.ZDS_APP['tutorial']['repo_path']):
             shutil.rmtree(settings.ZDS_APP['tutorial']['repo_path'])