Enums for choice fields; static files cleaning
8
.gitignore
vendored
|
|
@ -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
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
FROM nginx:latest
|
||||
|
||||
RUN rm /etc/nginx/conf.d/default.conf
|
||||
|
||||
COPY nginx/villafleurie.conf /etc/nginx/conf.d/
|
||||
|
|
@ -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
|
|
@ -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")
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 2.4 MiB |
|
Before Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 2.4 MiB |
|
Before Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 5 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 3 KiB |
|
Before Width: | Height: | Size: 3 KiB |
|
Before Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 255 KiB |
|
Before Width: | Height: | Size: 286 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 162 KiB |
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 58 KiB |
1197
rental/static/rental/lib/popper/popper.min.js
vendored
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||