Skip to content

Commit

Permalink
Merge branch 'dev' into debian11
Browse files Browse the repository at this point in the history
  • Loading branch information
Arnaud-D authored Feb 19, 2022
2 parents 0e7e5e1 + 337fb40 commit ce3cb9f
Show file tree
Hide file tree
Showing 7 changed files with 603 additions and 461 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ jobs:
- name: Install Python dependencies
run: pip install -r requirements-ci.txt

- name: Check that no migration is missing
run: python manage.py makemigrations --check --dry-run

- name: Build and start zmarkdown
run: |
make zmd-install
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
12
16
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
},
"homepage": "https://github.com/zestedesavoir/zds-site",
"dependencies": {
"autoprefixer": "10.2.5",
"chart.js": "3.5.1",
"autoprefixer": "10.4.2",
"chart.js": "3.7.0",
"chartjs-adapter-moment": "1.0.0",
"cssnano": "5.0.4",
"cssnano": "5.0.15",
"del": "6.0.0",
"easymde": "2.10.2-360.0",
"gulp": "4.0.2",
Expand All @@ -37,13 +37,13 @@
"gulp-if": "3.0.0",
"gulp-imagemin": "7.1.0",
"gulp-options": "1.1.1",
"gulp-postcss": "9.0.0",
"gulp-postcss": "9.0.1",
"gulp-terser-js": "5.1.2",
"gulp.spritesmith": "6.12.1",
"jquery": "3.6.0",
"moment": "2.29.1",
"normalize.css": "8.0.1",
"postcss": "8.3.0"
"postcss": "8.4.5"
},
"devDependencies": {
"eslint-config-standard": "14.1.1",
Expand Down
875 changes: 422 additions & 453 deletions yarn.lock

Large diffs are not rendered by default.

151 changes: 151 additions & 0 deletions zds/tutorialv2/tests/tests_views/tests_addsuggestion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
from django.test import TestCase
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from django.utils.html import escape

from zds.member.factories import ProfileFactory, StaffProfileFactory
from zds.tutorialv2.factories import PublishableContentFactory, PublishedContentFactory
from zds.tutorialv2.models.database import ContentSuggestion
from zds.tutorialv2.tests import TutorialTestMixin, override_for_contents


@override_for_contents()
class AddSuggestionPermissionTests(TutorialTestMixin, TestCase):
"""Test permissions and associated behaviors, such as redirections and status codes."""

def setUp(self):
# Create users
self.author = ProfileFactory().user
self.staff = StaffProfileFactory().user
self.outsider = ProfileFactory().user

# Create contents and suggestion
self.content = PublishableContentFactory(author_list=[self.author])
self.suggestable_content = PublishedContentFactory()

# Get information to be reused in tests
self.form_url = reverse("content:add-suggestion", kwargs={"pk": self.content.pk})
self.login_url = reverse("member-login") + "?next=" + self.form_url
self.content_url = reverse("content:view", kwargs={"pk": self.content.pk, "slug": self.content.slug})
self.form_data = {"options": self.suggestable_content.pk}

def test_not_authenticated(self):
self.client.logout()
self.content.type = "TUTORIAL"
self.content.save()
response = self.client.post(self.form_url, self.form_data)
self.assertRedirects(response, self.login_url)

def test_authenticated_outsider(self):
self.client.force_login(self.outsider)
self.content.type = "TUTORIAL"
self.content.save()
response = self.client.post(self.form_url, self.form_data)
self.assertEqual(response.status_code, 403)

def test_authenticated_author(self):
self.client.force_login(self.author)
self.content.type = "TUTORIAL"
self.content.save()
response = self.client.post(self.form_url, self.form_data)
self.assertEqual(response.status_code, 403)

def test_authenticated_staff_tutorial(self):
self.client.force_login(self.staff)
self.content.type = "TUTORIAL"
self.content.save()
response = self.client.post(self.form_url, self.form_data)
self.assertRedirects(response, self.content_url)

def test_authenticated_staff_article(self):
self.client.force_login(self.staff)
self.content.type = "ARTICLE"
self.content.save()
response = self.client.post(self.form_url, self.form_data)
self.assertRedirects(response, self.content_url)

def test_authenticated_staff_opinion(self):
self.client.force_login(self.staff)
self.content.type = "OPINION"
self.content.save()
response = self.client.post(self.form_url, self.form_data)
self.assertEqual(response.status_code, 403)


class AddSuggestionWorkflowTests(TutorialTestMixin, TestCase):
"""Test the workflow of the form, such as validity errors and success messages."""

def setUp(self):
# Create users
self.staff = StaffProfileFactory().user
self.author = ProfileFactory().user

# Createcontents
self.content = PublishableContentFactory(author_list=[self.author])
self.suggestable_content_1 = PublishedContentFactory()
self.suggestable_content_2 = PublishedContentFactory()
self.unpublished_content = PublishableContentFactory()

self.not_picked_opinion = PublishedContentFactory()
self.not_picked_opinion.type = "OPINION"
self.not_picked_opinion.save()

# Get information to be reused in tests
self.form_url = reverse("content:add-suggestion", kwargs={"pk": self.content.pk})
self.success_message_fragment = _("a été ajouté dans les suggestions")
self.error_message_fragment_unpublished = _("un contenu qui n'a pas été publié")
self.error_message_fragment_already_suggested = _("fait déjà partie des suggestions de")
self.error_message_fragment_self = _("en tant que suggestion pour lui même")
self.error_messge_fragment_not_picked = _("un billet qui n'a pas été mis en avant")

# Log in with an authorized user to perform the tests
self.client.force_login(self.staff)

def test_published_simple(self):
response = self.client.post(self.form_url, {"options": self.suggestable_content_1.pk}, follow=True)
self.assertContains(response, escape(self.success_message_fragment))
suggestion = ContentSuggestion.objects.get(publication=self.content, suggestion=self.suggestable_content_1)
self.assertEqual(list(ContentSuggestion.objects.all()), [suggestion])

def test_published_multiple(self):
response = self.client.post(
self.form_url, {"options": [self.suggestable_content_1.pk, self.suggestable_content_2.pk]}, follow=True
)
self.assertContains(response, escape(self.success_message_fragment))
suggestion_1 = ContentSuggestion.objects.get(publication=self.content, suggestion=self.suggestable_content_1)
suggestion_2 = ContentSuggestion.objects.get(publication=self.content, suggestion=self.suggestable_content_2)
self.assertEqual(list(ContentSuggestion.objects.all()), [suggestion_1, suggestion_2])

def test_already_suggested(self):
suggestion = ContentSuggestion(publication=self.content, suggestion=self.suggestable_content_1)
suggestion.save()
response = self.client.post(self.form_url, {"options": self.suggestable_content_1.pk}, follow=True)
self.assertContains(response, escape(self.error_message_fragment_already_suggested))
self.assertEqual(list(ContentSuggestion.objects.all()), [suggestion])

def test_self(self):
response = self.client.post(self.form_url, {"options": self.content.pk}, follow=True)
self.assertContains(response, escape(self.error_message_fragment_self))
self.assertQuerysetEqual(ContentSuggestion.objects.all(), [])

def test_not_picked_opinion(self):
response = self.client.post(self.form_url, {"options": self.not_picked_opinion.pk}, follow=True)
self.assertContains(response, escape(self.error_messge_fragment_not_picked))
self.assertQuerysetEqual(ContentSuggestion.objects.all(), [])

def test_unpublished(self):
response = self.client.post(self.form_url, {"options": self.unpublished_content.pk}, follow=True)
self.assertContains(response, escape(self.error_message_fragment_unpublished))
self.assertQuerysetEqual(ContentSuggestion.objects.all(), [])

def test_invalid(self):
response = self.client.post(self.form_url, {"options": "420"}, follow=True) # pk must not exist
self.assertEqual(response.status_code, 404)

def test_not_integer(self):
with self.assertRaises(ValueError):
self.client.post(self.form_url, {"options": "abcd"}, follow=True)

def test_empty(self):
with self.assertRaises(ValueError):
self.client.post(self.form_url, {"options": ""}, follow=True)
5 changes: 3 additions & 2 deletions zds/tutorialv2/views/editorialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.shortcuts import get_object_or_404, redirect
from django.utils.translation import gettext_lazy as _

from zds.member.decorator import LoggedWithReadWriteHability
from zds.member.decorator import LoggedWithReadWriteHability, PermissionRequiredMixin
from zds.tutorialv2.forms import RemoveSuggestionForm, EditContentTagsForm
from zds.tutorialv2.mixins import SingleContentFormViewMixin
from zds.tutorialv2.models.database import ContentSuggestion, PublishableContent
Expand Down Expand Up @@ -48,9 +48,10 @@ def form_invalid(self, form):
return super().form_valid(form)


class AddSuggestion(LoggedWithReadWriteHability, SingleContentFormViewMixin):
class AddSuggestion(LoggedWithReadWriteHability, PermissionRequiredMixin, SingleContentFormViewMixin):
only_draft_version = True
authorized_for_staff = True
permissions = ["tutorialv2.change_publishablecontent"]

def post(self, request, *args, **kwargs):
publication = get_object_or_404(PublishableContent, pk=kwargs["pk"])
Expand Down
18 changes: 18 additions & 0 deletions zds/utils/migrations/0024_alter_hatrequest_is_granted.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.2.11 on 2022-01-22 13:28

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("utils", "0023_move_potential_spam_to_comment_model"),
]

operations = [
migrations.AlterField(
model_name="hatrequest",
name="is_granted",
field=models.BooleanField(null=True, verbose_name="Est acceptée"),
),
]

0 comments on commit ce3cb9f

Please sign in to comment.