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}