From 2e690ae9a3e16486c436a2cf8da346bc0577eaef Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Sun, 26 Jul 2020 11:30:26 +0200 Subject: [PATCH] doc: add doctrings --- rental/admin.py | 2 ++ rental/enums.py | 3 ++ rental/forms/booking.py | 6 ++-- rental/forms/contact.py | 7 +++-- rental/models/booking.py | 25 +++++++++++------ rental/models/contact.py | 9 +++++- rental/models/guest.py | 1 + rental/models/picture.py | 2 ++ rental/models/place.py | 7 ++++- rental/models/testimonial.py | 11 ++++++-- rental/tasks/{apiMailer.py => api_mailer.py} | 29 ++++++++++---------- rental/tasks/{gMailer.py => g_mailer.py} | 23 ++++++++-------- rental/urls.py | 4 ++- rental/views/booking.py | 22 +++++++++------ rental/views/contact.py | 2 ++ rental/views/errors.py | 4 ++- rental/views/place.py | 4 ++- villafleurie/celery.py | 5 ++++ villafleurie/settings/base.py | 2 ++ villafleurie/settings/development.py | 4 ++- villafleurie/settings/production.py | 2 ++ villafleurie/urls.py | 6 ++-- 22 files changed, 121 insertions(+), 59 deletions(-) rename rental/tasks/{apiMailer.py => api_mailer.py} (88%) rename rental/tasks/{gMailer.py => g_mailer.py} (94%) diff --git a/rental/admin.py b/rental/admin.py index aa8b113..95fe245 100644 --- a/rental/admin.py +++ b/rental/admin.py @@ -1,3 +1,5 @@ +""" Register models and configure admin dashboard """ + from django.contrib import admin from rental.models.booking import Booking diff --git a/rental/enums.py b/rental/enums.py index 32eb66a..68095f2 100644 --- a/rental/enums.py +++ b/rental/enums.py @@ -3,5 +3,8 @@ from django.utils.translation import gettext_lazy as _ class PlaceNames(models.TextChoices): + """ PlaceNames enums serve to list places and prepare + for internationalisation + """ T2 = "T2", _("T2") T3 = "T3", _("T3") diff --git a/rental/forms/booking.py b/rental/forms/booking.py index f20f656..91b4ed5 100644 --- a/rental/forms/booking.py +++ b/rental/forms/booking.py @@ -1,11 +1,13 @@ from django import forms from rental.enums import PlaceNames -from rental.models.booking import Booking -from rental.models.place import Place class BookingForm(forms.Form): + """ + BookingForm serve to validate input and create a new booking. + doc: https://docs.djangoproject.com/fr/2.2/topics/forms/modelforms/ + """ name = forms.CharField( label="", diff --git a/rental/forms/contact.py b/rental/forms/contact.py index 7488bce..bd74797 100644 --- a/rental/forms/contact.py +++ b/rental/forms/contact.py @@ -1,10 +1,11 @@ from django import forms -from rental.models.contact import Contact -from rental.models.place import Place - class ContactForm(forms.Form): + """ + ContactForm serve to validate input and create a new contact. + doc: https://docs.djangoproject.com/fr/2.2/topics/forms/modelforms/ + """ name = forms.CharField( label='', diff --git a/rental/models/booking.py b/rental/models/booking.py index 6ffa2f9..bbf9ab0 100644 --- a/rental/models/booking.py +++ b/rental/models/booking.py @@ -3,26 +3,33 @@ from datetime import datetime from django.db import models import rental.services.calendar as calendar -import rental.tasks.apiMailer as mailer # or gMailer +import rental.tasks.api_mailer as mailer # or g_mailer from rental.models.guest import Guest from rental.models.place import Place class BookingManager(models.Manager): - """ BookingManager is the interface through which database query operations - are provided to Django models. + """ + BookingManager is the interface through which database query operations + are provided to Django models. """ def create_booking(self, **kwargs): - """ create_booking creates a Booking instance, computes the price and - updates the remote calendar. """ + """ + Create_booking creates a Booking instance, computes the price and + updates the remote calendar. + """ + booking = self.create(**kwargs) booking.price = booking.get_price() calendar.update(booking) + return booking class Booking(models.Model): + """ Booking encapsulate booking instance information """ + class Meta: verbose_name = 'Réservation' @@ -39,15 +46,17 @@ class Booking(models.Model): price = models.DecimalField(max_digits=6, decimal_places=2, null=True) def get_price(self): - """ Compute booking price as a function of place and dates """ + """ Compute booking price as a function of place and dates. """ - if type(self.start) == str: + if isinstance(self.start, str): self.start = datetime.strptime(self.start, '%Y-%m-%d') - if type(self.end) == str: + if isinstance(self.end, str): self.end = datetime.strptime(self.end, '%Y-%m-%d') nights = (self.end - self.start).days return self.place.price * nights def send_quotation(self): + """ Notify user of booking details """ + mailer.send_quotation.delay(self.guest.name, self.guest.email) diff --git a/rental/models/contact.py b/rental/models/contact.py index 45fd95f..b5d7f89 100644 --- a/rental/models/contact.py +++ b/rental/models/contact.py @@ -1,9 +1,12 @@ from django.db import models -import rental.tasks.apiMailer as mailer # or gMailer +import rental.tasks.api_mailer as mailer # or g_mailer class Contact(models.Model): + """ + Contact encapsulates communication with a customer. + """ def __str__(self): return f"Message de {self.name}, le {self.date}" @@ -15,9 +18,13 @@ class Contact(models.Model): date = models.DateTimeField(auto_now_add=True) def send_confirmation(self): + """ Notify that the message has been succesfully sent. """ + mailer.send_confirmation.delay(self.name, self.email) def send_notification(self): + """ Notify admins that a message has been sent. """ + mailer.send_notification.delay( self.name, self.email, diff --git a/rental/models/guest.py b/rental/models/guest.py index bd63895..b4db62a 100644 --- a/rental/models/guest.py +++ b/rental/models/guest.py @@ -2,6 +2,7 @@ from django.db import models class Guest(models.Model): + """ Guest summarizes customer information. """ class Meta: verbose_name = "Voyageur" diff --git a/rental/models/picture.py b/rental/models/picture.py index 7a5dc36..ac58e0a 100644 --- a/rental/models/picture.py +++ b/rental/models/picture.py @@ -2,6 +2,8 @@ from django.db import models class Picture(models.Model): + """ Picture manages media and set alt tags. """ + def __str__(self): return self.alt diff --git a/rental/models/place.py b/rental/models/place.py index c633513..a15ef9c 100644 --- a/rental/models/place.py +++ b/rental/models/place.py @@ -5,6 +5,8 @@ from rental.models.picture import Picture class Place(models.Model): + """Place encapsulates a loaction information.""" + class Meta: verbose_name = "Appartement" @@ -21,9 +23,12 @@ class Place(models.Model): beds = models.IntegerField(null=True, blank=True) max_occupation = models.IntegerField(null=True, blank=True) thumbnail = models.ForeignKey( - Picture, on_delete=models.CASCADE, blank=True, null=True) + Picture, on_delete=models.CASCADE, blank=True, null=True + ) images = models.ManyToManyField(Picture, related_name="places", blank=True) calendar = models.CharField(max_length=350, blank=True, null=True) def is_available(self, start, end): + """Check weither a location is available at a given time period.""" + return calendar.check_availability(self, start, end) diff --git a/rental/models/testimonial.py b/rental/models/testimonial.py index f282568..f4ab288 100644 --- a/rental/models/testimonial.py +++ b/rental/models/testimonial.py @@ -5,6 +5,8 @@ from rental.models.guest import Guest class Testimonial(models.Model): + """Testimonial represent a past customer testimony.""" + class Meta: verbose_name = "Témoignage" @@ -14,9 +16,12 @@ class Testimonial(models.Model): author = models.CharField(max_length=200) text = models.TextField(max_length=1000) picture = models.ImageField( - max_length=200, upload_to='img/', null=True, blank=True) + max_length=200, upload_to='img/', null=True, blank=True + ) link = models.URLField(max_length=200, null=True, blank=True) guest = models.OneToOneField( - Guest, on_delete=models.CASCADE, blank=True, null=True) + Guest, on_delete=models.CASCADE, blank=True, null=True + ) reservation = models.OneToOneField( - Booking, on_delete=models.CASCADE, blank=True, null=True) + Booking, on_delete=models.CASCADE, blank=True, null=True + ) diff --git a/rental/tasks/apiMailer.py b/rental/tasks/api_mailer.py similarity index 88% rename from rental/tasks/apiMailer.py rename to rental/tasks/api_mailer.py index 088c150..f1ac1c6 100644 --- a/rental/tasks/apiMailer.py +++ b/rental/tasks/api_mailer.py @@ -1,12 +1,3 @@ -from __future__ import absolute_import, unicode_literals - -from datetime import datetime - -import requests -from celery import shared_task - -from villafleurie.settings import DEFAULT_FROM_EMAIL, EMAIL_HOST_USER - """ Mailer Service used to send messages using API WebHooks. All Mailers must implement the following methods: @@ -17,7 +8,18 @@ from villafleurie.settings import DEFAULT_FROM_EMAIL, EMAIL_HOST_USER def send_quotation(name, email)->void """ -URL = "https://hooks.zapier.com/hooks/catch/4071838/o93celz/" +from __future__ import absolute_import, unicode_literals + +from datetime import datetime +import os + +import requests +from celery import shared_task + +from villafleurie.settings import DEFAULT_FROM_EMAIL, EMAIL_HOST_USER + +# get mailing hook URL from env +URL = os.environ.get("MAIL_HOOK") @shared_task @@ -32,8 +34,7 @@ def send_confirmation(name, email): "body": f"Merci {name}, nous avons bien reçu votre message, nous revenons vers vous rapidement !\nCordialement,\nNilka (VillaFleurie)" } - resp = requests.post(URL, data=payload) - + requests.post(URL, data=payload) @shared_task @@ -48,12 +49,12 @@ def send_notification(name, email, subject, message, date): "body": f"Sujet : {subject}\nDe : {name}, {email}\nLe : {date}\nMessage : {message}\nCordialement,\nNilka (VillaFleurie)" } - resp = requests.post(URL, data=payload) + requests.post(URL, data=payload) @shared_task def send_quotation(name, email): - """ Send quotation to customer """ + """ Notify admins then send quotation to customer """ send_notification( name, diff --git a/rental/tasks/gMailer.py b/rental/tasks/g_mailer.py similarity index 94% rename from rental/tasks/gMailer.py rename to rental/tasks/g_mailer.py index 146c816..dd23b27 100644 --- a/rental/tasks/gMailer.py +++ b/rental/tasks/g_mailer.py @@ -1,11 +1,3 @@ -from __future__ import absolute_import, unicode_literals - -from celery import shared_task -from django.core.mail import mail_admins, send_mail - -from villafleurie.settings import EMAIL_HOST_USER - - """ Mailer Service used to send messages using Gmail. All Mailers must implement the following methods: @@ -14,12 +6,20 @@ from villafleurie.settings import EMAIL_HOST_USER def send_notification(name, email, subject, message)->void def send_quotation(name, email)->void - """ +""" + +from __future__ import absolute_import, unicode_literals + +from celery import shared_task +from django.core.mail import mail_admins, send_mail + +from villafleurie.settings import EMAIL_HOST_USER @shared_task def send_confirmation(name, email): """ Send confirmation message to customer """ + subject = "Nous avons reçu votre message" message = f" Merci {name}, Bien reçu nous revenons vers vous rapidement !" @@ -27,7 +27,7 @@ def send_confirmation(name, email): subject, message, EMAIL_HOST_USER, - [email] + [email] ) @@ -44,4 +44,5 @@ def send_notification(name, email, subject, message): @shared_task def send_quotation(name, email): """ Send quotation to customer """ - send_confirmation_mail(name, email) + + send_confirmation(name, email) diff --git a/rental/urls.py b/rental/urls.py index d934c12..933fa3f 100644 --- a/rental/urls.py +++ b/rental/urls.py @@ -1,3 +1,5 @@ +""" URLs specifi to rental application """ + from django.contrib.staticfiles.urls import static, staticfiles_urlpatterns from django.urls import path @@ -18,7 +20,7 @@ urlpatterns = [ path('', place.index, name='index'), path('hebergements/', place.all, name='list_place'), - path('/', place.view, name='detail_place') + path('/', place.view, name='detail_place') ] urlpatterns += staticfiles_urlpatterns() diff --git a/rental/views/booking.py b/rental/views/booking.py index 290249e..c7bc095 100644 --- a/rental/views/booking.py +++ b/rental/views/booking.py @@ -10,12 +10,15 @@ from rental.models.place import Place def view(request): + """Return initial booking form.""" context, template = handle_booking_form(request) return render(request, template, context) def handle_booking_form(request, context={}, init_template='rental/reservation.html'): + """Validates form and checks if place availability a given period.""" + if request.method == 'POST': form = BookingForm(request.POST) if form.is_valid(): @@ -56,17 +59,18 @@ def handle_booking_form(request, context={}, init_template='rental/reservation.h } template = 'rental/merci.html' return context, template - else: - form.add_error(None, ValidationError( - _("Cet hébergement n'est pas disponible aux dates indiquées."), - code='invalid' - )) - context = {'form': form} - template = 'rental/reservation.html' - return context, template + + form.add_error(None, ValidationError( + _("Cet hébergement n'est pas disponible aux dates indiquées."), + code='invalid' + )) + context = {'form': form} + template = 'rental/reservation.html' + return context, template except IntegrityError: - form.errors['internal'] = "Une erreur interne est apparue. Merci de recommencer votre requête." + form.errors['internal'] = """Une erreur interne est apparue. + Merci de recommencer votre requête.""" else: form = BookingForm() diff --git a/rental/views/contact.py b/rental/views/contact.py index e7ec447..c82a6f9 100644 --- a/rental/views/contact.py +++ b/rental/views/contact.py @@ -5,6 +5,8 @@ from rental.models.contact import Contact def view(request): + """Handle contactForm.""" + if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): diff --git a/rental/views/errors.py b/rental/views/errors.py index 23c248c..fba403f 100644 --- a/rental/views/errors.py +++ b/rental/views/errors.py @@ -1,9 +1,11 @@ from django.shortcuts import render -def handler404(request, exception): +def handler404(request, _): + """handle 404 errors. Requires a request and an exception.""" return render(request, 'rental/404.html', status=404) def handler500(request): + """handle 500 errors.""" return render(request, 'rental/500.html', status=500) diff --git a/rental/views/place.py b/rental/views/place.py index 4d30050..be75a1a 100644 --- a/rental/views/place.py +++ b/rental/views/place.py @@ -1,5 +1,4 @@ from django.shortcuts import get_object_or_404, render -from django.utils.translation import gettext_lazy as _ from rental.models.place import Place from rental.models.testimonial import Testimonial @@ -7,6 +6,7 @@ from rental.views.booking import handle_booking_form def index(request): + """Display homePage.""" places = Place.objects.all() temoignages = Testimonial.objects.all() @@ -19,6 +19,7 @@ def index(request): def all(request): + """Handle places list page.""" places = Place.objects.all() context = {'places': places} @@ -27,6 +28,7 @@ def all(request): def view(request, place_name='T2'): + """Handle a specific place.""" place = get_object_or_404(Place, name=place_name) images = place.images.all() diff --git a/villafleurie/celery.py b/villafleurie/celery.py index cd96bc3..837dabc 100644 --- a/villafleurie/celery.py +++ b/villafleurie/celery.py @@ -1,3 +1,7 @@ +""" Celery is a distributed task queue used for real-time processing of + asynchronous actions +""" + from __future__ import absolute_import, unicode_literals import os @@ -12,4 +16,5 @@ app.autodiscover_tasks() @app.task(bind=True) def debug_task(self): + """ Print request. For debug purposes only. """ print(f'Request: {self.request!r}') diff --git a/villafleurie/settings/base.py b/villafleurie/settings/base.py index 3d50431..d4024bd 100644 --- a/villafleurie/settings/base.py +++ b/villafleurie/settings/base.py @@ -1,3 +1,5 @@ +""" Standard setting file to be imported by specific configurations """ + import os BASE_DIR = os.path.dirname(os.path.dirname(__file__)) diff --git a/villafleurie/settings/development.py b/villafleurie/settings/development.py index 1828e30..0e651a5 100644 --- a/villafleurie/settings/development.py +++ b/villafleurie/settings/development.py @@ -1,6 +1,8 @@ +""" Settings to be used in development """ + import os -from .base import BASE_DIR +from .base import * SECRET_KEY = "not_so_secret_key" DEBUG = True diff --git a/villafleurie/settings/production.py b/villafleurie/settings/production.py index f610a1c..bbbea77 100644 --- a/villafleurie/settings/production.py +++ b/villafleurie/settings/production.py @@ -1,3 +1,5 @@ +""" Settings to be used in production """ + import os from .base import * diff --git a/villafleurie/urls.py b/villafleurie/urls.py index 3fcad01..b9f02c6 100644 --- a/villafleurie/urls.py +++ b/villafleurie/urls.py @@ -1,10 +1,10 @@ -from django.conf import settings -from django.conf.urls import include, url +from django.conf.urls import include from django.contrib import admin from django.urls import path urlpatterns = [ - path('admin/', admin.site.urls), + # change admin path for security purposes + path('dashboard/', admin.site.urls), path('', include('rental.urls', namespace='rental')) ]