calendarwatch_frontend/server/googleHandler.py
raphael 752c7c5577 adds ical input to calendar html templates and implements data handling
- the icalHandler in the backend is used in two instances. First, when
  the user adds a new ical calendar into the database, routes.py passes
  the information (name and url) to the ical Handler. The calendars are
  saved in the database as type 'ical'.

  Then, when a connected device pulls current events, all the calendars
  which are of type 'ical' are pulled and parsed for current events.
  See the backend commit for details on what happens there.

- All google Calendar related functions now have an additional check,
  to make sure that the calendar they are working on is of type 'Google'.
2020-07-25 18:05:55 +02:00

219 lines
8.1 KiB
Python

import google.oauth2.credentials
import google_auth_oauthlib.flow
import googleapiclient.discovery
from googleapiclient.discovery import build
from oauthlib.oauth2 import WebApplicationClient
import flask
# Python standard libraries
import json
import os
# Third-party libraries
import flask
from flask import Flask, redirect, request, url_for
from flask_login import (
LoginManager,
current_user,
login_required,
login_user,
logout_user,
)
import requests
from database.models import Calendar as dbCalendar
from backend import Calendar, Event
# Configuration class for the google client
# all necessary variables and secrets are defined in this
# aswell as some helper functions
class GoogleClient():
def __init__(self):
self.CLIENT_SECRETS_FILE = "certificate/client_secret.json"
with open("/home/calendarwatch/certificate/google_client.json", encoding='utf-8') as json_file:
self.google_client = json.load(json_file)
self.SCOPES = self.google_client.get('scopes')
self.API_SERVICE_NAME = 'calendar'
self.API_VERSION = 'v3'
# GOOGLE_CLIENT_ID ="377787187748-shuvi4iq5bi4gdet6q3ioataimobs4lh.apps.googleusercontent.com"
self.GOOGLE_CLIENT_ID = self.google_client.get('client_id')
# GOOGLE_CLIENT_SECRET = "Hu_YWmKsVKUcLwyeINYzdKfZ"
self.GOOGLE_CLIENT_SECRET = self.google_client.get('client_secret')
self.GOOGLE_DISCOVERY_URL = (
"https://accounts.google.com/.well-known/openid-configuration"
)
# OAuth 2 client setup
self.client = WebApplicationClient(self.GOOGLE_CLIENT_ID)
def build_credentials(self, token, refresh_token):
data = {}
data['token'] = token
data['refresh_token'] = refresh_token
data['token_uri'] = self.google_client.get('token_uri')
data['client_id'] = self.google_client.get('client_id')
data['client_secret'] = self.google_client.get('client_secret')
data['scopes'] = self.google_client.get('scopes')
return data
GC = GoogleClient()
# stuff for OAuth login
def login():
# Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
GC.CLIENT_SECRETS_FILE, scopes=GC.SCOPES)
# The URI created here must exactly match one of the authorized redirect URIs
# for the OAuth 2.0 client, which you configured in the API Console. If this
# value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch'
# error.
flow.redirect_uri = "https://longitudecalendar.com/login/google/callback"
authorization_url, state = flow.authorization_url(
# Enable offline access so that you can refresh an access token without
# re-prompting the user for permission. Recommended for web server apps.
access_type='offline',
# Enable incremental authorization. Recommended as a best practice.
include_granted_scopes='true')
# Store the state so the callback can verify the auth server response.
flask.session['state'] = state
# Flask-Login helper to retrieve a user from our db
return authorization_url
def verifyResponse():
# Specify the state when creating the flow in the callback so that it can
# verified in the authorization server response.
state = flask.session['state']
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
GC.CLIENT_SECRETS_FILE, scopes=GC.SCOPES, state=state)
flow.redirect_uri = "https://longitudecalendar.com/login/google/callback"
# Use the authorization server's response to fetch the OAuth 2.0 tokens.
authorization_response = flask.request.url
flow.fetch_token(authorization_response=authorization_response)
# Store credentials in the session.
# ACTION ITEM: In a production app, you likely want to save these
# credentials in a persistent database instead.
credentials = flow.credentials
flask.session['credentials'] = credentials_to_dict(credentials)
print(credentials_to_dict(credentials), flush=True)
session = flow.authorized_session()
return session, credentials_to_dict(credentials)
def get_google_provider_cfg():
return requests.get(GC.GOOGLE_DISCOVERY_URL).json()
def deleteAccount(user):
result = requests.post('https://oauth2.googleapis.com/revoke',
params={'token': user.google_token.token},
headers = {'content-type': 'applixation/x-www-form-urlencoded'})
print(result, flush=True)
return
def fetchCalendarEvents(user, calendars, startDate, endDate):
service = None
if user.google_token is not None:
client_token = GC.build_credentials(user.google_token.token,
user.google_token.refresh_token)
credentials = google.oauth2.credentials.Credentials(**client_token)
service = build(GC.API_SERVICE_NAME, GC.API_VERSION, credentials=credentials)
all_events = []
for calendar in calendars:
if (calendar.toggle == "True" and
calendar.calendar_type == "Google" and
service != None):
event_result = service.events().list(calendarId=calendar.calendar_id,
timeMin=startDate.isoformat(),
timeMax=endDate.isoformat(),
maxResults=10,
singleEvents=True,
orderBy='startTime').execute()
for event in event_result.get('items', []):
# create simple event
name = event.get('summary', '(no Title)')
start = event['start'].get('dateTime')
end = event['end'].get('dateTime')
newEvent = Event(name, start, end)
# handle weird colors from google
color = event.get('colorId')
if color == None:
newEvent.colorHex = calendar.color
newEvent.eventColorId = None
else:
newEvent.eventColorId = color
all_events.append(newEvent)
if service != None:
colors = service.colors().get().execute()
else:
colors = None
return all_events, colors
def fetchCalendars():
# get client api service
if current_user.google_token == None:
return [], None, None
client_token = GC.build_credentials(current_user.google_token.token,
current_user.google_token.refresh_token)
credentials = google.oauth2.credentials.Credentials(**client_token)
service = build(GC.API_SERVICE_NAME, GC.API_VERSION, credentials=credentials)
# get all calendars and put them into Calendar Class
page_token = None
calendars = []
while True:
calendar_list = service.calendarList().list(pageToken=page_token).execute()
for calendar in calendar_list['items']:
calendars.append(Calendar(name=calendar['summary'],
calType="Google",
calendarId=calendar['id'],
color=calendar['colorId']))
page_token = calendar_list.get('nextPageToken')
if not page_token:
break
colors = service.colors().get().execute()
return calendars, colors, credentials.token
def getUserCredentials(user):
credentials = GC.build_credentials(user.google_token.token,
user.google_token.refresh_token)
googleCreds = google.oauth2.credentials.Credentials(**credentials)
return googleCreds
def credentials_to_dict(credentials):
return {'token': credentials.token,
'refresh_token': credentials.refresh_token,
'token_uri': credentials.token_uri,
'client_id': credentials.client_id,
'client_secret': credentials.client_secret,
'scopes': credentials.scopes}