feat(core): numero et article

Antoine 2023-01-03 15:46:00 +01:00
Parent e2f5a683b1
révision b7f893def1
7 fichiers modifiés avec 247 ajouts et 1 suppressions

Voir le fichier

@ -1,10 +1,20 @@
from wagtail.admin.panels import FieldPanel, TabbedInterface, ObjectList
from django import forms
from django.db import models
from wagtail.admin.panels import (
FieldPanel,
FieldRowPanel,
ObjectList,
TabbedInterface,
)
from wagtail.blocks import ListBlock
from wagtail.contrib.settings.models import BaseSetting, register_setting
from wagtail.core.models import Page
from wagtail.fields import RichTextField, StreamField
from wagtail.search import index
from .blocks import BodyBlock, ListLinksBlock, TextLinkBlock
from .validators import RangePageValidator
# PAGES
@ -47,6 +57,116 @@ class StandardPage(AbstractBasePage):
FieldPanel('body'),
]
search_fields = Page.search_fields + [
index.SearchField('body'),
]
def get_futur_num():
"""renvoit le prochain numéro"""
return Numero.get_last_num() + 1
class Numero(AbstractBasePage):
"""Un numero du journal"""
# Fields
journal_numero = models.PositiveSmallIntegerField(
'Numéro', null=True, blank=True, unique=True, default=get_futur_num
)
publish_date = models.DateField(
'Date de parution',
null=True,
blank=True,
help_text="Date à laquelle le journal est paru",
)
image = models.ForeignKey(
'wagtailimages.Image',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+',
help_text="Image de la une du journal",
)
@classmethod
def get_last_num(cls):
"""retrouve le dernier numero (retourne un integer)"""
numeros = [
num.journal_numero
for num in cls.objects.all()
if isinstance(num.journal_numero, int)
] + [0]
return max(numeros)
# wagtail attributes
subpage_types = ['Article']
content_panels = Page.content_panels + [
FieldPanel('journal_numero'),
FieldPanel('publish_date'),
FieldPanel('image'),
]
class Article(StandardPage):
"""Un article du journal"""
chapeau = RichTextField(blank=True)
page_number = models.CharField(
'numero(s) de page(s)',
max_length=16,
validators=[RangePageValidator],
help_text=(
"Le numéro de page au sein du journal papier. Si l'article s'étend"
" sur plusieurs pages, vous devez les séparer avec un tiret"
),
)
image = models.ForeignKey(
'wagtailimages.Image',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+',
help_text="Illustration de l'article",
)
breve = models.BooleanField(
'brève',
default=False,
help_text="Détermine si l'article est une brève ou non",
)
parent_page_types = ['Numero']
content_panels = [
FieldPanel('title'),
FieldPanel('chapeau'),
FieldRowPanel(
[
FieldPanel(
'page_number',
widget=forms.TextInput(
attrs={'placeholder': "exemple: 1 ou 2-5"}
),
),
FieldPanel('breve'),
],
heading="Métadonnées",
),
FieldPanel('image'),
FieldPanel('body'),
]
search_fields = Page.search_fields + [
index.SearchField('body'),
]
def is_void(self):
"""return True if has no editorial content"""
return not self.chapeau and not self.body
# SITE SETTINGS
# ------------------------------------------------------------------------------

Voir le fichier

@ -0,0 +1,25 @@
from wagtail.core.models import Site
import pytest
from ..models import HomePage
from .factories import ArticleFactory, HomePageFactory, NumeroFactory
@pytest.fixture
def home_page():
site = Site.objects.get(is_default_site=True)
if not isinstance(site.root_page, HomePage):
site.root_page = HomePageFactory()
site.save()
return site.root_page
@pytest.fixture
def numeros(home_page):
return NumeroFactory.create_batch(2, parent=home_page)
@pytest.fixture
def articles(numeros):
return ArticleFactory.create_batch(3, parent=numeros[0])

Voir le fichier

@ -0,0 +1,28 @@
import factory
from wagtail_factories import PageFactory
from ..models import Article, HomePage, Numero
class HomePageFactory(PageFactory):
title = "Accueil"
class Meta:
model = HomePage
class NumeroFactory(PageFactory):
journal_numero = factory.Sequence(int)
title = factory.LazyAttribute(lambda o: f'Le numéro {o.journal_numero}')
class Meta:
model = Numero
class ArticleFactory(PageFactory):
title = factory.Faker('sentence')
chapeau = factory.Faker('sentence')
page_number = factory.Iterator(['1', '2', '3-5'])
class Meta:
model = Article

Voir le fichier

@ -0,0 +1,23 @@
import pytest
from labrique.core.models import Numero
from .factories import ArticleFactory
@pytest.mark.django_db
class TestNumero:
def test_get_last_num_no_num(self):
assert Numero.get_last_num() == 0
def test_get_last_num(self, numeros):
assert Numero.get_last_num() == 2
@pytest.mark.django_db
class TestArticle:
def test_is_void(self):
assert ArticleFactory.create().is_void() is False
def test_is_not_void(self):
assert ArticleFactory.create(chapeau='', body='').is_void() is True

Voir le fichier

@ -0,0 +1,32 @@
from django.core.exceptions import ValidationError
import pytest
from labrique.core.validators import RangePageValidator
class TestRagePageValidator:
validate_page = RangePageValidator()
@pytest.mark.parametrize('page_number', ['1', '42', '1984'])
def test_one_page(self, page_number):
assert self.validate_page(page_number) is None
@pytest.mark.parametrize(
'page_range', ['1-2', '42-43', '1-99999999999999']
)
def test_valid_range_page(self, page_range):
assert self.validate_page(page_range) is None
@pytest.mark.parametrize('page_range', ['-', '-2', '2-', '-1-1', 'spam'])
def test_invalid_range_page(self, page_range):
with pytest.raises(ValidationError):
self.validate_page(page_range)
@pytest.mark.parametrize('page_range', ['42-1', '1-0'])
def test_range_page_not_increasing(self, page_range):
with pytest.raises(ValidationError) as exc_info:
self.validate_page(page_range)
assert exc_info.value.args[0] == (
'La première page doit être inférieure à la dernière'
)

Voir le fichier

@ -0,0 +1,17 @@
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from django.utils.deconstruct import deconstructible
@deconstructible
class RangePageValidator(RegexValidator):
regex = r'^[0-9]*$|^[0-9]+\-[0-9]+$'
def __call__(self, value):
super().__call__(value)
if '-' in value:
first, last = value.split('-')
if not int(first) < int(last):
raise ValidationError(
"La première page doit être inférieure à la dernière"
)

Voir le fichier

@ -4,6 +4,7 @@
# ------------------------------------------------------------------------------
pytest
pytest-django
wagtail-factories
# Code quality
# ------------------------------------------------------------------------------