doc: add doctrings

This commit is contained in:
Ruidy Nemausat 2020-07-26 11:30:26 +02:00
parent 5eea1e12ee
commit 2e690ae9a3
22 changed files with 121 additions and 59 deletions

View file

@ -1,3 +1,5 @@
""" Register models and configure admin dashboard """
from django.contrib import admin
from rental.models.booking import Booking

View file

@ -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")

View file

@ -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="",

View file

@ -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='',

View file

@ -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)

View file

@ -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,

View file

@ -2,6 +2,7 @@ from django.db import models
class Guest(models.Model):
""" Guest summarizes customer information. """
class Meta:
verbose_name = "Voyageur"

View file

@ -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

View file

@ -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)

View file

@ -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
)

View file

@ -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,

View file

@ -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 !"
@ -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)

View file

@ -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_name>/', place.view, name='detail_place')
path('<slug:place_name>/', place.view, name='detail_place')
]
urlpatterns += staticfiles_urlpatterns()

View file

@ -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()

View file

@ -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():

View file

@ -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)

View file

@ -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()

View file

@ -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}')

View file

@ -1,3 +1,5 @@
""" Standard setting file to be imported by specific configurations """
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))

View file

@ -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

View file

@ -1,3 +1,5 @@
""" Settings to be used in production """
import os
from .base import *

View file

@ -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'))
]