277 lines
9.1 KiB
Python
277 lines
9.1 KiB
Python
import logging
|
|
import datetime
|
|
|
|
from django.shortcuts import redirect, reverse
|
|
from django.views import generic
|
|
from django.utils import timezone
|
|
from django.contrib import messages
|
|
from django.http.response import HttpResponseNotAllowed
|
|
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
|
|
|
from utilisateurs.mixins import MaraudeurMixin
|
|
from maraudes.models import Maraude, CompteRendu
|
|
from maraudes.notes import Observation
|
|
from .models import Sujet, Note
|
|
from .forms import SujetCreateForm, AutoNoteForm, SelectSujetForm
|
|
from .mixins import NoteFormMixin
|
|
from .actions import merge_two
|
|
|
|
logger = logging.getLogger(__name__)
|
|
# Create your views here.
|
|
|
|
|
|
|
|
class IndexView(MaraudeurMixin, generic.TemplateView):
|
|
template_name = "notes/index.html"
|
|
|
|
def get(self, *args, **kwargs):
|
|
return redirect("notes:liste-sujet")
|
|
|
|
class Filter:
|
|
def __init__(self, title, name, filter_func):
|
|
self.title = title
|
|
self.parameter_name = name
|
|
self.active = False
|
|
self._filter_func = filter_func
|
|
|
|
def filter(self, qs):
|
|
return self._filter_func(qs)
|
|
|
|
|
|
|
|
class ListView(MaraudeurMixin, generic.ListView):
|
|
""" Base ListView for Maraude and Sujet lists """
|
|
paginate_by = 30
|
|
cell_template = None
|
|
|
|
filters = []
|
|
active_filter = None
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self._filters = {}
|
|
|
|
if self.filters:
|
|
for i, (title, func) in enumerate(self.filters):
|
|
_id = "filter_%i" % i
|
|
self._filters[_id] = Filter(title, _id, func)
|
|
|
|
def get(self, request, **kwargs):
|
|
filter_name = self.request.GET.get('filter', None)
|
|
if filter_name:
|
|
self.active_filter = self._filters.get(filter_name, None)
|
|
if self.active_filter:
|
|
self.active_filter.active = True
|
|
|
|
return super().get(request, **kwargs)
|
|
|
|
def get_queryset(self):
|
|
qs = super().get_queryset()
|
|
if self.active_filter:
|
|
qs = self.active_filter.filter(qs)
|
|
return qs
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context["filters"] = self._filters.values()
|
|
context["table_cell_template"] = getattr(self, 'cell_template', None)
|
|
context["table_header"] = getattr(self, 'table_header', None)
|
|
return context
|
|
|
|
|
|
class MaraudeListView(ListView):
|
|
""" Vue de la liste des compte-rendus de maraude """
|
|
|
|
model = CompteRendu
|
|
template_name = "notes/liste_maraudes.html"
|
|
cell_template = "notes/table_cell_maraudes.html"
|
|
table_header = "Liste des maraudes"
|
|
|
|
queryset = Maraude.objects.get_past().order_by("-date")
|
|
|
|
filters = [
|
|
("Ce mois-ci", lambda qs: qs.filter(date__month=timezone.now().date().month)),
|
|
]
|
|
|
|
|
|
class SujetListView(ListView):
|
|
#ListView
|
|
model = Sujet
|
|
template_name = "notes/liste_sujets.html"
|
|
cell_template = "notes/table_cell_sujets.html"
|
|
table_header = "Liste des sujets"
|
|
|
|
|
|
def info_completed_filter(qs):
|
|
COMPLETED_RATIO = 70 # % of total fields completed
|
|
|
|
excluded_set = set()
|
|
for sujet in qs:
|
|
if sujet.statistiques.info_completed >= COMPLETED_RATIO:
|
|
excluded_set.add(sujet.pk)
|
|
|
|
return qs.exclude(pk__in=excluded_set)
|
|
|
|
def rencontre_dans_le_mois(qs):
|
|
""" Renvoie les sujets du queryset pour lesquelles une observation a été enregistrée
|
|
au cours des 30 derniers jours """
|
|
DAYS_NUMBER = 30
|
|
LIMIT_DATE = timezone.now().date() - datetime.timedelta(DAYS_NUMBER)
|
|
|
|
included_set = set()
|
|
for sujet in qs:
|
|
# Try to find an observation in the range
|
|
most_recent_obs = Observation.objects.filter(sujet=sujet).order_by("-created_date").first()
|
|
if most_recent_obs and most_recent_obs.created_date >= LIMIT_DATE:
|
|
included_set.add(sujet.pk)
|
|
return qs.filter(pk__in=included_set)
|
|
|
|
|
|
filters = [
|
|
("Connu(e)s cette année",
|
|
lambda qs: qs.filter(
|
|
premiere_rencontre__year=timezone.now().date().year)
|
|
),
|
|
("Rencontré(e)s dans le mois", rencontre_dans_le_mois),
|
|
("Statistiques incomplètes", info_completed_filter),
|
|
]
|
|
|
|
def post(self, request, **kwargs):
|
|
from watson import search as watson
|
|
search_text = request.POST.get('q')
|
|
results = watson.filter(Sujet, search_text)
|
|
#logger.warning("SEARCH for %s : %s" % (search_text, results))
|
|
if results.count() == 1:
|
|
return redirect(results[0].get_absolute_url())
|
|
self.queryset = results
|
|
return self.get(request, **kwargs)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['query_text'] = self.request.POST.get('q', None)
|
|
return context
|
|
|
|
|
|
class DetailView(MaraudeurMixin, generic.DetailView):
|
|
template_name = "notes/details.html"
|
|
|
|
class CompteRenduDetailsView(DetailView):
|
|
""" Vue détaillé d'un compte-rendu de maraude """
|
|
|
|
model = CompteRendu
|
|
context_object_name = "maraude"
|
|
template_name = "notes/details_maraude.html"
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['notes'] = sorted(Note.objects.get_queryset().filter(created_date=self.object.date), key=lambda n: n.created_time)
|
|
context['next_maraude'] = Maraude.objects.get_future(
|
|
date=self.object.date + datetime.timedelta(1)
|
|
).filter(
|
|
heure_fin__isnull=False
|
|
).first()
|
|
context['prev_maraude'] = Maraude.objects.get_past(
|
|
date=self.object.date
|
|
).filter(
|
|
heure_fin__isnull=False
|
|
).last()
|
|
return context
|
|
|
|
|
|
class SuiviSujetView(NoteFormMixin, DetailView):
|
|
#NoteFormMixin
|
|
forms = {
|
|
'note': AutoNoteForm,
|
|
}
|
|
def get_success_url(self):
|
|
return reverse('notes:details-sujet', kwargs={'pk': self.get_object().pk})
|
|
def get_form_kwargs(self):
|
|
kwargs = super().get_form_kwargs()
|
|
kwargs['sujet'] = self.get_object()
|
|
return kwargs
|
|
#DetailView
|
|
model = Sujet
|
|
template_name = "notes/details_sujet.html"
|
|
context_object_name = "sujet"
|
|
# Paginator
|
|
per_page = 5
|
|
|
|
def get(self, *args, **kwargs):
|
|
self.paginator = Paginator(
|
|
self.get_object().notes.by_date(reverse=True),
|
|
self.per_page
|
|
)
|
|
self.page = self.request.GET.get('page', 1)
|
|
return super().get(*args, **kwargs)
|
|
|
|
def get_context_data(self, *args, **kwargs):
|
|
context = super().get_context_data(*args, **kwargs)
|
|
try:
|
|
notes = self.paginator.page(self.page)
|
|
except PageNotAnInteger:
|
|
notes = self.paginator.page(1)
|
|
except EmptyPage:
|
|
notes = self.paginator.page(self.paginator.num_pages)
|
|
context['notes'] = notes
|
|
return context
|
|
|
|
|
|
### Sujet Management Views
|
|
|
|
class SujetAjaxDetailsView(generic.DetailView):
|
|
#DetailView
|
|
template_name = "notes/details_sujet_inner.html"
|
|
model = Sujet
|
|
|
|
http_method_names = ["get"]
|
|
|
|
def get(self, *args, **kwargs):
|
|
""" Redirect to complete details view if request is not ajax """
|
|
if not self.request.is_ajax():
|
|
return redirect("notes:details-sujet", pk=self.get_object().pk)
|
|
return super().get(*args, **kwargs)
|
|
|
|
class SujetAjaxUpdateView(generic.edit.UpdateView):
|
|
#UpdateView
|
|
template_name = "notes/details_sujet_update.html"
|
|
model = Sujet
|
|
fields = '__all__'
|
|
|
|
def get_success_url(self):
|
|
return reverse("notes:details-sujet", kwargs={'pk': self.object.pk})
|
|
|
|
from website.mixins import AjaxTemplateMixin
|
|
|
|
class SujetCreateView(AjaxTemplateMixin, generic.edit.CreateView):
|
|
#CreateView
|
|
template_name = "notes/sujet_create.html"
|
|
form_class = SujetCreateForm
|
|
def post(self, request, *args, **kwargs):
|
|
if 'next' in self.request.POST:
|
|
self.success_url = self.request.POST["next"]
|
|
return super().post(self, request, *args, **kwargs)
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
try: context['next'] = self.request.GET['next']
|
|
except:context['next'] = None
|
|
return context
|
|
|
|
class MergeView(generic.DetailView, generic.FormView):
|
|
""" Implement actions.merge_two as a view """
|
|
|
|
template_name = "notes/sujet_merge.html"
|
|
model = Sujet
|
|
form_class = SelectSujetForm
|
|
|
|
def form_valid(self, form):
|
|
slave = self.get_object()
|
|
master = form.cleaned_data['sujet']
|
|
try:
|
|
merge_two(master, slave)
|
|
except Exception as e:
|
|
logger.error("Merge: ", e)
|
|
messages.error(self.request, "La fusion vers %s a échoué !" % master)
|
|
return redirect(slave)
|
|
messages.success(self.request, "%s vient d'être fusionné" % slave)
|
|
return redirect(master)
|