From 524b40b8692c00d26a35ca256fbf91dab6369c40 Mon Sep 17 00:00:00 2001 From: Dave Mateer Date: Mon, 18 Jul 2022 13:39:00 +0100 Subject: [PATCH] Added Google OAuth flow for Google Drive so can use a real user and not a service account to save files --- configs/config.py | 3 +- create_update_test_oauth_token.py | 77 +++++++++++++++++++++++++++++++ example.config.yaml | 12 ++++- 3 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 create_update_test_oauth_token.py diff --git a/configs/config.py b/configs/config.py index 2d134da..2298c51 100644 --- a/configs/config.py +++ b/configs/config.py @@ -117,7 +117,8 @@ class Config: gd = secrets["google_drive"] self.gd_config = GDConfig( root_folder_id=gd.get("root_folder_id"), - service_account=gd.get("service_account", GDConfig.service_account) + oauth_token_file_path_and_name=gd.get("oauth_token_file_path_and_name"), + service_account=gd.get("service_account") ) if "local" in secrets: diff --git a/create_update_test_oauth_token.py b/create_update_test_oauth_token.py new file mode 100644 index 0000000..cfe2709 --- /dev/null +++ b/create_update_test_oauth_token.py @@ -0,0 +1,77 @@ +from __future__ import print_function + +import os.path + +from google.auth.transport.requests import Request +from google.oauth2.credentials import Credentials +from google_auth_oauthlib.flow import InstalledAppFlow +from googleapiclient.discovery import build +from googleapiclient.errors import HttpError + +from googleapiclient.http import MediaFileUpload + +# If creating for first time download the json `credentials.json` from https://console.cloud.google.com/apis/credentials OAuth 2.0 Client IDs +# https://davemateer.com/2022/04/28/google-drive-with-python for more information + +# Can run this code to get a new token and verify the token is the correct user +# and it will refresh the token accordingly + +# Code below from https://developers.google.com/drive/api/quickstart/python + +SCOPES = ['https://www.googleapis.com/auth/drive'] + +def main(): + # token_file = 'gd-token.json' + + token_file = 'secrets/token-davemateer-gmail.json' + + creds = None + + # The file token.json stores the user's access and refresh tokens, and is + # created automatically when the authorization flow completes for the first + # time. + if os.path.exists(token_file): + creds = Credentials.from_authorized_user_file(token_file, SCOPES) + + # If there are no (valid) credentials available, let the user log in. + if not creds or not creds.valid: + if creds and creds.expired and creds.refresh_token: + print('Requesting new token') + creds.refresh(Request()) + else: + print('First run through so putting up login dialog') + # credentials.json downloaded from https://console.cloud.google.com/apis/credentials + flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES) + creds = flow.run_local_server(port=0) + # Save the credentials for the next run + with open(token_file, 'w') as token: + print('Saving new token') + token.write(creds.to_json()) + else: + print('Token valid') + + try: + service = build('drive', 'v3', credentials=creds) + + # About the user + results = service.about().get(fields="*").execute() + emailAddress = results['user']['emailAddress'] + print(emailAddress) + + # Call the Drive v3 API and return some files + results = service.files().list( + pageSize=10, fields="nextPageToken, files(id, name)").execute() + items = results.get('files', []) + + if not items: + print('No files found.') + return + print('Files:') + for item in items: + print(u'{0} ({1})'.format(item['name'], item['id'])) + + except HttpError as error: + print(f'An error occurred: {error}') + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/example.config.yaml b/example.config.yaml index f823c47..60753fa 100644 --- a/example.config.yaml +++ b/example.config.yaml @@ -18,8 +18,16 @@ secrets: # needed if you use storage=gd google_drive: - # local filename can be the same or different file from google_sheets.service_account, defaults to service_account.json - service_account: "service_account.json" + # 1.service account to write to google storage - be aware of 15GB limit. Recommend using OAuth user. + # filename can be the same or different file from google_sheets.service_account + # service_account: "service_account.json" + + # 2.token (only 1. or 2. - if both specified then this 2. token takes precedence) + # will need to have write access on the server so refresh flow works + # run the file `create_update_test_oauth_token.py` to create the token and save in a secrets directory so + # it is not checked into source control + oauth_token_file_path_and_name: "secrets/token-davemateer-gmail.json" + root_folder_id: copy XXXX from https://drive.google.com/drive/folders/XXXX # needed if you use storage=local