Compare commits
No commits in common. "book" and "master" have entirely different histories.
|
@ -1,6 +1,6 @@
|
||||||
import bisect
|
import bisect
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from flask import Flask, jsonify, make_response, redirect, request
|
from flask import Flask, jsonify, redirect, request
|
||||||
from google.auth.transport.requests import Request
|
from google.auth.transport.requests import Request
|
||||||
from google.oauth2.credentials import Credentials
|
from google.oauth2.credentials import Credentials
|
||||||
from googleapiclient.discovery import build
|
from googleapiclient.discovery import build
|
||||||
|
@ -14,8 +14,7 @@ WEEK_DAYS = {1, 2, 3, 4, 5}
|
||||||
FROM = 9
|
FROM = 9
|
||||||
TO = 17
|
TO = 17
|
||||||
|
|
||||||
TIMEZONE_NAME = 'America/New_York'
|
TIMEZONE = pytz.timezone('America/New_York')
|
||||||
TIMEZONE = pytz.timezone(TIMEZONE_NAME)
|
|
||||||
|
|
||||||
AVAILABILITY_LIFETIME = timedelta(minutes=2)
|
AVAILABILITY_LIFETIME = timedelta(minutes=2)
|
||||||
|
|
||||||
|
@ -32,12 +31,8 @@ def read_datetime(dct):
|
||||||
return dt
|
return dt
|
||||||
|
|
||||||
|
|
||||||
def asiso(dt):
|
|
||||||
return dt.isoformat()[:19]
|
|
||||||
|
|
||||||
|
|
||||||
def asutciso(dt):
|
def asutciso(dt):
|
||||||
return asiso(dt.astimezone(UTC)) + 'Z'
|
return dt.astimezone(UTC).isoformat()[:19] + 'Z'
|
||||||
|
|
||||||
|
|
||||||
def aslocal(dt):
|
def aslocal(dt):
|
||||||
|
@ -116,49 +111,6 @@ def api_availability():
|
||||||
return jsonify({'availability': [asutciso(time) for time in availability]})
|
return jsonify({'availability': [asutciso(time) for time in availability]})
|
||||||
|
|
||||||
|
|
||||||
@app.route('/book', methods=['POST', 'OPTIONS'])
|
@app.route('/book', methods=['POST'])
|
||||||
def api_book():
|
def api_book():
|
||||||
# Allow cross-origin
|
TODO
|
||||||
if request.method == 'OPTIONS':
|
|
||||||
response = make_response()
|
|
||||||
response.headers.add(
|
|
||||||
'Access-Control-Allow-Origin',
|
|
||||||
'https://vicky.rampin.org',
|
|
||||||
)
|
|
||||||
response.headers.add(
|
|
||||||
'Access-Control-Allow-Headers',
|
|
||||||
'Content-Type',
|
|
||||||
)
|
|
||||||
response.headers.add(
|
|
||||||
'Access-Control-Allow-Methods',
|
|
||||||
'POST',
|
|
||||||
)
|
|
||||||
return response
|
|
||||||
|
|
||||||
if not creds.valid:
|
|
||||||
creds.refresh(Request())
|
|
||||||
service = build('calendar', 'v3', credentials=creds)
|
|
||||||
|
|
||||||
full_name = request.form['name']
|
|
||||||
email = request.form['email']
|
|
||||||
topic = request.form['topic']
|
|
||||||
date = request.form['date']
|
|
||||||
|
|
||||||
end = start + timedelta(minutes=30)
|
|
||||||
|
|
||||||
service.events().insert(
|
|
||||||
calendarId='primary',
|
|
||||||
body=dict(
|
|
||||||
start={'dateTime': asiso(start), 'timeZone': TIMEZONE_NAME},
|
|
||||||
end={'dateTime': asiso(end), 'timeZone': TIMEZONE_NAME},
|
|
||||||
summary="Meeting with Vicky",
|
|
||||||
description="Meeting scheduled from the web",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
response = redirect('https://vicky.rampin.org/book-successful', 303)
|
|
||||||
response.headers.add(
|
|
||||||
'Access-Control-Allow-Origin',
|
|
||||||
'https://vicky.rampin.org',
|
|
||||||
)
|
|
||||||
return response
|
|
||||||
|
|
250
form.html
250
form.html
|
@ -7,7 +7,7 @@
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="container px-5 my-5">
|
<div class="container px-5 my-5">
|
||||||
<form id="contactForm" action="https://contact.vicky.rampin.org/book" method="POST">
|
<form id="contactForm">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label" for="name">Full name</label>
|
<label class="form-label" for="name">Full name</label>
|
||||||
<input class="form-control" id="name" name="name" type="text" placeholder="Full name" />
|
<input class="form-control" id="name" name="name" type="text" placeholder="Full name" />
|
||||||
|
@ -20,199 +20,20 @@
|
||||||
<label class="form-label" for="topic">What would you like to discuss?</label>
|
<label class="form-label" for="topic">What would you like to discuss?</label>
|
||||||
<textarea class="form-control" id="topic" name="topic" placeholder="What would you like to discuss?" style="height: 10rem;"></textarea>
|
<textarea class="form-control" id="topic" name="topic" placeholder="What would you like to discuss?" style="height: 10rem;"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3" style="overflow-x: auto;">
|
<div class="mb-3">
|
||||||
<label class="form-label d-block">Which day and time works best for us to meet on Zoom?</label>
|
<label class="form-label d-block">Which day and time works best for us to meet on Zoom?</label>
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">Thursday 5/12</th>
|
|
||||||
<th scope="col">Friday 5/13</th>
|
|
||||||
<th scope="col">Monday 5/16</th>
|
|
||||||
<th scope="col">Tuesday 5/17</th>
|
|
||||||
<th scope="col">Wednesday 5/18</th>
|
|
||||||
<th scope="col">Thursday 5/19</th>
|
|
||||||
<th scope="col">Friday 5/20</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
<div class="form-check form-check-inline">
|
||||||
<input class="form-check-input" id="2022-05-12T09:00:00" value="2022-05-12T09:00:00" type="radio" name="date" />
|
<input class="form-check-input" id="optionA" type="radio" name="date" />
|
||||||
<label class="form-check-label" for="2022-05-12T09:00:00">9:00</label>
|
<label class="form-check-label" for="optionA">option A</label>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
<div class="form-check form-check-inline">
|
||||||
<input class="form-check-input" id="2022-05-13T09:00:00" value="2022-05-13T09:00:00" type="radio" name="date" />
|
<input class="form-check-input" id="optionB" type="radio" name="date" />
|
||||||
<label class="form-check-label" for="2022-05-13T09:00:00">9:00</label>
|
<label class="form-check-label" for="optionB">option B</label>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
<div class="form-check form-check-inline">
|
||||||
<input class="form-check-input" id="2022-05-16T09:00:00" value="2022-05-16T09:00:00" type="radio" name="date" />
|
<input class="form-check-input" id="optionC" type="radio" name="date" />
|
||||||
<label class="form-check-label" for="2022-05-16T09:00:00">9:00</label>
|
<label class="form-check-label" for="optionC">option C</label>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-17T09:00:00" value="2022-05-17T09:00:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-17T09:00:00">9:00</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-18T09:00:00" value="2022-05-18T09:00:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-18T09:00:00">9:00</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-19T09:00:00" value="2022-05-19T09:00:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-19T09:00:00">9:00</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-20T09:00:00" value="2022-05-20T09:00:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-20T09:00:00">9:00</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-12T09:30:00" value="2022-05-12T09:30:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-12T09:30:00">9:30</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-13T09:30:00" value="2022-05-13T09:30:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-13T09:30:00">9:30</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-16T09:30:00" value="2022-05-16T09:30:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-16T09:30:00">9:30</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-17T09:30:00" value="2022-05-17T09:30:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-17T09:30:00">9:30</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-18T09:30:00" value="2022-05-18T09:30:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-18T09:30:00">9:30</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-19T09:30:00" value="2022-05-19T09:30:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-19T09:30:00">9:30</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-20T09:30:00" value="2022-05-20T09:30:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-20T09:30:00">9:30</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-12T10:00:00" value="2022-05-12T10:00:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-12T10:00:00">10:00</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-13T10:00:00" value="2022-05-13T10:00:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-13T10:00:00">10:00</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-16T10:00:00" value="2022-05-16T10:00:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-16T10:00:00">10:00</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-17T10:00:00" value="2022-05-17T10:00:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-17T10:00:00">10:00</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-18T10:00:00" value="2022-05-18T10:00:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-18T10:00:00">10:00</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-19T10:00:00" value="2022-05-19T10:00:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-19T10:00:00">10:00</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-20T10:00:00" value="2022-05-20T10:00:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-20T10:00:00">10:00</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-12T10:30:00" value="2022-05-12T10:30:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-12T10:30:00">10:30</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-13T10:30:00" value="2022-05-13T10:30:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-13T10:30:00">10:30</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-16T10:30:00" value="2022-05-16T10:30:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-16T10:30:00">10:30</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-17T10:30:00" value="2022-05-17T10:30:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-17T10:30:00">10:30</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-18T10:30:00" value="2022-05-18T10:30:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-18T10:30:00">10:30</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-19T10:30:00" value="2022-05-19T10:30:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-19T10:30:00">10:30</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" id="2022-05-20T10:30:00" value="2022-05-20T10:30:00" type="radio" name="date" />
|
|
||||||
<label class="form-check-label" for="2022-05-20T10:30:00">10:30</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="d-grid">
|
<div class="d-grid">
|
||||||
<button class="btn btn-primary btn-lg disabled" id="submitButton" type="submit">Submit</button>
|
<button class="btn btn-primary btn-lg disabled" id="submitButton" type="submit">Submit</button>
|
||||||
|
@ -221,60 +42,5 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src=".bootstrap/bootstrap.bundle.min.js"></script>
|
<script src=".bootstrap/bootstrap.bundle.min.js"></script>
|
||||||
|
|
||||||
<script>
|
|
||||||
let contactForm = document.getElementById("contactForm");
|
|
||||||
|
|
||||||
function formValid() {
|
|
||||||
console.log("name: ", contactForm.name.value);
|
|
||||||
if(!contactForm.name.value) {
|
|
||||||
console.log("wrong name ", contactForm.name.value);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
console.log("email: ", contactForm.email.value);
|
|
||||||
if(!contactForm.email.value) {
|
|
||||||
console.log("wrong email ", contactForm.email.value);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
console.log("topic: ", contactForm.topic.value);
|
|
||||||
if(!contactForm.topic.value) {
|
|
||||||
console.log("wrong topic ", contactForm.topic.value);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
console.log("date: ", contactForm.date.value);
|
|
||||||
if(!contactForm.date.value) {
|
|
||||||
console.log("wrong date ", contactForm.date.value);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
contactForm.addEventListener("submit", function submitEventHandler(e) {
|
|
||||||
if(!formValid()) {
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
contactForm.addEventListener("change", function changeEventHandler(e) {
|
|
||||||
if(formValid()) {
|
|
||||||
console.log("change, valid=true");
|
|
||||||
document.getElementById("submitButton").classList.remove("disabled");
|
|
||||||
} else {
|
|
||||||
console.log("change, valid=false");
|
|
||||||
document.getElementById("submitButton").classList.add("disabled");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
fetch("https://contact.vicky.rampin.org/availability")
|
|
||||||
.then(function(response) {
|
|
||||||
if(response.status !== 200) {
|
|
||||||
throw new Error();
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then(function(obj) {
|
|
||||||
console.log(obj.availability);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in New Issue