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