From c4bec622b0314f95ab8804fca2e3db5044533273 Mon Sep 17 00:00:00 2001 From: firm1 Date: Sat, 12 Jul 2014 12:24:28 +0200 Subject: [PATCH 01/10] corrections des problemes de maj des tutos --- templates/tutorial/chapter/view.html | 2 +- zds/tutorial/models.py | 31 ++++++++++++-- zds/tutorial/views.py | 62 ++++++++++++++-------------- zds/utils/tutorials.py | 3 ++ 4 files changed, 64 insertions(+), 34 deletions(-) diff --git a/templates/tutorial/chapter/view.html b/templates/tutorial/chapter/view.html index 7404f2788e..793dc0e561 100644 --- a/templates/tutorial/chapter/view.html +++ b/templates/tutorial/chapter/view.html @@ -21,7 +21,7 @@ {% with authors=tutorial.authors.all %}

{% if chapter.image %} - + {% endif %} {{ chapter.title }}

diff --git a/zds/tutorial/models.py b/zds/tutorial/models.py index b718f9e920..1e57bf28b7 100644 --- a/zds/tutorial/models.py +++ b/zds/tutorial/models.py @@ -162,7 +162,8 @@ def in_drafting(self): return (self.sha_draft is not None) and (self.sha_draft.strip() != '') def on_line(self): - return (self.sha_public is not None) and (self.sha_public.strip() != '') + print('--------------> {}'.format(self.sha_public)) + return (self.sha_public is not None) and (self.sha_public.strip() != '') and (self.sha_public.strip() != '') def is_mini(self): return self.type == 'MINI' @@ -196,6 +197,10 @@ def load_dic(self, mandata): mandata['image'] = self.image mandata['pubdate'] = self.pubdate mandata['source'] = self.source + mandata['have_markdown'] = self.have_markdown() + mandata['have_html'] = self.have_html() + mandata['have_pdf'] = self.have_pdf() + mandata['have_epub'] = self.have_epub() return mandata @@ -358,6 +363,22 @@ def update_children(self): if chapter: chapter.update_children() + def have_markdown(self): + return os.path.isfile(os.path.join(self.get_prod_path(), + self.slug + + ".md")) + def have_html(self): + return os.path.isfile(os.path.join(self.get_prod_path(), + self.slug + + ".html")) + def have_pdf(self): + return os.path.isfile(os.path.join(self.get_prod_path(), + self.slug + + ".pdf")) + def have_epub(self): + return os.path.isfile(os.path.join(self.get_prod_path(), + self.slug + + ".epub")) def get_last_tutorials(): tutorials = Tutorial.objects.all()\ @@ -775,8 +796,12 @@ def get_conclusion_online(self): return None def update_children(self): - self.introduction = os.path.join(self.get_phy_slug(), "introduction.md") - self.conclusion = os.path.join(self.get_phy_slug(), "conclusion.md") + if self.part: + self.introduction = os.path.join(self.part.get_phy_slug(), self.get_phy_slug(), "introduction.md") + self.conclusion = os.path.join(self.part.get_phy_slug(), self.get_phy_slug(), "conclusion.md") + else: + self.introduction = os.path.join("introduction.md") + self.conclusion = os.path.join("conclusion.md") self.save() for extract in self.get_extracts(): extract.save() diff --git a/zds/tutorial/views.py b/zds/tutorial/views.py index 2f51933e20..49202020f4 100644 --- a/zds/tutorial/views.py +++ b/zds/tutorial/views.py @@ -726,9 +726,8 @@ def view_tutorial_online(request, tutorial_pk, tutorial_slug): tutorial = get_object_or_404(Tutorial, pk=tutorial_pk) # If the tutorial isn't online, we raise 404 error. - - if not tutorial.on_line: - raise PermissionDenied + if not tutorial.on_line(): + raise Http404 # Two variables to handle two distinct cases (large/small tutorial) @@ -1112,7 +1111,7 @@ def view_part_online( part = get_object_or_404(Part, slug=part_slug, tutorial__pk=tutorial_pk) tutorial = part.tutorial - if not tutorial.on_line: + if not tutorial.on_line(): raise Http404 # find the good manifest file @@ -1260,7 +1259,7 @@ def modify_part(request): tut_p.position_in_tutorial = tut_p.position_in_tutorial - 1 tut_p.save() old_slug = os.path.join(settings.REPO_PATH, part.tutorial.get_phy_slug(), part.get_phy_slug()) - maj_repo_part(request, old_slug_path=old_slug, action="del") + maj_repo_part(request, old_slug_path=old_slug, part=part, action="del") # Actually delete the part @@ -1387,12 +1386,13 @@ def view_chapter( chapter["position_in_part"] = cpt_c chapter["position_in_tutorial"] = cpt_c * cpt_p chapter["get_absolute_url"] = part["get_absolute_url"] \ - + "{0}/".format(chapter["slug"]) + + "{0}/{1}/".format(chapter["pk"], chapter["slug"]) if chapter_pk == str(chapter["pk"]): chapter["intro"] = get_blob(repo.commit(sha).tree, chapter["introduction"]) chapter["conclu"] = get_blob(repo.commit(sha).tree, chapter["conclusion"]) + cpt_e = 1 for ext in chapter["extracts"]: ext["chapter"] = chapter @@ -1411,6 +1411,7 @@ def view_chapter( > 0 else None) next_chapter = (chapter_tab[final_position + 1] if final_position + 1 < len(chapter_tab) else None) + return render_template("tutorial/chapter/view.html", { "tutorial": tutorial, "chapter": final_chapter, @@ -1437,7 +1438,7 @@ def view_chapter_online( part__tutorial__pk=tutorial_pk) tutorial = chapter_bd.get_tutorial() - if not tutorial.on_line: + if not tutorial.on_line(): raise Http404 # find the good manifest file @@ -1472,7 +1473,7 @@ def view_chapter_online( chapter["position_in_part"] = cpt_c chapter["position_in_tutorial"] = cpt_c * cpt_p chapter["get_absolute_url_online"] = part[ - "get_absolute_url_online"] + "{0}/".format(chapter["slug"]) + "get_absolute_url_online"] + "{0}/{1}/".format(chapter["pk"], chapter["slug"]) if chapter_pk == str(chapter["pk"]): intro = open( os.path.join( @@ -1702,6 +1703,7 @@ def edit_chapter(request): old_slug = chapter.get_path() chapter.save() + chapter.update_children() if chapter.part: if chapter.tutorial: @@ -1723,7 +1725,6 @@ def edit_chapter(request): img.pubdate = datetime.now() img.save() chapter.image = img - maj_repo_chapter( request, old_slug_path=old_slug, @@ -1810,7 +1811,6 @@ def add_extract(request): @login_required def edit_extract(request): """Edit extract.""" - try: extract_pk = request.GET["extrait"] except KeyError: @@ -2558,13 +2558,12 @@ def download_markdown(request): """Download a markdown tutorial.""" tutorial = get_object_or_404(Tutorial, pk=request.GET["tutoriel"]) - response = HttpResponse( - open( - os.path.join( + phy_path = os.path.join( tutorial.get_prod_path(), tutorial.slug + - ".md"), - "rb").read(), + ".md") + response = HttpResponse( + open(phy_path, "rb").read(), mimetype="application/txt") response["Content-Disposition"] = \ "attachment; filename={0}.md".format(tutorial.slug) @@ -2576,13 +2575,14 @@ def download_html(request): """Download a pdf tutorial.""" tutorial = get_object_or_404(Tutorial, pk=request.GET["tutoriel"]) - response = HttpResponse( - open( - os.path.join( + phy_path = os.path.join( tutorial.get_prod_path(), tutorial.slug + - ".html"), - "rb").read(), + ".html") + if not os.path.isfile(phy_path): + raise Http404 + response = HttpResponse( + open(phy_path, "rb").read(), mimetype="text/html") response["Content-Disposition"] = \ "attachment; filename={0}.html".format(tutorial.slug) @@ -2594,13 +2594,14 @@ def download_pdf(request): """Download a pdf tutorial.""" tutorial = get_object_or_404(Tutorial, pk=request.GET["tutoriel"]) - response = HttpResponse( - open( - os.path.join( + phy_path = os.path.join( tutorial.get_prod_path(), tutorial.slug + - ".pdf"), - "rb").read(), + ".pdf") + if not os.path.isfile(phy_path): + raise Http404 + response = HttpResponse( + open(phy_path, "rb").read(), mimetype="application/pdf") response["Content-Disposition"] = \ "attachment; filename={0}.pdf".format(tutorial.slug) @@ -2612,13 +2613,14 @@ def download_epub(request): """Download an epub tutorial.""" tutorial = get_object_or_404(Tutorial, pk=request.GET["tutoriel"]) - response = HttpResponse( - open( - os.path.join( + phy_path = os.path.join( tutorial.get_prod_path(), tutorial.slug + - ".epub"), - "rb").read(), + ".epub") + if not os.path.isfile(phy_path): + raise Http404 + response = HttpResponse( + open(phy_path, "rb").read(), mimetype="application/epub") response["Content-Disposition"] = \ "attachment; filename={0}.epub".format(tutorial.slug) diff --git a/zds/utils/tutorials.py b/zds/utils/tutorials.py index acf84fda96..58f2bdd88f 100644 --- a/zds/utils/tutorials.py +++ b/zds/utils/tutorials.py @@ -98,14 +98,17 @@ def get_blob(tree, chemin): return data.decode('utf-8') except: return "" + print('---------> OK') if len(tree.trees) > 0: for tr in tree.trees: result = get_blob(tr, chemin) if result is not None: return result return None + print('---------> OK') else: return None + print('---------> OK') def export_tutorial_to_md(tutorial): From 9c3e9e88ef5c84e8b71aa95bc3d35e4b7fe8526f Mon Sep 17 00:00:00 2001 From: firm1 Date: Sat, 12 Jul 2014 12:25:02 +0200 Subject: [PATCH 02/10] =?UTF-8?q?tests=20de=20v=C3=A9rifications=20du=20wo?= =?UTF-8?q?rkflow=20tuto=20agr=C3=A9ment=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zds/tutorial/tests.py | 364 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 348 insertions(+), 16 deletions(-) diff --git a/zds/tutorial/tests.py b/zds/tutorial/tests.py index 3fffb17498..569f78a3ac 100644 --- a/zds/tutorial/tests.py +++ b/zds/tutorial/tests.py @@ -501,31 +501,59 @@ def test_workflow_tuto(self): self.assertEqual(result.status_code, 302) self.assertEqual(Tutorial.objects.all().count(), 2) tuto = Tutorial.objects.last() - #add part + #add part 1 result = self.client.post( reverse('zds.tutorial.views.add_part') + '?tutoriel={}'.format(tuto.pk), { 'title': u"Partie 1", - 'introduction':"Présentation", - 'conclusion': "", + 'introduction':u"Présentation", + 'conclusion': u"Fin de la présenation", }, follow=False) self.assertEqual(result.status_code, 302) self.assertEqual(Part.objects.filter(tutorial=tuto).count(), 1) p1 = Part.objects.filter(tutorial=tuto).last() - #add part + + #check view offline + result = self.client.get( + reverse( + 'zds.tutorial.views.view_part', + args=[ + tuto.pk, + tuto.slug, + p1.pk, + p1.slug]), + follow=True) + self.assertContains(response=result, text = u"Présentation") + self.assertContains(response=result, text = u"Fin de la présenation") + + #add part 2 result = self.client.post( reverse('zds.tutorial.views.add_part') + '?tutoriel={}'.format(tuto.pk), { 'title': u"Partie 2", - 'introduction':"Analyse", - 'conclusion': "", + 'introduction': u"Analyse", + 'conclusion': u"Fin de l'analyse", }, follow=False) self.assertEqual(result.status_code, 302) self.assertEqual(Part.objects.filter(tutorial=tuto).count(), 2) p2 = Part.objects.filter(tutorial=tuto).last() - #add part + + #check view offline + result = self.client.get( + reverse( + 'zds.tutorial.views.view_part', + args=[ + tuto.pk, + tuto.slug, + p2.pk, + p2.slug]), + follow=True) + self.assertContains(response=result, text = u"Analyse") + self.assertContains(response=result, text = u"Fin de l'analyse") + + #add part 3 result = self.client.post( reverse('zds.tutorial.views.add_part') + '?tutoriel={}'.format(tuto.pk), { @@ -537,49 +565,111 @@ def test_workflow_tuto(self): self.assertEqual(result.status_code, 302) self.assertEqual(Part.objects.filter(tutorial=tuto).count(), 3) p3 = Part.objects.filter(tutorial=tuto).last() - #add chapter + + #check view offline + result = self.client.get( + reverse( + 'zds.tutorial.views.view_part', + args=[ + tuto.pk, + tuto.slug, + p3.pk, + p3.slug]), + follow=True) + self.assertContains(response=result, text = u"Expérimentation") + self.assertContains(response=result, text = u"C'est terminé") + + #add chapter 1 for part 2 result = self.client.post( reverse('zds.tutorial.views.add_chapter') + '?partie={}'.format(p2.pk), { 'title': u"Chapitre 1", 'introduction':"Mon premier chapitre", - 'conclusion': "", + 'conclusion': "Fin de mon premier chapitre", }, follow=False) self.assertEqual(result.status_code, 302) self.assertEqual(Chapter.objects.filter(part=p1).count(), 0) self.assertEqual(Chapter.objects.filter(part=p2).count(), 1) self.assertEqual(Chapter.objects.filter(part=p3).count(), 0) + c1 = Chapter.objects.filter(part=p2).last() - #add chapter + #check view offline + result = self.client.get( + reverse( + 'zds.tutorial.views.view_chapter', + args=[ + tuto.pk, + tuto.slug, + p2.pk, + p2.slug, + c1.pk, + c1.slug]), + follow=True) + self.assertContains(response=result, text = u"Mon premier chapitre") + self.assertContains(response=result, text = u"Fin de mon premier chapitre") + + #add chapter 2 for part 2 result = self.client.post( reverse('zds.tutorial.views.add_chapter') + '?partie={}'.format(p2.pk), { 'title': u"Chapitre 2", - 'introduction':"Mon deuxième chapitre", - 'conclusion': "", + 'introduction': u"Mon deuxième chapitre", + 'conclusion':u"Fin de mon deuxième chapitre", }, follow=False) self.assertEqual(result.status_code, 302) self.assertEqual(Chapter.objects.filter(part=p1).count(), 0) self.assertEqual(Chapter.objects.filter(part=p2).count(), 2) self.assertEqual(Chapter.objects.filter(part=p3).count(), 0) + c2 = Chapter.objects.filter(part=p2).last() - #add chapter + #check view offline + result = self.client.get( + reverse( + 'zds.tutorial.views.view_chapter', + args=[ + tuto.pk, + tuto.slug, + p2.pk, + p2.slug, + c2.pk, + c2.slug]), + follow=True) + self.assertContains(response=result, text = u"Mon deuxième chapitre") + self.assertContains(response=result, text = u"Fin de mon deuxième chapitre") + + #add chapter 3 for part 2 result = self.client.post( reverse('zds.tutorial.views.add_chapter') + '?partie={}'.format(p2.pk), { 'title': u"Chapitre 2", - 'introduction':"Mon troisième chapitre homonyme", - 'conclusion': "", + 'introduction': u"Mon troisième chapitre homonyme", + 'conclusion': u"Fin de mon troisième chapitre", }, follow=False) self.assertEqual(result.status_code, 302) self.assertEqual(Chapter.objects.filter(part=p1).count(), 0) self.assertEqual(Chapter.objects.filter(part=p2).count(), 3) self.assertEqual(Chapter.objects.filter(part=p3).count(), 0) + c3 = Chapter.objects.filter(part=p2).last() + + #check view offline + result = self.client.get( + reverse( + 'zds.tutorial.views.view_chapter', + args=[ + tuto.pk, + tuto.slug, + p2.pk, + p2.slug, + c3.pk, + c3.slug]), + follow=True) + self.assertContains(response=result, text = u"Mon troisième chapitre homonyme") + self.assertContains(response=result, text = u"Fin de mon troisième chapitre") - #add chapter + #add chapter 4 for part 1 result = self.client.post( reverse('zds.tutorial.views.add_chapter') + '?partie={}'.format(p1.pk), { @@ -592,6 +682,114 @@ def test_workflow_tuto(self): self.assertEqual(Chapter.objects.filter(part=p1).count(), 1) self.assertEqual(Chapter.objects.filter(part=p2).count(), 3) self.assertEqual(Chapter.objects.filter(part=p3).count(), 0) + c4 = Chapter.objects.filter(part=p1).last() + + #check view offline + result = self.client.get( + reverse( + 'zds.tutorial.views.view_chapter', + args=[ + tuto.pk, + tuto.slug, + p1.pk, + p1.slug, + c4.pk, + c4.slug]), + follow=True) + self.assertContains(response=result, text = u"Mon premier chapitre d'une autre partie") + + #edit part 2 + result = self.client.post( + reverse('zds.tutorial.views.edit_part') + '?partie={}'.format(p2.pk), + { + 'title': u"Partie 2 : edition de titre", + 'introduction': u"Expérimentation : edition d'introduction", + 'conclusion': u"C'est terminé : edition de conlusion", + }, + follow=True) + self.assertContains(response=result, text = u"Partie 2 : edition de titre") + self.assertContains(response=result, text = u"Expérimentation : edition d'introduction") + self.assertContains(response=result, text = u"C'est terminé : edition de conlusion") + self.assertEqual(Part.objects.filter(tutorial=tuto).count(), 3) + + #edit chapter 3 + result = self.client.post( + reverse('zds.tutorial.views.edit_chapter') + '?chapitre={}'.format(c3.pk), + { + 'title': u"Chapitre 3 : edition de titre", + 'introduction': u"Edition d'introduction", + 'conclusion': u"Edition de conlusion", + }, + follow=True) + self.assertContains(response=result, text = u"Chapitre 3 : edition de titre") + self.assertContains(response=result, text = u"Edition d'introduction") + self.assertContains(response=result, text = u"Edition de conlusion") + self.assertEqual(Chapter.objects.filter(part=p2.pk).count(), 3) + + #edit part 2 + result = self.client.post( + reverse('zds.tutorial.views.edit_part') + '?partie={}'.format(p2.pk), + { + 'title': u"Partie 2 : seconde edition de titre", + 'introduction': u"Expérimentation : seconde edition d'introduction", + 'conclusion': u"C'est terminé : seconde edition de conlusion", + }, + follow=True) + self.assertContains(response=result, text = u"Partie 2 : seconde edition de titre") + self.assertContains(response=result, text = u"Expérimentation : seconde edition d'introduction") + self.assertContains(response=result, text = u"C'est terminé : seconde edition de conlusion") + self.assertEqual(Part.objects.filter(tutorial=tuto).count(), 3) + + #edit chapter 2 + result = self.client.post( + reverse('zds.tutorial.views.edit_chapter') + '?chapitre={}'.format(c2.pk), + { + 'title': u"Chapitre 2 : edition de titre", + 'introduction': u"Edition d'introduction", + 'conclusion': u"Edition de conlusion", + }, + follow=True) + self.assertContains(response=result, text = u"Chapitre 2 : edition de titre") + self.assertContains(response=result, text = u"Edition d'introduction") + self.assertContains(response=result, text = u"Edition de conlusion") + self.assertEqual(Chapter.objects.filter(part=p2.pk).count(), 3) + + #move chapter 1 against 2 + result = self.client.post( + reverse('zds.tutorial.views.modify_chapter'), + { + 'chapter': c1.pk, + 'move_target': c2.position_in_part, + }, + follow=True) + #move part 1 against 2 + result = self.client.post( + reverse('zds.tutorial.views.modify_part'), + { + 'part': p1.pk, + 'move_target': p2.position_in_tutorial, + }, + follow=True) + self.assertEqual(Chapter.objects.filter(part__tutorial=tuto.pk).count(), 4) + + #delete part 1 + result = self.client.post( + reverse('zds.tutorial.views.modify_part'), + { + 'part': p1.pk, + 'delete': "OK", + }, + follow=True) + #delete chapter 3 + result = self.client.post( + reverse('zds.tutorial.views.modify_chapter'), + { + 'chapter': c3.pk, + 'delete': "OK", + }, + follow=True) + self.assertEqual(Chapter.objects.filter(part__tutorial=tuto.pk).count(), 2) + self.assertEqual(Part.objects.filter(tutorial=tuto.pk).count(), 2) def test_url_for_member(self): """Test simple get request by simple member.""" @@ -1151,6 +1349,8 @@ def setUp(self): self.user = ProfileFactory().user self.staff = StaffProfileFactory().user + self.subcat = SubCategoryFactory() + self.minituto = MiniTutorialFactory() self.minituto.authors.add(self.user_author) self.minituto.gallery = GalleryFactory() @@ -2032,6 +2232,138 @@ def test_workflow_beta_tuto(self) : self.client.get(url).status_code, 200) + def test_workflow_tuto(self): + """Test workflow of mini tutorial.""" + + # logout before + self.client.logout() + # login with simple member + self.assertEqual( + self.client.login( + username=self.user.username, + password='hostel77'), + True) + + #add new mini tuto + result = self.client.post( + reverse('zds.tutorial.views.add_tutorial'), + { + 'title': u"Introduction à l'algèbre", + 'description': "Perçer les mystère de boole", + 'introduction':"Bienvenue dans le monde binaires", + 'conclusion': "", + 'type': "MINI", + 'subcategory': self.subcat.pk, + }, + follow=False) + + self.assertEqual(result.status_code, 302) + self.assertEqual(Tutorial.objects.all().count(), 2) + tuto = Tutorial.objects.last() + chapter = Chapter.objects.filter(tutorial__pk=tuto.pk).first() + + #add extract 1 + result = self.client.post( + reverse('zds.tutorial.views.add_extract') + '?chapitre={}'.format(chapter.pk), + { + 'title': u"Extrait 1", + 'text': u"Introduisons notre premier extrait", + }, + follow=False) + self.assertEqual(result.status_code, 302) + self.assertEqual(Extract.objects.filter(chapter=chapter).count(), 1) + e1 = Extract.objects.filter(chapter=chapter).last() + + #check view offline + result = self.client.get( + reverse( + 'zds.tutorial.views.view_tutorial', + args=[ + tuto.pk, + tuto.slug]), + follow=True) + self.assertContains(response=result, text = u"Extrait 1") + self.assertContains(response=result, text = u"Introduisons notre premier extrait") + + #add extract 2 + result = self.client.post( + reverse('zds.tutorial.views.add_extract') + '?chapitre={}'.format(chapter.pk), + { + 'title': u"Extrait 2", + 'text': u"Introduisons notre deuxième extrait", + }, + follow=False) + self.assertEqual(result.status_code, 302) + self.assertEqual(Extract.objects.filter(chapter=chapter).count(), 2) + e2 = Extract.objects.filter(chapter=chapter).last() + + #check view offline + result = self.client.get( + reverse( + 'zds.tutorial.views.view_tutorial', + args=[ + tuto.pk, + tuto.slug]), + follow=True) + self.assertContains(response=result, text = u"Extrait 2") + self.assertContains(response=result, text = u"Introduisons notre deuxième extrait") + + #add extract 3 + result = self.client.post( + reverse('zds.tutorial.views.add_extract') + '?chapitre={}'.format(chapter.pk), + { + 'title': u"Extrait 3", + 'text': u"Introduisons notre troisième extrait", + }, + follow=False) + self.assertEqual(result.status_code, 302) + self.assertEqual(Extract.objects.filter(chapter=chapter).count(), 3) + e3 = Extract.objects.filter(chapter=chapter).last() + + #check view offline + result = self.client.get( + reverse( + 'zds.tutorial.views.view_tutorial', + args=[ + tuto.pk, + tuto.slug]), + follow=True) + self.assertContains(response=result, text = u"Extrait 3") + self.assertContains(response=result, text = u"Introduisons notre troisième extrait") + + #edit extract 2 + result = self.client.post( + reverse('zds.tutorial.views.edit_extract') + '?extrait={}'.format(e2.pk), + { + 'title': u"Extrait 2 : edition de titre", + 'text': u"Edition d'introduction", + }, + follow=True) + self.assertEqual(result.status_code, 200) + self.assertContains(response=result, text = u"Extrait 2 : edition de titre") + self.assertContains(response=result, text = u"Edition d'introduction") + self.assertEqual(Extract.objects.filter(chapter__tutorial=tuto).count(), 3) + + #move extract 1 against 2 + result = self.client.post( + reverse('zds.tutorial.views.modify_extract'), + { + 'extract': e1.pk, + 'move_target': e2.position_in_chapter, + }, + follow=True) + + #delete extract 1 + result = self.client.post( + reverse('zds.tutorial.views.modify_extract'), + { + 'extract': e1.pk, + 'delete': "OK", + }, + follow=True) + + self.assertEqual(Extract.objects.filter(chapter__tutorial=tuto).count(), 2) + def tearDown(self): if os.path.isdir(settings.REPO_PATH): shutil.rmtree(settings.REPO_PATH) From 656330bc0934f12820072547a4e876674020c268 Mon Sep 17 00:00:00 2001 From: firm1 Date: Sat, 12 Jul 2014 12:25:48 +0200 Subject: [PATCH 03/10] =?UTF-8?q?v=C3=A9rification=20que=20les=20format=20?= =?UTF-8?q?sont=20dispo=20avant=20de=20les=20pr=C3=A9senter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/tutorial/base.html | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/templates/tutorial/base.html b/templates/tutorial/base.html index 35cab7c6db..a32d1578f2 100644 --- a/templates/tutorial/base.html +++ b/templates/tutorial/base.html @@ -56,28 +56,35 @@

