Enums for choice fields; static files cleaning

This commit is contained in:
Ruidy Nemausat 2020-03-28 14:50:29 +01:00
parent fd74cb80d7
commit 0f76c54a38
49 changed files with 1253 additions and 30 deletions

8
.gitignore vendored
View file

@ -1,15 +1,11 @@
.gitignore
.DS_Store
.vscode/
env/
__pycache__/
rental/__pycache__/
# rental/migrations/
villafleurie/__pycache__/
villafleurie/staticfiles/
**/__pycache__
villafleurie/static_files/
rental/client_secrets.json
token.pickle
*.env
*.tar
debug.log
rental/templates/rental/mails

View file

@ -1,5 +1,3 @@
FROM nginx:latest
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx/villafleurie.conf /etc/nginx/conf.d/

View file

@ -13,19 +13,18 @@ from villafleurie.settings import BASE_DIR
def build_calendar_api_service():
""" Build Google Calendar API service and returns calendar list and service """
creds = None
# If modifying these scopes, delete the file token.pickle.
SCOPES = [
'https://www.googleapis.com/auth/calendar',
'https://www.googleapis.com/auth/calendar.events'
]
# The file token.pickle stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
@ -34,14 +33,16 @@ def build_calendar_api_service():
flow = InstalledAppFlow.from_client_secrets_file(
SECRETS, scopes=SCOPES, redirect_uri="http://localhost:8080/")
creds = flow.run_local_server()
# Save the credentials for the next run
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('calendar', 'v3', credentials=creds)
calendars = {
'T2': "burik7aclvhc7vsboh06c179uo@group.calendar.google.com",
'T3': "fu7h30p0gk4a2p4nvo7nsbgpok@group.calendar.google.com"
}
return service, calendars
@ -55,6 +56,7 @@ def get_calendar_reservations(place):
orderBy='startTime'
).execute()
events = events_result.get('items', [])
if not events:
print('No upcoming events found.')
else:
@ -65,6 +67,7 @@ def get_calendar_reservations(place):
'start': event['start'].get('dateTime', event['start'].get('date')).strip(),
'end': event['end'].get('dateTime', event['end'].get('date')).strip()
}
return reservation
@ -72,6 +75,7 @@ def synchronize_calendars(place):
""" Get a complete list of existing bookings in calendar
Creates reservation if not in db, update if already in db
Delete from db reservation deleted from cal """
reservation = get_calendar_reservations(place)
place = get_object_or_404(Place, name=place.name)
price = get_reservation_price(
@ -81,6 +85,7 @@ def synchronize_calendars(place):
)
start = reservation['start']
end = reservation['end']
guest = Guest.objects.filter(name=reservation['guest'])
if not guest.exists():
guest = Guest.objects.create(name=reservation['guest'])
@ -108,17 +113,21 @@ def synchronize_calendars(place):
def get_bookings(place):
""" Synchronize with Master calendar via a call to synchronize_calendar
Returns a list of all related place reservations """
synchronize_calendars(place)
booked_dates = Reservation.objects.filter(place=place)
return [booking for booking in booked_dates]
def check_availability(place, start_date, end_date):
""" check if the related place is available during a given period """
bookings = get_bookings(place)
for booking in bookings:
if (booking.start <= start_date <= booking.end) or (booking.start <= end_date <= booking.end):
return False
return True
@ -142,7 +151,3 @@ def update_calendar(reservation):
},
}
).execute()
# if __name__ == "__main__":
# update_calendar(reservation)

8
rental/enums.py Normal file
View file

@ -0,0 +1,8 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
class PlacesNames(models.TextChoices):
T2 = "T2", _("T2")
T3 = "T3", _("T3")

View file

