Commit cafdb48d authored by cynddl's avatar cynddl

Add edit and preview views for articles

parent 2f289bad
......@@ -12,24 +12,38 @@ STATUS_CHOICES = (
("REJECTED", _("Rejected"))
)
URL_HELP_TEXT = """The URL should not contain any marketing tags. We
automatically strip the most known tags."""
TITLE_HELP_TEXT = """Please remove non-necessary parts such as newspapers'
names and leave only the article title."""
EXTRACTS_HELP_TEXT = """Please select short and helpful extracts from the
article content. You should aim at around 500 characters. Use bracket ellipsis
[…] to cut parts not required to understand the context."""
class Article(VoteMixin):
url = models.URLField("URL")
url = models.URLField("URL", help_text=URL_HELP_TEXT)
lang = models.CharField(_("Language"), max_length=50, null=True)
metadata = models.TextField(_("Opengraph metadata"), blank=True, null=True)
screenshot = models.ImageField(_("Article screenshot"),
blank=True, null=True)
title = models.CharField(_("Article title"), max_length=255, default="")
metadata = models.TextField(
_("Opengraph metadata"), blank=True, null=True)
screenshot = models.ImageField(
_("Article screenshot"), blank=True, null=True)
title = models.CharField(
_("Article title"), max_length=255, default="",
help_text=TITLE_HELP_TEXT)
website = models.CharField(_("Website"), max_length=255, default="")
extracts = models.TextField(_("Content extracts"), blank=True, null=True)
extracts = models.TextField(
_("Content extracts"), blank=True, null=True,
help_text=EXTRACTS_HELP_TEXT)
created_at = models.DateTimeField(_("Creation date"), auto_now_add=True)
updated_at = models.DateTimeField(_("Last update"), auto_now=True)
published_at = models.DateTimeField(_("Publication date"),
blank=True, null=True)
published_at = models.DateTimeField(
_("Publication date"), blank=True, null=True)
status = models.CharField(
_("Status"), choices=STATUS_CHOICES,
default="PENDING", max_length=20)
_("Status"), choices=STATUS_CHOICES, default="PENDING", max_length=20)
#: priority: True if article have priority
priority = models.BooleanField(default=False)
......
{% extends "base.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% load crispy_forms_field %}
{% block content-banner %}
{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-12 white-bg">
<div class="well">
<div class="d-flex justify-content-start align-items-baseline mb-4">
<p class="lead">
<a class="btn btn-outline-primary" href="{% url 'rp:article-list' filter_view='draft' %}">
<i class="fa fa-chevron-left" aria-hidden="true"></i> Pending articles
</a>
<span class="ml-2"><strong>Article ID #{{object.id}}</strong></span>
</p>
<div class="ml-auto">
<span class="btn-group" role="group" aria-label="Actions">
<a class="btn btn-outline-primary" href="{% url 'rp:article-edit' object.id %}">Éditer</a>
<input type="submit" class="btn btn-outline-warning" name="publish" value="Publier">
</span>
</div>
</div>
<div class="row">
<div class="col-sm-3">
{% if object.screenshot %}
<img class="img-responsive mb-4"
src="/media/{{ object.screenshot }}">
{% endif %}
</div>
<div class="col-sm-9 lead">
<h4>{{object.title}}</h4>
<p>{{article.created_at.date}}
{% for t in article.tags.all %}
<span class="badge badge-default ml-1">{{t}}</span>
{% endfor %}
</p>
<p>{{object.extracts}}</p>
</div>
</div>
</div>
</div>
{% endblock %}
{% extends "base.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% load crispy_forms_field %}
{% block content-banner %}
{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-12 white-bg">
<div class="well">
<form class="" action="#" method="post">
<div class="d-flex justify-content-start align-items-baseline mb-4">
<p class="lead">
<a class="btn btn-outline-primary" href="{{request.META.HTTP_REFERER}}"><i class="fa fa-chevron-left" aria-hidden="true"></i> Go back</a>
<span class="ml-2"><strong>Article ID #{{object.id}}</strong> – proposé par XXX</span></span>
</p>
<div class="ml-auto">
<span>Save and&nbsp;</span>
<span class="btn-group" role="group" aria-label="Actions">
<input type="submit" class="btn btn-outline-primary" name="preview" value="Prévisualiser">
<input type="submit" class="btn btn-outline-warning" name="publish" value="Publier">
</span>
</div>
</div>
{% crispy form %}
</form>
</div>
</div>
{% endblock %}
{% extends "base.html" %}
{% block content %}
{% block content-header %}
<div class="row justify-content-left">
<div class="col-md-6 offset-md-1">
<h4>Participez à l'aventure !</h4>
<p>En tant que padawan
<img class="inline-image" role="img" src="{% static 'img/padawan.svg' %}" />,
aidez-nous à sélectionner les prochains articles à intégrer dans la
revue de presse en votant pour les meilleurs. Les jedis
<img class="inline-image" role="img" src="{% static 'img/jedi.svg' %}" />
s'occupent ensuite de la relecture et de la mise en page des articles.
</p>
<p>Faites-vous connaître sur le
<a target="_blank" href="https://www.laquadrature.net/wiki/IRC">salon IRC #lqdn-rp</a>
où il vous sera fait bon accueil, ou en nous
<a target="_blank" href="https://www.laquadrature.net/fr/contact">contactant par email</a>.
</p>
</div>
<div class="col-md-4">
<h4>Comment sélectionner un article ?</h4>
<ol>
<li>Il aborde les sujets sur lesquels La Quadrature est engagée (paquet télécom, ACTA, <i>etc.</i>).</li>
<li>Il reflète ou appuie l'avis de La Quadrature.</li>
<li>Il provient prioritairement de médias importants (presse nationale, régionale ou internationale).</li>
</ol>
</div>
</div>
{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-12 white-bg">
<ul class="nav nav-integrated">
......@@ -88,7 +118,7 @@
<i class="fa fa-times" aria-hidden="true"></i> Rejeter
</li>
{% else %}
<li class="actions-item actions-item-edit"><a href="#">
<li class="actions-item actions-item-edit"><a href="{% url 'rp:article-edit' article.id %}">
<i class="fa fa-pencil" aria-hidden="true"></i> Éditer</a>
</li>
<li class="actions-item actions-item-publish" onclick="javascript:call_publish({{article.id}})">
......
from django.conf.urls import url
from rp.views.articles import ArticleListFlux
from rp.views.articles import ArticleListFlux, ArticleEdit, ArticleDetailView
urlpatterns = [
url(
......@@ -12,4 +12,19 @@ urlpatterns = [
ArticleListFlux.as_view(),
name="article-list"
),
url(
r"^article/edit/(?P<pk>\d+)",
ArticleEdit.as_view(),
name="article-edit"
),
url(
r"^article/view/(?P<pk>\d+)",
ArticleDetailView.as_view(),
name="article-view"
),
url(
r"^article/preview/(?P<pk>\d+)",
ArticleDetailView.as_view(preview=True),
name="article-preview"
)
]
from django.http import HttpResponseRedirect
from django.views.generic.detail import DetailView
from django.views.generic.edit import UpdateView
from django.urls import reverse
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, Layout, Field, Div, HTML
from crispy_forms.bootstrap import AppendedText
from rp.models import Article
from .votes import UDList
......@@ -31,3 +42,69 @@ class ArticleListFlux(UDList):
"status='PENDING'"
]).count()
return context
class ArticleDetailView(DetailView):
model = Article
preview = False
def get_context_data(self, **kwargs):
context = super(ArticleDetailView, self).get_context_data(**kwargs)
context['is_preview'] = self.preview
return context
class ArticleEdit(UpdateView):
model = Article
fields = ['screenshot', 'url', 'lang', 'title', 'tags', 'extracts']
success_url = 'article-list'
def form_valid(self, form):
self.object = form.save()
if "preview" in self.request.POST:
self.success_url = reverse("rp:article-preview", args=[self.object.id])
elif "publish" in self.request.POST:
self.object.status = "PUBLISHED"
self.object.save()
self.success_url = reverse("rp:article-list")
return HttpResponseRedirect(self.get_success_url())
def get_form(self, form_class=None):
form = super().get_form(form_class)
form.fields["screenshot"].widget = forms.widgets.FileInput()
form.helper = FormHelper()
form.helper.form_tag = False
left_layout = Div(
Div(
Field('title', wrapper_class='col-sm-10'),
Field('lang', wrapper_class='col-sm-2'),
css_class="row"),
AppendedText('url',
'<a href="%s">Go to link</a>' % form.initial['url']),
'tags',
'extracts',
css_class="col-sm-8")
right_layout = Div(
'screenshot',
HTML(
"""
{% if form.screenshot.value %}
<img class="img-responsive mb-4"
src="/media/{{ form.screenshot.value }}">
{% endif %}
"""
),
css_class="col-sm-4")
form.helper.layout = Layout(
Div(left_layout, right_layout, css_class="row"))
form.helper.add_input(
Submit('submit', 'Update the article', css_class='btn-primary'))
return form
......@@ -20,6 +20,7 @@ CONTRIB_APPS = [
# https://github.com/philipn/django-rest-framework-filters
# "rest_framework_filters",
"taggit",
"crispy_forms"
]
if DEBUG:
......@@ -38,3 +39,5 @@ INSTALLED_APPS = DJANGO_APPS + CONTRIB_APPS + PROJECT_APPS
# Use username for upvote instead of user object
UND_USE_USERNAME = True
CRISPY_TEMPLATE_PACK = "bootstrap4"
......@@ -2,7 +2,9 @@
rp_new URL Configuration
"""
from django.conf import settings
from django.conf.urls import url, include
from django.conf.urls.static import static
from django.contrib import admin
# Django rest framework router
......@@ -17,3 +19,10 @@ urlpatterns = [
url(r"^api/", include(router.urls, namespace="api")),
url(r"^rp/", include("rp.urls", namespace="rp"))
]
if settings.DEBUG:
# Serve static files in DEBUG mode
urlpatterns += static(
settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT
)
......@@ -120,39 +120,16 @@
</div>
<section class="container-fluid light-grey-bg">
<div id="subtitle" class="text-center row justify-content-center">
{% block content-banner %}
<div id="main-banner" class="text-center row justify-content-center">
<div class="page-header col-md-10">
<h1><span>Bienvenue sur la revue de presse de La Quadrature</span></h1>
</div>
</div>
{% endblock %}
<div class="row justify-content-left">
<div class="col-md-6 offset-md-1">
<h4>Participez à l'aventure !</h4>
<p>En tant que padawan
<img class="inline-image" role="img" src="{% static 'img/padawan.svg' %}" />,
aidez-nous à sélectionner les prochains articles à intégrer dans la
revue de presse en votant pour les meilleurs. Les jedis
<img class="inline-image" role="img" src="{% static 'img/jedi.svg' %}" />
s'occupent ensuite de la relecture et de la mise en page des articles.
</p>
<p>Faites-vous connaître sur le
<a target="_blank" href="https://www.laquadrature.net/wiki/IRC">salon IRC #lqdn-rp</a>
où il vous sera fait bon accueil, ou en nous
<a target="_blank" href="https://www.laquadrature.net/fr/contact">contactant par email</a>.
</p>
</div>
<div class="col-md-4">
<h4>Comment sélectionner un article ?</h4>
<ol>
<li>Il aborde les sujets sur lesquels La Quadrature est engagée (paquet télécom, ACTA, <i>etc.</i>).</li>
<li>Il reflète ou appuie l'avis de La Quadrature.</li>
<li>Il provient prioritairement de médias importants (presse nationale, régionale ou internationale).</li>
</ol>
</div>
</div>
{% block content-header %}
{% endblock %}
</section>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment