From 85f388aac26728ae21081f2db6c7631549364535 Mon Sep 17 00:00:00 2001 From: artus40 Date: Thu, 1 Mar 2018 19:10:01 +0100 Subject: [PATCH] cleaned up code --- maraudes/admin.py | 7 +--- maraudes/apps.py | 5 +-- maraudes/forms.py | 59 +++++++++++++--------------- maraudes/managers.py | 24 +++--------- maraudes/models.py | 62 ++++++++++++++--------------- maraudes/notes.py | 20 ++++++---- maraudes/tests.py | 37 ++++++++++-------- maraudes/views.py | 92 ++++++++++++++++++++++---------------------- 8 files changed, 142 insertions(+), 164 deletions(-) diff --git a/maraudes/admin.py b/maraudes/admin.py index 42507b1..85c357d 100644 --- a/maraudes/admin.py +++ b/maraudes/admin.py @@ -1,10 +1,5 @@ from django.contrib import admin -from django import forms - -from django.contrib.auth.admin import UserAdmin as BaseUserAdmin -from django.contrib.auth.models import User - from .models import * from .notes import Observation @@ -12,6 +7,7 @@ from .notes import Observation # Basic registration admin.site.register(Lieu) + # Inlines class ObservationInline(admin.StackedInline): model = Observation @@ -32,7 +28,6 @@ class RencontreAdmin(admin.ModelAdmin): list_filter = ['lieu'] - @admin.register(Maraude) class MaraudeAdmin(admin.ModelAdmin): diff --git a/maraudes/apps.py b/maraudes/apps.py index c051295..38854ea 100644 --- a/maraudes/apps.py +++ b/maraudes/apps.py @@ -2,7 +2,4 @@ from django.apps import AppConfig class Config(AppConfig): - name = 'maraudes' - - - + name = 'maraudes' \ No newline at end of file diff --git a/maraudes/forms.py b/maraudes/forms.py index e1fb0b0..306fdda 100644 --- a/maraudes/forms.py +++ b/maraudes/forms.py @@ -1,20 +1,22 @@ from django import forms +from django.utils.translation import gettext from django.utils import timezone - from django_select2.forms import Select2Widget - -# Models -from .models import * -from .notes import * from notes.forms import UserNoteForm, SimpleNoteForm from notes.models import Sujet, GENRE_CHOICES +from .models import * +from .notes import * + + +MONTHS = [ + (num, gettext(calendar.month_name[num])) for num in range(1, 13) +] def current_year_range(): """ Returns a range from year -1 to year + 2 """ year = timezone.now().date().year - return (year - 1, year, year + 1, year + 2) - + return year - 1, year, year + 1, year + 2 class MaraudeHiddenDateForm(forms.ModelForm): @@ -24,8 +26,6 @@ class MaraudeHiddenDateForm(forms.ModelForm): widgets = {'date': forms.HiddenInput()} - - class RencontreForm(forms.ModelForm): class Meta: model = Rencontre @@ -35,37 +35,33 @@ class RencontreForm(forms.ModelForm): } -ObservationInlineFormSet = forms.inlineformset_factory( Rencontre, Observation, - form=SimpleNoteForm, - extra = 1, - ) +ObservationInlineFormSet = forms.inlineformset_factory( + Rencontre, Observation, + form=SimpleNoteForm, + extra=1, +) RencontreInlineFormSet = forms.inlineformset_factory( - Maraude, Rencontre, - form = RencontreForm, - extra = 0, - ) + Maraude, Rencontre, + form=RencontreForm, + extra=0, +) ObservationInlineFormSetNoExtra = forms.inlineformset_factory( - Rencontre, Observation, - form = SimpleNoteForm, - extra = 0 - ) - + Rencontre, Observation, + form=SimpleNoteForm, + extra=0 +) class MonthSelectForm(forms.Form): month = forms.ChoiceField(label="Mois", - choices=[ - (1, 'Janvier'), (2, 'Février'), (3, 'Mars'), (4, 'Avril'), - (5, 'Mai'), (6, 'Juin'), (7, 'Juillet'), (8, 'Août'), - (9, 'Septembre'),(10, 'Octobre'),(11, 'Novembre'),(12, 'Décembre') - ], - ) + choices=MONTHS, + ) year = forms.ChoiceField(label="Année", - choices = [(y, y) for y in current_year_range()] - ) + choices=[(y, y) for y in current_year_range()], + ) def __init__(self, *args, month=None, year=None, **kwargs): super().__init__(*args, **kwargs) @@ -73,16 +69,13 @@ class MonthSelectForm(forms.Form): self.fields['year'].initial = year - class AppelForm(UserNoteForm): class Meta(UserNoteForm.Meta): model = Appel fields = ['sujet', 'text', 'entrant', 'created_date', 'created_time'] - class SignalementForm(UserNoteForm): - nom = forms.CharField(64, required=False) prenom = forms.CharField(64, required=False) age = forms.IntegerField(required=False) diff --git a/maraudes/managers.py b/maraudes/managers.py index 19cc045..4e6ccc9 100644 --- a/maraudes/managers.py +++ b/maraudes/managers.py @@ -1,11 +1,9 @@ -from django.db.models import Manager - import datetime - from django.utils import timezone from django.utils.functional import cached_property +from django.db.models import Manager + -# TODO: What is really useful in there ?? class MaraudeManager(Manager): """ Manager for Maraude objects """ @@ -33,7 +31,8 @@ class MaraudeManager(Manager): def get_future(self, date=None): """ Retourne la liste des prochaines maraudes """ - if not date: date = self.today + if not date: + date = self.today return self.get_queryset().filter( date__gte=date ).order_by( @@ -42,7 +41,8 @@ class MaraudeManager(Manager): def get_past(self, date=None): """ Retourne la liste des maraudes passées """ - if not date: date = self.today + if not date: + date = self.today return self.get_queryset().filter( date__lt=date ).order_by( @@ -81,15 +81,3 @@ class MaraudeManager(Manager): return None except self.model.DoesNotExist: return None - - - - - -class ObservationManager(Manager): - - def get_for_sujet(self, sujet): - return self.filter(sujet=sujet) - - def get_first_for_sujet(self, sujet): - return self.filter(sujet=sujet).order_by('date').first() diff --git a/maraudes/models.py b/maraudes/models.py index d3a6e15..6d434c5 100644 --- a/maraudes/models.py +++ b/maraudes/models.py @@ -1,22 +1,21 @@ import calendar import datetime -from collections import OrderedDict - -from django.utils import timezone from django.db import models from django.db.models import Count from django.core.urlresolvers import reverse +from django.utils.translation import gettext as _ from utilisateurs.models import Maraudeur from . import managers -## Fonctions utiles +# Fonctions utiles def get_referent_maraude(): """ Retourne l'administrateur et référent de la Maraude """ return Maraudeur.objects.get_referent() + def split_by_12h_blocks(iterable): """ Move object with given 'field' time under 12:00 to the end of stream. Apart from this, order is untouched. @@ -31,22 +30,20 @@ def split_by_12h_blocks(iterable): for note in to_end: yield note -## Constantes +# Constantes # Jours de la semaine WEEKDAYS = [ - (0, "Lundi"), - (1, "Mardi"), - (2, "Mercredi"), - (3, "Jeudi"), - (4, "Vendredi"), - (5, "Samedi"), - (6, "Dimanche") + (n, _(calendar.day_name[n])) for n in range(7) ] +MONTHS = { + n: _(calendar.month_name[n]) for n in range(1, 13) +} + # Horaires HORAIRES_APRESMIDI = datetime.time(16, 0) -HORAIRES_SOIREE = datetime.time(20, 0) +HORAIRES_SOIREE = datetime.time(19, 0) HORAIRES_CHOICES = ( (HORAIRES_APRESMIDI, 'Après-midi'), (HORAIRES_SOIREE, 'Soirée') @@ -60,12 +57,13 @@ DUREE_CHOICES = ( (20, '20 min'), (30, '30 min'), (45, '45 min'), - (60, '1 heure'), + (60, '1heure'), + (75, '1h15min'), + (90, '1h30min'), ) -## Modèles - +# Modèles class Lieu(models.Model): """ Lieu de rencontre """ nom = models.CharField(max_length=128) @@ -77,7 +75,6 @@ class Lieu(models.Model): verbose_name = "Lieu de rencontre" - class Maraude(models.Model): """ Modèle pour une maraude - date : jour de la maraude @@ -135,12 +132,12 @@ class Maraude(models.Model): ('view_maraudes', "Accès à l'application 'maraudes'"), ) - MOIS = ["Jan.", "Fév.", "Mars", "Avr.", "Mai", "Juin", - "Juil.", "Août", "Sept.", "Oct.", "Nov.", "Déc."] def __str__(self): - return '%s %i %s' % (WEEKDAYS[self.date.weekday()][1], # Retrieve text inside tuple - self.date.day, - self.MOIS[self.date.month - 1]) + return '%(dayname)s %(day)i %(month)s' % { + 'dayname': WEEKDAYS[self.date.weekday()][1], # Retrieve text inside tuple + 'day': self.date.day, + 'month': MONTHS[self.date.month][:3] + ".", + } def est_terminee(self): """ Indique si la maraude est considérée comme terminée """ @@ -161,7 +158,6 @@ class Maraude(models.Model): return reverse('notes:details-maraude', kwargs={'pk': self.id}) - class Rencontre(models.Model): """ Une Rencontre dans le cadre d'une maraude """ @@ -170,7 +166,7 @@ class Rencontre(models.Model): maraude = models.ForeignKey( Maraude, models.CASCADE, - related_name = 'rencontres', + related_name='rencontres', limit_choices_to={'heure_fin__isnull': False} ) lieu = models.ForeignKey( @@ -188,18 +184,19 @@ class Rencontre(models.Model): ordering = ['maraude', 'heure_debut'] def __str__(self): - return "%s à %s (%imin)" % ( - self.lieu, - self.heure_debut.strftime("%Hh%M"), - self.duree - ) + return "%(lieu)s à %(heure)s (%(duree)imin)" % { + 'lieu': self.lieu, + 'heure': self.heure_debut.strftime("%Hh%M"), + 'duree': self.duree + } @property def date(self): return self.maraude.date - INDIVIDU = "Individu" - GROUPE = "Groupe" + INDIVIDU = _("Individu") + GROUPE = _("Groupe") + def groupe_ou_individu(self): """ Retourne le type de rencontre : 'groupe'/'individu' """ nb = self.observations.count() @@ -254,7 +251,6 @@ class CompteRendu(Maraude): proxy = True - class FoyerAccueil(Lieu): """ Foyer d'hébergement partenaire """ @@ -264,7 +260,6 @@ class FoyerAccueil(Lieu): ) - class Planning(models.Model): """ Plannification des maraudes. Chaque instance représente un jour de la semaine et un horaire par défaut. @@ -293,7 +288,6 @@ class Planning(models.Model): """ Renvoie le jour et l'horaire prévu de maraude, comme un tuple, pour l'année et le mois donnés. """ - planning = Planning.get_planning() for week in calendar.monthcalendar(year, month): for planned in cls.get_planning(): day_of_maraude = week[planned.week_day] diff --git a/maraudes/notes.py b/maraudes/notes.py index 2fda646..48c5e56 100644 --- a/maraudes/notes.py +++ b/maraudes/notes.py @@ -1,7 +1,6 @@ from django.db import models - from notes.models import Note -from . import managers + # Extends 'notes' module @@ -9,7 +8,6 @@ from . import managers class Observation(Note): """ Note dans le cadre d'une rencontre """ - objects = managers.ObservationManager() rencontre = models.ForeignKey('maraudes.Rencontre', models.CASCADE, related_name="observations") @@ -25,18 +23,24 @@ class Observation(Note): def note_bg_colors(self): return "info", "info" + class Appel(Note): - entrant = models.BooleanField( "Appel entrant ?") + entrant = models.BooleanField("Appel entrant ?") - def note_labels(self): return ["Reçu" if self.entrant else "Émis", self.created_by] - def note_bg_colors(self): return "warning", "info" + def note_labels(self): + return ["Reçu" if self.entrant else "Émis", self.created_by] + + def note_bg_colors(self): + return "warning", "info" class Signalement(Note): source = models.ForeignKey("utilisateurs.Organisme") - def note_labels(self): return [self.source, self.created_by] - def note_bg_colors(self): return 'danger', 'info' + def note_labels(self): + return [self.source, self.created_by] + def note_bg_colors(self): + return 'danger', 'info' diff --git a/maraudes/tests.py b/maraudes/tests.py index 2c91ac6..7fb8d39 100644 --- a/maraudes/tests.py +++ b/maraudes/tests.py @@ -1,12 +1,11 @@ import datetime -import random from calendar import monthrange from django.test import TestCase from .models import ( Maraude, Maraudeur, Planning, - WEEKDAYS, HORAIRES_SOIREE, + HORAIRES_SOIREE, ) @@ -14,6 +13,7 @@ MARAUDE_DAYS = [ True, True, False, True, True, False, False ] + def get_maraude_days(start, end): """ Iterator that returns date of maraude within start-end range """ maraude_days = [] @@ -32,6 +32,7 @@ def get_maraude_days(start, end): return maraude_days + class PlanningTestCase(TestCase): def setUp(self): @@ -49,11 +50,13 @@ class PlanningTestCase(TestCase): def test_get_maraudes_days_for_month(self): test_values = [ - {'year': 2017, 'month': 2, -'test': [(day, HORAIRES_SOIREE) for day in (2,3,6,7,9,10,13,14,16,17,20,21,23,24,27,28)] }, - {'year': 2016, 'month': 3, -'test': [(day, HORAIRES_SOIREE) for day in (1,3,4,7,8,10,11,14,15,17,18,21,22,24,25,28,29,31)] }, - ] + {'year': 2017, 'month': 2, + 'test': [(day, HORAIRES_SOIREE) for day in (2, 3, 6, 7, 9, 10, 13, 14, 16, + 17, 20, 21, 23, 24, 27, 28)]}, + {'year': 2016, 'month': 3, + 'test': [(day, HORAIRES_SOIREE) for day in (1, 3, 4, 7, 8, 10, 11, 14, 15, + 17, 18, 21, 22, 24, 25, 28, 29, 31)]}, + ] for test in test_values: self.assertEqual(test['test'], list(Planning.get_maraudes_days_for_month(test['year'], test['month']))) @@ -61,7 +64,9 @@ class PlanningTestCase(TestCase): class MaraudeManagerTestCase(TestCase): - maraudeurs = [{"first_name": "Astérix", "last_name": "Le Gaulois"}, {"first_name": "Obélix", "last_name": "et Idéfix"}] + maraudeurs = [ + {"first_name": "Astérix", "last_name": "Le Gaulois"}, + {"first_name": "Obélix", "last_name": "et Idéfix"}] def setUp(self): first = True @@ -78,14 +83,15 @@ class MaraudeManagerTestCase(TestCase): self.past_dates = [self.today - datetime.timedelta(d) for d in (1, 3, 5)] self.future_dates = [self.today + datetime.timedelta(d) for d in (2, 4, 6)] - for date in [self.today,] + self.past_dates + self.future_dates: + for date in [self.today, ] + self.past_dates + self.future_dates: Maraude.objects.create( - date = date, - referent = self.referent, - binome = self.binome + date=date, + referent=self.referent, + binome=self.binome ) - def retrieve_date(self, maraude): + @staticmethod + def retrieve_date(maraude): return maraude.date def test_all_of(self): @@ -99,12 +105,12 @@ class MaraudeManagerTestCase(TestCase): def test_future_maraudes_no_args(self): """ La liste des futures maraudes """ - test_set = set(self.future_dates + [self.today,]) + test_set = set(self.future_dates + [self.today, ]) check_set = set(map(self.retrieve_date, Maraude.objects.get_future())) self.assertEqual(test_set, check_set) def test_future_maraudes_are_sorted_by_date(self): - check_generator = iter(sorted(self.future_dates + [self.today,])) + check_generator = iter(sorted(self.future_dates + [self.today, ])) for maraude in Maraude.objects.get_future(): self.assertEqual(maraude.date, next(check_generator)) @@ -128,7 +134,6 @@ class MaraudeManagerTestCase(TestCase): self.assertEqual(self.retrieve_date(Maraude.objects.get_next_of(self.binome)), self.today) - class MaraudeTestCase(TestCase): def test_est_terminee(self): diff --git a/maraudes/views.py b/maraudes/views.py index 78c3a28..9671ca4 100644 --- a/maraudes/views.py +++ b/maraudes/views.py @@ -1,22 +1,19 @@ import datetime import calendar import logging - +from django.conf import settings from django.utils import timezone from django.shortcuts import redirect, reverse from django.views import generic from django.core.mail import send_mail from django.forms import modelformset_factory from django.contrib import messages - from utilisateurs.mixins import MaraudeurMixin - from .models import (Maraude, Maraudeur, CompteRendu, - Rencontre, Lieu, + Lieu, Planning,) from .notes import Signalement -# Forms from .forms import (RencontreForm, ObservationInlineFormSet, MaraudeHiddenDateForm, MonthSelectForm, @@ -26,6 +23,9 @@ from notes.mixins import NoteFormMixin logger = logging.getLogger(__name__) +# How many month shall we look back +NUMBER_OF_MONTH_BACKWARDS = 1 # Must be lower than 12 ! + def derniers_sujets_rencontres(): """ Renvoie le 'set' des sujets rencontrés dans les deux dernières maraudes """ @@ -38,11 +38,8 @@ def derniers_sujets_rencontres(): def derniers_sujets_signales(): def recent_filter(qs): - NUMBER_OF_MONTH_BACKWARDS = 1 # Must be lower than 12 ! - current_date = timezone.localtime(timezone.now()).date() recent_dates = [(current_date.month, current_date.year)] - for i in range(1, NUMBER_OF_MONTH_BACKWARDS + 1): prev_month, prev_year = current_date.month - i, current_date.year if prev_month <= 0: @@ -56,7 +53,6 @@ def derniers_sujets_signales(): filtered = [] for month, year in recent_dates: filtered += list(qs.filter(created_date__year=year, created_date__month=month)) - return filtered return recent_filter(Signalement.objects.all()) @@ -66,7 +62,7 @@ class IndexView(NoteFormMixin, MaraudeurMixin, generic.TemplateView): template_name = "maraudes/index.html" - #NoteFormMixin + # NoteFormMixin forms = { 'appel': AppelForm, 'signalement': SignalementForm, @@ -89,18 +85,19 @@ class IndexView(NoteFormMixin, MaraudeurMixin, generic.TemplateView): if self.request.user.is_superuser: context['missing_cr'] = CompteRendu.objects.get_queryset().filter( heure_fin__isnull=True, - date__lt = timezone.localtime(timezone.now()).date() + date__lt=timezone.localtime(timezone.now()).date() ) return context -## COMPTE-RENDU DE MARAUDE +# COMPTE-RENDU DE MARAUDE def redirect_to_current_compterendu(request): maraude_en_cours = Maraude.objects.get_in_progress() if not maraude_en_cours: + messages.warning(request, "Il n'y a actuellement aucune maraude en cours !") return redirect("maraudes:index") kwargs = {'pk': maraude_en_cours.pk} @@ -128,7 +125,7 @@ class CompteRenduCreateView(MaraudeurMixin, generic.DetailView): instance=self.form.instance ) - def post(self, request, *args, **kwargs): + def post(self, request, **kwargs): self.get_forms(request.POST, request.FILES) if self.form.has_changed(): if not self.form.is_valid() or not self.inline_formset.is_valid(): @@ -145,8 +142,10 @@ class CompteRenduCreateView(MaraudeurMixin, generic.DetailView): def calculate_end_time(debut, duree): end_minute = debut.minute + duree hour = debut.hour + end_minute // 60 - if hour >= 24: hour -= 24 - elif hour < 0: hour += 24 + if hour >= 24: + hour -= 24 + elif hour < 0: + hour += 24 minute = end_minute % 60 return datetime.time( hour, @@ -179,10 +178,9 @@ class CompteRenduCreateView(MaraudeurMixin, generic.DetailView): return context - -class FinalizeView( MaraudeurMixin, - generic.detail.SingleObjectMixin, - generic.edit.FormView): +class FinalizeView(MaraudeurMixin, + generic.detail.SingleObjectMixin, + generic.edit.FormView): template_name = "maraudes/finalize.html" model = Maraude @@ -190,8 +188,7 @@ class FinalizeView( MaraudeurMixin, success_url = "/maraudes/" def get(self, *args, **kwargs): - print(self.request.GET) - if bool(self.request.GET.get("no_mail", False)) == True: + if bool(self.request.GET.get("no_mail", False)): messages.warning(self.request, "Aucun compte-rendu n'a été envoyé !") return self.finalize() return super().get(*args, **kwargs) @@ -232,23 +229,25 @@ class FinalizeView( MaraudeurMixin, ) if result == 1: - messages.success(self.request, "Le compte-rendu a été transmis à %s" % ", ".join(map(str, recipients))) + if settings.DEBUG: + messages.warning(self.request, "En mode DEBUG, le compte-rendu n'est pas réellement envoyé !") + else: + messages.success(self.request, "Le compte-rendu a été transmis à %s" % ", ".join(map(str, recipients))) else: messages.error(self.request, "Erreur lors de l'envoi du message !") return self.finalize() def get_context_data(self, **kwargs): - self.object = self.get_object() + obj = self.get_object() context = super().get_context_data(**kwargs) - if self.object.est_terminee is True: - context['form'] = None#Useless form + if obj.est_terminee is True: + context['form'] = None # Useless form return context # Link there so that "Compte-rendu" menu item is not disabled - context['prochaine_maraude'] = self.object + context['prochaine_maraude'] = obj return context - class PlanningView(MaraudeurMixin, generic.TemplateView): """ Vue d'édition du planning des maraudes """ @@ -256,10 +255,14 @@ class PlanningView(MaraudeurMixin, generic.TemplateView): def _parse_request(self): self.current_date = datetime.date.today() - try: self.month = int(self.request.GET['month']) - except: self.month = self.current_date.month - try: self.year = int(self.request.GET['year']) - except: self.year = self.current_date.year + try: + self.month = int(self.request.GET['month']) + except ValueError: + self.month = self.current_date.month + try: + self.year = int(self.request.GET['year']) + except ValueError: + self.year = self.current_date.year def _calculate_initials(self): self._parse_request() @@ -267,7 +270,7 @@ class PlanningView(MaraudeurMixin, generic.TemplateView): for day, time in Planning.get_maraudes_days_for_month(self.year, self.month): date = datetime.date(self.year, self.month, day) try: - maraude = Maraude.objects.get(date=date) + Maraude.objects.get(date=date) except Maraude.DoesNotExist: self.initials.append({ 'date': date, @@ -284,26 +287,26 @@ class PlanningView(MaraudeurMixin, generic.TemplateView): self._calculate_initials() return modelformset_factory( Maraude, - form = MaraudeHiddenDateForm, - extra = len(self.initials), + form=MaraudeHiddenDateForm, + extra=len(self.initials), )( *args, - queryset = self.get_queryset(), - initial = self.initials + queryset=self.get_queryset(), + initial=self.initials ) def post(self, request): - self.formset = self.get_formset(request.POST, request.FILES) - for form in self.formset.forms: + formset = self.get_formset(request.POST, request.FILES) + for form in formset.forms: if form.is_valid(): form.save() else: logger.info("Form was ignored ! (%s)" % (form.errors.as_data())) return redirect('maraudes:planning') - def get(self, request): + def get(self, request, *args, **kwargs): self.formset = self.get_formset() - return super().get(request) + return super().get(request, *args, **kwargs) def get_weeks(self): """ List of (day, form) tuples, split by weeks """ @@ -319,7 +322,7 @@ class PlanningView(MaraudeurMixin, generic.TemplateView): day = yield None day = yield form - while True: # Avoid StopIteration + while True: # Avoid StopIteration day = yield None form_or_none = form_generator(self.formset) @@ -330,8 +333,8 @@ class PlanningView(MaraudeurMixin, generic.TemplateView): for week in calendar.monthcalendar(self.year, self.month) ] - def get_context_data(self, *args, **kwargs): - context = super().get_context_data(*args, **kwargs) + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) context['weekdays'] = ["Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"] context['weeks'] = self.get_weeks() @@ -341,7 +344,6 @@ class PlanningView(MaraudeurMixin, generic.TemplateView): return context - class LieuCreateView(generic.edit.CreateView): """ Vue de création d'un lieu """ @@ -359,6 +361,6 @@ class LieuCreateView(generic.edit.CreateView): context = super().get_context_data(**kwargs) try: context['next'] = self.request.GET['next'] - except: + except KeyError: context['next'] = None return context