@ -1,9 +1,10 @@
from django import forms
from .models import Reservation, Place, Guest
from .enums import PlaceNames
class ReservationForm(forms.Form):
PLACES = (('T2', 'T2'), ('T3', 'T3'),)
name = forms.CharField(
label="",
max_length=100,
@ -13,6 +14,7 @@ class ReservationForm(forms.Form):
'placeholder': 'Nom *'
}),
required=True)
email = forms.EmailField(
label='',
widget=forms.EmailInput(attrs={
@ -21,6 +23,7 @@ class ReservationForm(forms.Form):
}),
required=True
)
phone = forms.CharField(
label='',
max_length=30,
@ -30,12 +33,16 @@ class ReservationForm(forms.Form):
'placeholder': 'Téléphone *'
}),
required=True)
place = forms.ChoiceField(
label='',
widget=forms.Select(
attrs={'class': 'form-control form-control-lg form-control-a'}),
required=True,
choices=PLACES)
choices=PlacesNames.choices,
default=PlacesNames.T2
)
message = forms.CharField(
label='',
# max_length=100,
@ -47,6 +54,7 @@ class ReservationForm(forms.Form):
'placeholder': 'Message *'
}),
required=True)
start = forms.DateField(
label='',
input_formats=['%d/%m/%Y'],
@ -56,6 +64,7 @@ class ReservationForm(forms.Form):
'class': 'form-control form-control-lg form-control-a',
'placeholder': '01/01/2020 *'}),
required=True)
end = forms.DateField(
label='',
input_formats=['%d/%m/%Y'],
@ -66,6 +75,7 @@ class ReservationForm(forms.Form):
class ContactForm(forms.Form):
name = forms.CharField(
label='',
widget=forms.TextInput(attrs={
@ -74,6 +84,7 @@ class ContactForm(forms.Form):
}),
required=True,
)
email = forms.EmailField(
label='',
widget=forms.EmailInput(attrs={
@ -82,6 +93,7 @@ class ContactForm(forms.Form):
}),
required=True,
)
subject = forms.CharField(
label='',
widget=forms.TextInput(attrs={
@ -90,6 +102,7 @@ class ContactForm(forms.Form):
}),
required=True,
)
message = forms.CharField(
label='',
# max_length=100,

View file

@ -3,11 +3,13 @@ from datetime import datetime
def get_reservation_price(place, start, end):
""" Compute booking price as a function of place and dates """
if type(start) == str:
start = datetime.strptime(start, '%Y-%m-%d')
if type(end) == str:
end = datetime.strptime(end, '%Y-%m-%d')
nights = (end - start).days
return place.price * nights

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

File diff suppressed because one or more lines are too long

View file

@ -1,36 +1,37 @@
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from .models import Testimonial, Reservation, Guest, Place
from django.urls import reverse_lazy
from django.views.generic.base import TemplateView
from .forms import ReservationForm, ContactForm
from django.db import IntegrityError
from django.views.generic.base import TemplateView
from rental.forms import ReservationForm, ContactForm
from rental.models import Testimonial, Reservation, Guest, Place, Contact
from rental.pricing import get_reservation_price
from rental.bookings import check_availability, synchronize_calendars, update_calendar
# send_confirmation_mail, send_notification, send_quotation
from rental.tasks.apiMailer import * # gMailer
from rental.models import Contact
from rental.tasks.apiMailer import * # or gMailer
def index(request):
places = Place.objects.all()
temoignages = Testimonial.objects.all()
context = {
'places': places,
'temoignages': temoignages
}
return render(request, 'rental/index.html', context)
def liste_location(request):
places = Place.objects.all()
context = {'places': places}
return render(request, 'rental/list_place.html', context)
def location(request, place_name='T2'):
place = get_object_or_404(Place, name=place_name)
images = place.images.all()
context = {
'place': place,
'images': images
@ -44,6 +45,7 @@ def location(request, place_name='T2'):
def reservation(request):
context, template = handle_reservation_form(request)
return render(request, template, context)
@ -58,6 +60,7 @@ def handle_reservation_form(request, context={}, init_template='rental/reservati
place_name = form.cleaned_data['place']
start = form.cleaned_data['start']
end = form.cleaned_data['end']
try:
guest = Guest.objects.filter(email=email)
if not guest.exists():
@ -68,6 +71,7 @@ def handle_reservation_form(request, context={}, init_template='rental/reservati
)
else:
guest = guest.first()
place = get_object_or_404(Place, name=place_name)
available = check_availability(place, start, end)
price = get_reservation_price(place, start, end)
@ -91,13 +95,16 @@ def handle_reservation_form(request, context={}, init_template='rental/reservati
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."
else:
form = ReservationForm()
context['form'] = form
context['errors'] = form.errors.items()
template = init_template
return context, template
@ -113,6 +120,7 @@ def calendar(request, place_name):
'place_name': place_name,
'bookings': bookings
}
return render(request, 'rental/calendar.html', context)