Télécharger

    {% if tutorial.on_line %} {% if perms.tutorial.change_tutorial %} -
  • - - Markdown - -
  • + {% if tutorial.have_markdown %} +
  • + + Markdown + +
  • + {% endif %} {% endif %} - + {% if tutorial.have_html %}
  • HTML
  • + {% endif %} + {% if tutorial.have_pdf %}
  • PDF
  • + {% endif %} + {% if tutorial.have_epub %}
  • EPUB
  • + {% endif %} {% endif %}
  • From 80d705b4ecf8fda6da6d2622bfb0e655b08eecfe Mon Sep 17 00:00:00 2001 From: firm1 Date: Sat, 12 Jul 2014 12:26:31 +0200 Subject: [PATCH 04/10] =?UTF-8?q?renvoi=20un=20404=20=C3=A0=20la=20place?= =?UTF-8?q?=20d'une=20500=20en=20cas=20d'article=20indispo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zds/article/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zds/article/views.py b/zds/article/views.py index 4ea5164b33..547e07c4e3 100644 --- a/zds/article/views.py +++ b/zds/article/views.py @@ -779,7 +779,7 @@ def history(request, article_pk, article_slug): """Display an article.""" article = get_object_or_404(Article, pk=article_pk) - if not article.on_line \ + if not article.on_line() \ and not request.user.has_perm('article.change_article') \ and request.user not in article.authors.all(): raise Http404 From 71492e2b44a8c8784fe9ebf15b90692e9913058f Mon Sep 17 00:00:00 2001 From: firm1 Date: Sun, 13 Jul 2014 03:34:38 +0200 Subject: [PATCH 05/10] corrige les tests de publications --- zds/tutorial/models.py | 3 +-- zds/tutorial/tests.py | 3 +++ zds/tutorial/views.py | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/zds/tutorial/models.py b/zds/tutorial/models.py index 1e57bf28b7..a429fd318d 100644 --- a/zds/tutorial/models.py +++ b/zds/tutorial/models.py @@ -162,8 +162,7 @@ def in_drafting(self): return (self.sha_draft is not None) and (self.sha_draft.strip() != '') def on_line(self): - print('--------------> {}'.format(self.sha_public)) - return (self.sha_public is not None) and (self.sha_public.strip() != '') and (self.sha_public.strip() != '') + return (self.sha_public is not None) and (self.sha_public.strip() != '') def is_mini(self): return self.type == 'MINI' diff --git a/zds/tutorial/tests.py b/zds/tutorial/tests.py index 569f78a3ac..cfa0855541 100644 --- a/zds/tutorial/tests.py +++ b/zds/tutorial/tests.py @@ -113,6 +113,7 @@ def setUp(self): 'source': 'http://zestedesavoir.com', }, follow=False) + self.bigtuto = Tutorial.objects.get(pk=self.bigtuto.pk) self.assertEqual(pub.status_code, 302) self.assertEquals(len(mail.outbox), 1) @@ -1398,6 +1399,8 @@ def setUp(self): }, follow=False) self.assertEqual(pub.status_code, 302) + self.minituto = Tutorial.objects.get(pk=self.minituto.pk) + self.assertEqual(self.minituto.on_line(), True) self.assertEquals(len(mail.outbox), 1) mail.outbox = [] diff --git a/zds/tutorial/views.py b/zds/tutorial/views.py index 49202020f4..b4c853a3fc 100644 --- a/zds/tutorial/views.py +++ b/zds/tutorial/views.py @@ -345,7 +345,7 @@ def valid_tutorial(request): # Update sha_public with the sha of validation. We don't update sha_draft. # So, the user can continue to edit his tutorial in offline. - if request.POST.get('is_major', False) or tutorial.sha_public is None: + if request.POST.get('is_major', False) or tutorial.sha_public is None or tutorial.sha_public == '': tutorial.pubdate = datetime.now() tutorial.sha_public = validation.version tutorial.source = request.POST["source"] @@ -3048,13 +3048,13 @@ def edit_note(request): @login_required def like_note(request): """Like a note.""" - try: note_pk = request.GET["message"] except KeyError: raise Http404 resp = {} note = get_object_or_404(Note, pk=note_pk) + user = request.user if note.author.pk != request.user.pk: From 978b8457db107acfe500ed36aafc3a1a15929b9b Mon Sep 17 00:00:00 2001 From: firm1 Date: Sun, 13 Jul 2014 03:37:39 +0200 Subject: [PATCH 06/10] suppression des lignes de debug --- zds/utils/tutorials.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/zds/utils/tutorials.py b/zds/utils/tutorials.py index 58f2bdd88f..acf84fda96 100644 --- a/zds/utils/tutorials.py +++ b/zds/utils/tutorials.py @@ -98,17 +98,14 @@ def get_blob(tree, chemin): return data.decode('utf-8') except: return "" - print('---------> OK') if len(tree.trees) > 0: for tr in tree.trees: result = get_blob(tr, chemin) if result is not None: return result return None - print('---------> OK') else: return None - print('---------> OK') def export_tutorial_to_md(tutorial): From 5ef592dcf042b50d0d317902181533758539f479 Mon Sep 17 00:00:00 2001 From: firm1 Date: Sun, 13 Jul 2014 04:21:12 +0200 Subject: [PATCH 07/10] permet la suppression d'une partie --- templates/tutorial/part/view.html | 18 ++++++++++++++++ zds/tutorial/views.py | 34 ++++++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/templates/tutorial/part/view.html b/templates/tutorial/part/view.html index ebaea40ca9..61b3916dd8 100644 --- a/templates/tutorial/part/view.html +++ b/templates/tutorial/part/view.html @@ -118,6 +118,7 @@

    Déplacer la partie + +

  • {% endif %} {% endif %} {% endblock %} diff --git a/zds/tutorial/views.py b/zds/tutorial/views.py index b4c853a3fc..49a53fdb53 100644 --- a/zds/tutorial/views.py +++ b/zds/tutorial/views.py @@ -1246,7 +1246,6 @@ def modify_part(request): tuto = part.tutorial, action = "maj") elif "delete" in request.POST: - # Delete all chapters belonging to the part Chapter.objects.all().filter(part=part).delete() @@ -1261,9 +1260,16 @@ def modify_part(request): old_slug = os.path.join(settings.REPO_PATH, part.tutorial.get_phy_slug(), part.get_phy_slug()) maj_repo_part(request, old_slug_path=old_slug, part=part, action="del") + new_slug_tuto_path = os.path.join(settings.REPO_PATH, part.tutorial.get_phy_slug()) # Actually delete the part - part.delete() + + + maj_repo_tuto(request, + old_slug_path = new_slug_tuto_path, + new_slug_path = new_slug_tuto_path, + tuto = part.tutorial, + action = "maj") return redirect(part.tutorial.get_absolute_url()) @@ -1656,7 +1662,7 @@ def modify_chapter(request): old_slug_path=chapter.get_path(), action="del") # Then delete the chapter - + new_slug_path_part = os.path.join(settings.REPO_PATH, chapter.part.tutorial.get_phy_slug()) chapter.delete() # Update all the position_in_tutorial fields for the next chapters @@ -1665,6 +1671,12 @@ def modify_chapter(request): Chapter.objects.filter(position_in_tutorial__gt=old_tut_pos): tut_c.update_position_in_tutorial() tut_c.save() + + maj_repo_part(request, + old_slug_path = new_slug_path_part, + new_slug_path = new_slug_path_part, + part = chapter.part, + action = "maj") messages.info(request, u"Le chapitre a bien été supprimé.") return redirect(parent.get_absolute_url()) @@ -1921,8 +1933,24 @@ def modify_extract(request): # Use path retrieve before and use it to create the new slug. old_slug = extract.get_path() + + if extract.chapter.tutorial: + new_slug_path_chapter = os.path.join(settings.REPO_PATH, + extract.chapter.tutorial.get_phy_slug()) + else: + new_slug_path_chapter = os.path.join(settings.REPO_PATH, + chapter.part.tutorial.get_phy_slug(), + chapter.part.get_phy_slug(), + chapter.get_phy_slug()) + maj_repo_extract(request, old_slug_path=old_slug, extract=extract, action="del") + + maj_repo_chapter(request, + old_slug_path = new_slug_path_chapter, + new_slug_path = new_slug_path_chapter, + chapter = chapter, + action = "maj") return redirect(chapter.get_absolute_url()) elif "move" in data: try: From 404c4509a7616f0c3655f0e5b03c355f37aac3bf Mon Sep 17 00:00:00 2001 From: firm1 Date: Sun, 13 Jul 2014 16:51:36 +0200 Subject: [PATCH 08/10] =?UTF-8?q?correction=20des=20messages=20MP=20et=20l?= =?UTF-8?q?iens=20404=20apr=C3=A8s=20modifications?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zds/tutorial/views.py | 71 ++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/zds/tutorial/views.py b/zds/tutorial/views.py index 49a53fdb53..d71beeb43c 100644 --- a/zds/tutorial/views.py +++ b/zds/tutorial/views.py @@ -290,11 +290,14 @@ def reject_tutorial(request): u'certaines corrections peuvent surement être faite pour ' u'l’améliorer et repasser la validation plus tard. ' u'Voici le message que [{2}]({3}), ton validateur t\'a laissé `{4}`' - u'N\'hésite pas a lui envoyer un petit message pour discuter ' - u'de la décision ou demander plus de détail si tout cela te ' - u'semble injuste ou manque de clarté.' - .format(author.username, tutorial.title, validation.validator.username, - settings.SITE_URL + validation.validator.profile.get_absolute_url(), validation.comment_validator)) + u'N\'hésite pas à lui envoyer un petit message pour discuter ' + u'de la décision ou demander plus de détails si tout cela te ' + u'semble injuste ou manque de clarté.'.format( + author.username, + tutorial.title, + validation.validator.username, + settings.SITE_URL + validation.validator.profile.get_absolute_url(), + validation.comment_validator)) bot = get_object_or_404(User, username=settings.BOT_ACCOUNT) send_mp( bot, @@ -359,16 +362,16 @@ def valid_tutorial(request): msg = ( u'Félicitations **{0}** ! Ton zeste [{1}]({2}) ' u'a été publié par [{3}]({4}) ! Les lecteurs du monde entier ' - u'peuvent venir l\'éplucher et réagir a son sujet. ' - u'Je te conseille de rester a leur écoute afin ' + u'peuvent venir l\'éplucher et réagir à son sujet. ' + u'Je te conseille de rester à leur écoute afin ' u'd\'apporter des corrections/compléments.' - u'Un Tutoriel vivant et a jour est bien plus lu ' - u'qu\'un sujet abandonné !' - .format(author.username, - tutorial.title, - settings.SITE_URL + tutorial.get_absolute_url_online(), - validation.validator.username, - settings.SITE_URL + validation.validator.profile.get_absolute_url())) + u'Un Tutoriel vivant et à jour est bien plus lu ' + u'qu\'un sujet abandonné !'.format( + author.username, + tutorial.title, + settings.SITE_URL + tutorial.get_absolute_url_online(), + validation.validator.username, + settings.SITE_URL + validation.validator.profile.get_absolute_url())) bot = get_object_or_404(User, username=settings.BOT_ACCOUNT) send_mp( bot, @@ -1109,8 +1112,7 @@ def view_part_online( ): """Display a part.""" - part = get_object_or_404(Part, slug=part_slug, tutorial__pk=tutorial_pk) - tutorial = part.tutorial + tutorial = get_object_or_404(Tutorial, pk=tutorial_pk) if not tutorial.on_line(): raise Http404 @@ -1122,6 +1124,7 @@ def view_part_online( mandata["get_parts"] = mandata["parts"] parts = mandata["parts"] cpt_p = 1 + final_part= None for part in parts: part["tutorial"] = mandata part["path"] = tutorial.get_path() @@ -1136,6 +1139,7 @@ def view_part_online( part["conclusion"] + ".html"), "r") part["conclu"] = conclu.read() conclu.close() + final_part=part cpt_c = 1 for chapter in part["chapters"]: chapter["part"] = part @@ -1155,7 +1159,7 @@ def view_part_online( part["get_chapters"] = part["chapters"] cpt_p += 1 - return render_template("tutorial/part/view_online.html", {"part": part}) + return render_template("tutorial/part/view_online.html", {"part": final_part}) @can_write_and_read_now @@ -1176,8 +1180,8 @@ def add_part(request): # Make sure the user belongs to the author list - if request.user not in tutorial.authors.all(): - raise Http404 + if request.user not in tutorial.authors.all() and not request.user.has_perm("tutorial.change_tutorial"): + raise PermissionDenied if request.method == "POST": form = PartForm(request.POST) if form.is_valid(): @@ -1226,8 +1230,8 @@ def modify_part(request): # Make sure the user is allowed to do that - if request.user not in part.tutorial.authors.all(): - raise Http404 + if request.user not in part.tutorial.authors.all() and not request.user.has_perm("tutorial.change_tutorial"): + raise PermissionDenied if "move" in request.POST: try: new_pos = int(request.POST["move_target"]) @@ -1286,8 +1290,8 @@ def edit_part(request): # Make sure the user is allowed to do that - if request.user not in part.tutorial.authors.all(): - raise Http404 + if request.user not in part.tutorial.authors.all() and not request.user.has_perm("tutorial.change_tutorial"): + raise PermissionDenied if request.method == "POST": form = PartForm(request.POST) if form.is_valid(): @@ -1439,11 +1443,7 @@ def view_chapter_online( ): """View chapter.""" - chapter_bd = get_object_or_404(Chapter, pk=chapter_pk, - part__pk=part_pk, - part__tutorial__pk=tutorial_pk) - - tutorial = chapter_bd.get_tutorial() + tutorial = get_object_or_404(Tutorial, pk=tutorial_pk) if not tutorial.on_line(): raise Http404 @@ -1541,8 +1541,8 @@ def add_chapter(request): # Make sure the user is allowed to do that - if request.user not in part.tutorial.authors.all(): - raise Http404 + if request.user not in part.tutorial.authors.all() and not request.user.has_perm("tutorial.change_tutorial"): + raise PermissionDenied if request.method == "POST": form = ChapterForm(request.POST, request.FILES) if form.is_valid(): @@ -1620,8 +1620,8 @@ def modify_chapter(request): # Make sure the user is allowed to do that - if request.user not in chapter.get_tutorial().authors.all(): - raise Http404 + if request.user not in chapter.get_tutorial().authors.all() and not request.user.has_perm("tutorial.change_tutorial"): + raise PermissionDenied if "move" in data: try: new_pos = int(request.POST["move_target"]) @@ -1699,9 +1699,10 @@ def edit_chapter(request): # Make sure the user is allowed to do that - if big and request.user not in chapter.part.tutorial.authors.all() \ - or small and request.user not in chapter.tutorial.authors.all(): - raise Http404 + if (big and request.user not in chapter.part.tutorial.authors.all() \ + or small and request.user not in chapter.tutorial.authors.all())\ + and not request.user.has_perm("tutorial.change_tutorial"): + raise PermissionDenied if request.method == "POST": if chapter.part: form = ChapterForm(request.POST, request.FILES) From 304e2ca1e526416de25c1634bc08a1468d071b9f Mon Sep 17 00:00:00 2001 From: firm1 Date: Sun, 13 Jul 2014 20:16:37 +0200 Subject: [PATCH 09/10] droit de modif des extraits au staff --- templates/tutorial/tutorial/view.html | 9 +++++++++ zds/tutorial/views.py | 7 ++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/templates/tutorial/tutorial/view.html b/templates/tutorial/tutorial/view.html index 72801e72de..e3ca6cde0a 100644 --- a/templates/tutorial/tutorial/view.html +++ b/templates/tutorial/tutorial/view.html @@ -264,6 +264,15 @@

    {% crispy formAskValidation %} + {% elif tutorial.sha_validation != version %} +
  • + + Mettre à jour la version en validation + + +
  • {% else %}
  • En attente de validation diff --git a/zds/tutorial/views.py b/zds/tutorial/views.py index d71beeb43c..c4a2a80674 100644 --- a/zds/tutorial/views.py +++ b/zds/tutorial/views.py @@ -445,8 +445,13 @@ def ask_validation(request): if not request.user.has_perm("tutorial.change_tutorial"): raise PermissionDenied + #delete old pending validation + Validation.objects.filter(tutorial__pk=tutorial_pk, + status__in=['PENDING','PENDING_V'])\ + .delete() # We create and save validation object of the tutorial. - + + validation = Validation() validation.tutorial = tutorial validation.date_proposition = datetime.now() From d2ee3221c7047a71bc785772fcb90dd8a0e9ca47 Mon Sep 17 00:00:00 2001 From: firm1 Date: Sun, 13 Jul 2014 20:17:02 +0200 Subject: [PATCH 10/10] =?UTF-8?q?alignement=20des=20comportements=20des=20?= =?UTF-8?q?modales=20de=20d=C3=A9placement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/tutorial/includes/chapter.part.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/tutorial/includes/chapter.part.html b/templates/tutorial/includes/chapter.part.html index e69036566c..e624427ff6 100644 --- a/templates/tutorial/includes/chapter.part.html +++ b/templates/tutorial/includes/chapter.part.html @@ -39,7 +39,7 @@

    - {% if user in authors %} + {% if user in authors or perms.tutorial.change_tutorial %}
    Supprimer