from django.http import HttpResponseRedirect
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from django.views.generic.edit import UpdateView
from django.utils.translation import ugettext_lazy as _
from django.urls import reverse, reverse_lazy
from django.db.models import Count
from django.db.models import Q
from django import forms
from django.contrib.auth.mixins import (LoginRequiredMixin,
PermissionRequiredMixin)
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Field, Div, HTML
from crispy_forms.bootstrap import AppendedText
from taggit.models import Tag
from rp.forms import TagMultipleChoiceField
from rp.models import Article
class ArticleFilterMixin:
"""
This mixin allows to filter views using various parameters in the query
string.
"""
archive = 'both'
quote = 'both'
speak = 'both'
def get_queryset(self):
qs = super().get_queryset()
# Tags filtering
self.quote = self.request.GET.get('quote', self.quote)
self.speak = self.request.GET.get('speak', self.speak)
self.archive = self.request.GET.get('archive', self.archive)
if self.speak != 'both':
if self.speak == 'true':
qs = qs.filter(speak=True)
else:
qs = qs.filter(speak=False)
if self.quote != 'both':
if self.quote == 'true':
qs = qs.filter(quote=True)
else:
qs = qs.filter(quote=False)
if self.archive != 'both':
if self.archive == 'true':
qs = qs.filter(archive=True)
else:
qs = qs.filter(archive=False)
search_keywords = self.request.GET.get('q', '')
if search_keywords != '':
qs = qs.filter(Q(title__icontains=search_keywords)
| Q(extracts__icontains=search_keywords))
return qs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["search"] = self.request.GET.get('q', '')
context["archive"] = self.request.GET.get('archive', self.archive)
context["speak"] = self.request.GET.get('speak', self.speak)
context["quote"] = self.request.GET.get('quote', self.quote)
return context
class ArticleList(ArticleFilterMixin, ListView):
model = Article
paginate_by = 10
template_name = "rp/article_list_public.html"
filter_lang = None
filter_tag = None
archive = 'false' # We do not want to display archived items by default
def get_queryset(self):
qs = super().get_queryset()
if self.filter_lang in ["EN", "FR"]:
qs = qs.filter(lang=self.filter_lang)
else:
qs = qs.filter()
filter_tag = self.kwargs.get("filter_tag", self.filter_tag)
if filter_tag is not None:
qs = qs.filter(tags__name__in=[filter_tag])
return qs.order_by('-created_at')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
qs = Tag.objects.annotate(
num_times=Count('taggit_taggeditem_items')).all()
qs = qs.order_by('-num_times')
context["tags"] = qs
return context
class ArticleListFlux(LoginRequiredMixin, ArticleFilterMixin, ListView):
model = Article
paginate_by = 10
def get_queryset(self):
filter_view = self.kwargs.get("filter_view", "draft")
qs = super().get_queryset()
if filter_view in ["published", "draft", "rejected"]:
qs = qs.filter(status=filter_view.upper())
else:
qs = qs.filter(status="NEW")
return qs.order_by('-created_at')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["filter_view"] = self.kwargs.get("filter_view", "draft")
context["nb_draft"] = Article.objects.filter(status="DRAFT").count()
return context
class ArticleDetailView(LoginRequiredMixin, 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(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
model = Article
permission_required = 'rp.can_edit'
raise_exception = True
fields = ['screenshot', 'url', 'lang', 'title', 'tags', 'extracts',
'quote', 'speak', 'archive']
success_url = reverse_lazy("rp:article-list")
def get(self, request, **kwargs):
self.object = self.get_object()
if 'fetch_content' in self.request.GET:
self.object.fetch_content()
elif 'fetch_image' in self.request.GET:
self.object.fetch_image()
elif 'fetch_metadata' in self.request.GET:
self.object.fetch_metadata()
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
def form_valid(self, form):
self.object = form.save(commit=False)
if "preview" in self.request.POST:
self.success_url = reverse("rp:article-preview", args=[self.object.id])
elif "view" in self.request.POST:
self.success_url = reverse("rp:article-view", args=[self.object.id])
elif "publish" in self.request.POST:
self.object.publish()
self.object.save()
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
# Change the layout of the tags field
form.fields["tags"] = TagMultipleChoiceField(
queryset=Tag.objects.all(), required=False)
left_layout = Div(
Div(
Field('title', wrapper_class='col-sm-10'),
Field('lang', wrapper_class='col-sm-2'),
css_class="row"),
AppendedText(
'url',
_('Go to link') % form.initial['url']),
'tags',
'extracts',
css_class="col-sm-8")
right_layout = Div(
'screenshot',
HTML(
"""
{% if form.screenshot.value %}
{% endif %}
"""
),
css_class="col-sm-4")
form.helper.layout = Layout(
Div(left_layout, right_layout, css_class="row"))
return form