calendarwatch_frontend/server/googleHandler.py

182 lines
6.7 KiB
Python

import google.oauth2.credentials
import google_auth_oauthlib.flow
import googleapiclient.discovery
import backend.caltojson as caltojson
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 server import db
# Configuration
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()
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
class Calendar:
def __init__(self, name, calendarId, toggle='False', color="#000000"):
self.name = name
self.color = color
self.toggle=toggle
self.calendarId = calendarId
# TODO move this to database
def calendarsFromDb():
pyCalendars = []
for calendar in current_user.calendars:
name = (calendar.name[:16] + '..') if len(calendar.name)> 18 else calendar.name
calendarId = calendar.calendar_id
toggle = calendar.toggle
color = calendar.color
pyCalendars.append(Calendar(name, calendarId, toggle, color))
return pyCalendars
def updateCalendars():
if 'credentials' not in flask.session:
return flask.redirect('login/google')
# Load credentials from the session.
# credentials = google.oauth2.credentials.Credentials(
# **flask.session['credentials'])
# a = flask.session['credentials']
# print(a, flush=True)
# print(current_user.getGoogleCredentials(), flush=True)
if current_user.google_token == None:
return
client_token = GC.build_credentials(current_user.google_token.token,
current_user.google_token.refresh_token)
credentials = google.oauth2.credentials.Credentials(**client_token)
calendars = caltojson.getCalendarList(credentials)
for calendar in calendars:
if not current_user.hasCalendar(calendar.calendarId):
c = dbCalendar(calendar_id=calendar.calendarId,
name = calendar.summary,
toggle = "False",
color = calendar.color)
db.session.add(c)
current_user.calendars.append(c)
# Save credentials back to session in case access token was refreshed.
# ACTION ITEM: In a production app, you likely want to save these
# credentials in a persistent database instead.
# TODO add save updated token to database here
current_user.google_token.token = credentials.token
db.session.commit()
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}