Open s2t2 opened 2 years ago
If you are using a flask app with google login routes like these...
1) you'll need to update the google login route to store the token in the session, so we can use it later. do this around line 57:
session["bearer_token"] = token
2) add some new routes, like these, called "gcal_routes.py" in the "routes" directory:
import datetime
from dateutil.parser import parse as to_dt # converts string to datetime object
#from pprint import pprint
from flask import Blueprint, render_template, session, flash, redirect, current_app, request
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from web_app.routes.wrappers import authenticated_route
gcal_routes = Blueprint("gcal_routes", __name__)
def format_timestamp(dt):
"""Formats datetime object for storing in Google Calendar."""
return dt.strftime("%Y-%m-%dT%H:%M:%S")
def user_authorized_gcal_client():
"""
Access user's calendars on their behalf via their login credentials.
See: https://google-auth.readthedocs.io/en/stable/user-guide.html#user-credentials
"""
bearer_token = session.get("bearer_token")
print("BEARER TOKEN:", bearer_token.keys())
access_token = bearer_token["access_token"] # or user.access_token
credentials = Credentials(access_token)
client = build("calendar", "v3", credentials=credentials)
return client
@gcal_routes.route("/reservations/export/gcal", methods=["POST"])
@authenticated_route
def export_reservation_to_gcal():
form_data = dict(request.form)
print("FORM DATA:", form_data)
redirect_path = form_data["redirect_path"] # for page navigation
event_start = form_data["event_start"] #> '2021-08-10 11:00:00-04:00'
event_end = form_data["event_end"] #> '2021-08-10 11:45:00-04:00'
time_zone = form_data["time_zone"] #> 'America/New_York'
try:
client = user_authorized_gcal_client()
calendars = client.calendarList().list().execute()
print("GCALS:", [(cal["id"], cal["summary"], cal["timeZone"]) for cal in calendars])
return render_template("gcal_calendar_selection_form.html",
calendars=calendars,
event_start=event_start,
event_end=event_end,
time_zone=time_zone,
redirect_path=redirect_path,
)
except Exception as err:
print(err)
flash(f"Oops, something went wrong with your google credentials... {err} Try logging out and back in again.", "danger")
return redirect(redirect_path)
@gcal_routes.route("/reservations/export/gcal/create", methods=["POST"])
@authenticated_route
def create_gcal_event():
form_data = dict(request.form)
print("FORM DATA:", form_data)
calendar_id = form_data["calendar_id"]
event_start = form_data["event_start"] #> '2021-08-10 11:00:00-04:00'
event_end = form_data["event_end"] #> '2021-08-10 11:45:00-04:00'
time_zone = form_data["time_zone"]
redirect_path = form_data["redirect_path"]
try:
event_start_timestamp = format_timestamp(to_dt(event_start))
event_end_timestamp = format_timestamp(to_dt(event_end))
event_data = {
'summary': "Gym Time",
'description': "This event was generated by Our Gym Calendar App.",
'start': {'dateTime': event_start_timestamp, 'timeZone': time_zone},
'end': {'dateTime': event_end_timestamp, 'timeZone': time_zone},
#"attendees": [{"email": email}],
#"source": {"title": source_title, "url": source_url},
"visibility": "default" # "private"
}
client = user_authorized_gcal_client()
# https://developers.google.com/calendar/api/guides/create-events
# https://developers.google.com/calendar/v3/reference/events/insert
# https://developers.google.com/calendar/concepts/sharing
# https://developers.google.com/calendar/auth#perform-g-suite-domain-wide-delegation-of-authority
# Service accounts cannot invite attendees without Domain-Wide Delegation of Authority.
# https://developers.google.com/admin-sdk/directory/v1/guides/delegation
event = client.events().insert(calendarId=calendar_id, body=event_data).execute()
print("GCAL EVENT:", event)
flash("Reservation exported to Google Calendar!", "success")
return redirect(redirect_path)
except Exception as err:
print(err)
flash(f"Oops, something went wrong... {err}", "danger")
return redirect(redirect_path)
3) add a new HTML form to send the original POST Request to "/reservations/export/gcal", with inputs named event_start
, event_end
, and timezone
4) add a new HTML dropdown for the calendar selection:
{% extends "bootstrap_5_layout.html" %}
{% set active_page = "gcal_calendar_selection" %}
{% block content %}
<h1>Select a Google Calendar</h1>
<p>Export this reservation to which calendar?</p>
<form method="POST" action="/reservations/export/gcal/create">
<input type="hidden" name="event_start" value="{{ event_start }}">
<input type="hidden" name="event_end" value="{{ event_end }}">
<input type="hidden" name="time_zone" value="{{ time_zone }}">
<input type="hidden" name="redirect_path" value="{{ redirect_path }}">
<!-- see: https://getbootstrap.com/docs/5.0/forms/select/ -->
<select name="calendar_id" id="google-calendar-selector" class="form-select form-select-lg mb-3">
{% for calendar in calendars %}
<option value="{{ calendar['id'] }}"> {{ calendar['summary'] }}</option>
{% endfor %}
</select>
<button type="submit" class="btn btn-outline-success">Create Event</button>
</form>
{% endblock %}
Google Calendar API
Using the
google-api-python-client
PackageReference
Google Calendar API Docs:
Installation
Setup
After creating a new Google Cloud project via the Google Cloud APIs console, and enabling the Google Calendar API...
Create service account credentials for this project, and download the resulting JSON key file into the root directory of this repo, for example named "google-credentials.json".
If you want to use the environment variable approach, from the root directory of this repo, set the credentials as an environment variable:
Usage