2020-04-22 22:15:21 +02:00
|
|
|
import google.oauth2.credentials
|
|
|
|
import google_auth_oauthlib.flow
|
|
|
|
import googleapiclient.discovery
|
2020-05-30 23:05:46 +02:00
|
|
|
from googleapiclient.discovery import build
|
2020-04-22 22:15:21 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2020-05-24 13:33:48 +02:00
|
|
|
from database.models import Calendar as dbCalendar
|
2020-05-30 23:05:46 +02:00
|
|
|
from backend import Calendar, Event
|
|
|
|
|
2020-07-10 10:11:31 +02:00
|
|
|
# Configuration class for the google client
|
|
|
|
# all necessary variables and secrets are defined in this
|
|
|
|
# aswell as some helper functions
|
2020-05-27 20:06:43 +02:00
|
|
|
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"
|
|
|
|
)
|
2020-04-22 22:15:21 +02:00
|
|
|
|
2020-05-27 20:06:43 +02:00
|
|
|
# OAuth 2 client setup
|
|
|
|
self.client = WebApplicationClient(self.GOOGLE_CLIENT_ID)
|
2020-04-22 22:15:21 +02:00
|
|
|
|
|
|
|
|
2020-05-27 20:06:43 +02:00
|
|
|
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()
|
2020-04-22 22:15:21 +02:00
|
|
|
|
2020-05-30 23:05:46 +02:00
|
|
|
# stuff for OAuth login
|
2020-04-22 22:15:21 +02:00
|
|
|
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(
|
2020-05-27 20:06:43 +02:00
|
|
|
GC.CLIENT_SECRETS_FILE, scopes=GC.SCOPES)
|
2020-04-22 22:15:21 +02:00
|
|
|
# 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.
|
2020-05-29 20:30:37 +02:00
|
|
|
flow.redirect_uri = "https://longitudecalendar.com/login/google/callback"
|
2020-04-22 22:15:21 +02:00
|
|
|
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(
|
2020-05-27 20:06:43 +02:00
|
|
|
GC.CLIENT_SECRETS_FILE, scopes=GC.SCOPES, state=state)
|
2020-05-29 20:30:37 +02:00
|
|
|
flow.redirect_uri = "https://longitudecalendar.com/login/google/callback"
|
|
|
|
|
2020-04-22 22:15:21 +02:00
|
|
|
# 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.
|
2020-05-17 22:59:12 +02:00
|
|
|
|
2020-04-22 22:15:21 +02:00
|
|
|
credentials = flow.credentials
|
|
|
|
flask.session['credentials'] = credentials_to_dict(credentials)
|
2020-05-17 22:59:12 +02:00
|
|
|
print(credentials_to_dict(credentials), flush=True)
|
2020-04-22 22:15:21 +02:00
|
|
|
session = flow.authorized_session()
|
2020-04-24 19:54:56 +02:00
|
|
|
return session, credentials_to_dict(credentials)
|
2020-04-22 22:15:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
def get_google_provider_cfg():
|
2020-05-27 20:06:43 +02:00
|
|
|
return requests.get(GC.GOOGLE_DISCOVERY_URL).json()
|
2020-04-22 22:15:21 +02:00
|
|
|
|
2020-05-22 10:47:28 +02:00
|
|
|
def deleteAccount(user):
|
|
|
|
result = requests.post('https://oauth2.googleapis.com/revoke',
|
2020-05-27 20:06:43 +02:00
|
|
|
params={'token': user.google_token.token},
|
2020-05-22 10:47:28 +02:00
|
|
|
headers = {'content-type': 'applixation/x-www-form-urlencoded'})
|
|
|
|
print(result, flush=True)
|
|
|
|
return
|
|
|
|
|
2020-05-30 23:05:46 +02:00
|
|
|
|
|
|
|
def fetchCalendarEvents(user, calendars, startDate, endDate):
|
|
|
|
|
|
|
|
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)
|
2020-05-27 20:06:43 +02:00
|
|
|
|
2020-05-30 23:05:46 +02:00
|
|
|
all_events = []
|
|
|
|
for calendar in calendars:
|
|
|
|
if calendar.toggle == "True":
|
|
|
|
event_result = service.events().list(calendarId=calendar.calendar_id,
|
|
|
|
timeMin=startDate,
|
|
|
|
timeMax=endDate,
|
|
|
|
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:
|
2020-05-30 23:33:55 +02:00
|
|
|
newEvent.colorHex = calendar.color
|
|
|
|
newEvent.eventColorId = None
|
2020-05-30 23:05:46 +02:00
|
|
|
else:
|
|
|
|
newEvent.eventColorId = color
|
|
|
|
|
|
|
|
all_events.append(newEvent)
|
|
|
|
|
|
|
|
colors = service.colors().get().execute()
|
|
|
|
|
|
|
|
return all_events, colors
|
|
|
|
|
|
|
|
|
|
|
|
def fetchCalendars():
|
|
|
|
# get client api service
|
2020-06-06 20:02:18 +02:00
|
|
|
if current_user.google_token == None:
|
|
|
|
return [], None, None
|
2020-05-27 20:06:43 +02:00
|
|
|
client_token = GC.build_credentials(current_user.google_token.token,
|
|
|
|
current_user.google_token.refresh_token)
|
|
|
|
credentials = google.oauth2.credentials.Credentials(**client_token)
|
2020-05-30 23:05:46 +02:00
|
|
|
|
|
|
|
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'],
|
|
|
|
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
|
|
|
|
|
2020-04-22 22:15:21 +02:00
|
|
|
|
2020-05-27 20:06:43 +02:00
|
|
|
|
2020-04-22 22:15:21 +02:00
|
|
|
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}
|
|
|
|
|
|
|
|
|