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 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): 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": 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: newEvent.colorHex = calendar.color newEvent.eventColorId = None else: newEvent.eventColorId = color all_events.append(newEvent) colors = service.colors().get().execute() 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'], 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}