230 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			230 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # Python standard libraries
 | |
| import json
 | |
| import os
 | |
| import sqlite3
 | |
| 
 | |
| # 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,
 | |
| )
 | |
| from oauthlib.oauth2 import WebApplicationClient
 | |
| import requests
 | |
| 
 | |
| # Internal imports
 | |
| from database.db import init_db_command
 | |
| from database.user import User
 | |
| 
 | |
| import caltojson
 | |
| 
 | |
| import google.oauth2.credentials
 | |
| import google_auth_oauthlib.flow
 | |
| import googleapiclient.discovery
 | |
| 
 | |
| # Configuration
 | |
| 
 | |
| CLIENT_SECRETS_FILE = "certificate/client_secret.json"
 | |
| 
 | |
| # This OAuth 2.0 access scope allows for full read/write access to the
 | |
| # authenticated user's account and requires requests to use an SSL connection.
 | |
| SCOPES = ["https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/calendar.readonly", "openid"]
 | |
| API_SERVICE_NAME = 'calendar'
 | |
| API_VERSION = 'v3'
 | |
| 
 | |
| GOOGLE_CLIENT_ID ="377787187748-shuvi4iq5bi4gdet6q3ioataimobs4lh.apps.googleusercontent.com"
 | |
| GOOGLE_CLIENT_SECRET = "Hu_YWmKsVKUcLwyeINYzdKfZ"
 | |
| GOOGLE_DISCOVERY_URL = (
 | |
|     "https://accounts.google.com/.well-known/openid-configuration"
 | |
| )
 | |
| # Flask app setup
 | |
| app = Flask(__name__,
 | |
|             static_folder='static',
 | |
|             template_folder='template')
 | |
| app.secret_key = os.environ.get("SECRET_KEY") or os.urandom(24)
 | |
| 
 | |
| # User session management setup
 | |
| # https://flask-login.readthedocs.io/en/latest
 | |
| login_manager = LoginManager()
 | |
| login_manager.init_app(app)
 | |
| 
 | |
| # Naive database setup
 | |
| try:
 | |
|     init_db_command()
 | |
| except sqlite3.OperationalError:
 | |
|     # Assume it's already been created
 | |
|     pass
 | |
| 
 | |
| # OAuth 2 client setup
 | |
| client = WebApplicationClient(GOOGLE_CLIENT_ID)
 | |
| 
 | |
| # Flask-Login helper to retrieve a user from our db
 | |
| @login_manager.user_loader
 | |
| def load_user(user_id):
 | |
|     return User.get(user_id)
 | |
| 
 | |
| @app.route("/")
 | |
| def account():
 | |
|     return flask.redirect('account')
 | |
| 
 | |
| @app.route("/account")
 | |
| def index():
 | |
|     if current_user.is_authenticated:
 | |
|         return (flask.render_template('account.html',
 | |
|             username = current_user.name, email = current_user.email, profile_img=current_user.profile_pic
 | |
|             )
 | |
|         )
 | |
|     else:
 | |
|         return flask.render_template('login.html')
 | |
| 
 | |
| def get_google_provider_cfg():
 | |
|     return requests.get(GOOGLE_DISCOVERY_URL).json()
 | |
| 
 | |
| class Calendar:
 | |
|     def __init__(self, name, color):
 | |
|         self.name = name
 | |
|         self.color = color
 | |
| 
 | |
| @app.route("/calendar")
 | |
| def calendar():
 | |
|     ca1 = Calendar("Hightower", "#30ff30")
 | |
|     ca2 = Calendar("Toast", "#66e230")
 | |
|     calendars = [ca1, ca2]
 | |
|     return flask.render_template('calendar.html', calendars=calendars)
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| @app.route('/test')
 | |
| def test_api_request():
 | |
|   if 'credentials' not in flask.session:
 | |
|     return flask.redirect('login/google')
 | |
| 
 | |
|   # Load credentials from the session.
 | |
|   credentials = google.oauth2.credentials.Credentials(
 | |
|       **flask.session['credentials'])
 | |
| 
 | |
|   todaysCal = caltojson.generateJsonFromCalendarEntries(credentials)
 | |
| 
 | |
| 
 | |
|   # 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.
 | |
|   flask.session['credentials'] = credentials_to_dict(credentials)
 | |
| 
 | |
|   return flask.jsonify(todaysCal)
 | |
| 
 | |
| @app.route("/login/google")
 | |
| def login():
 | |
| 
 | |
|     '''
 | |
|     # Find out what URL to hit for Google login
 | |
|     google_provider_cfg = get_google_provider_cfg()
 | |
|     authorization_endpoint = google_provider_cfg["authorization_endpoint"]
 | |
| 
 | |
|     # Use library to construct the request for Google login and provide
 | |
|     # scopes that let you retrieve user's profile from Google
 | |
|     request_uri = client.prepare_request_uri(
 | |
|         authorization_endpoint,
 | |
|         redirect_uri=request.base_url + "/callback",
 | |
|         scope=["openid", "email", "profile", "https://www.googleapis.com/auth/calendar.readonly"],
 | |
|     )
 | |
|     return redirect(request_uri)
 | |
|     '''
 | |
| 
 | |
|     # Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
 | |
|     flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
 | |
|         CLIENT_SECRETS_FILE, scopes=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 = request.base_url + "/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
 | |
| 
 | |
|     return flask.redirect(authorization_url)
 | |
| 
 | |
| @app.route("/login/google/callback")
 | |
| def callback():
 | |
|     # 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(
 | |
|         CLIENT_SECRETS_FILE, scopes=SCOPES, state=state)
 | |
|     flow.redirect_uri = request.base_url
 | |
| 
 | |
|     # 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)
 | |
| 
 | |
|     session = flow.authorized_session()
 | |
| 
 | |
|     userinfo = session.get('https://www.googleapis.com/userinfo/v2/me').json()
 | |
|     
 | |
|     # Create a user in your db with the information provided
 | |
|     # by Google
 | |
|     user = User(
 | |
|         id_=userinfo['id'], 
 | |
|         name=userinfo['name'], 
 | |
|         email=userinfo['email'], 
 | |
|         profile_pic=userinfo['picture']
 | |
|     )
 | |
| 
 | |
|     # Doesn't exist? Add it to the database.
 | |
|     if not User.get(user.id):
 | |
|         User.create(user.id, user.name, user.email, user.profile_pic)
 | |
| 
 | |
|     # Begin user session by logging the user in
 | |
|     login_user(user)
 | |
|     return flask.redirect(flask.url_for('index'))
 | |
|     
 | |
| @app.route("/logout")
 | |
| @login_required
 | |
| def logout():
 | |
|     logout_user()
 | |
|     return redirect(url_for("index"))
 | |
| 
 | |
| 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}
 | |
| 
 | |
| 
 | |
| @app.route("/userinfo/107971745944668140075/calendarevents.json")
 | |
| def downloader():
 | |
|     path = "/home/raphael/dev/website_ws/website/login/userinfo/107971745944668140075"
 | |
|     return flask.send_from_directory(path, "calendarevents.json")
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     context = ('certificate/xip.io.crt', 'certificate/xip.io.key')#certificate and key files
 | |
|     app.run('192.168.68.103.xip.io', 1234, ssl_context=context, debug=True)
 | |
| 
 | |
| 
 | |
| 
 |