Skip to content

Commit

Permalink
Merge pull request #2 from zLukas/add_and_download_content
Browse files Browse the repository at this point in the history
PoC version created
  • Loading branch information
zLukas authored Feb 13, 2022
2 parents 17efbaa + dcc787f commit c626862
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 68 deletions.
33 changes: 30 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,41 @@ tool features:
- upload files/folders
- download files/folders

[google API docs](https://developers.google.com/drive/api/v3/about-sdk)

# prequsities
* pipenv
* google account
* GCP cloud project([details](https://cloud.google.com))
* Enabled Drive API ([details](https://developers.google.com/workspace/guides/create-project))
* OAuth client ID credential (with .json file)([details](https://developers.google.com/workspace/guides/create-credentials))
* Test Users For Google Oauth Api defined In Google Console([details](https://support.google.com/cloud/answer/10311615?hl=en#publishing-status&zippy=%2Cexternal%2Ctesting))

* Test users For Google Oauth Api defined In Google Console([details](https://support.google.com/cloud/answer/10311615?hl=en#publishing-status&zippy=%2Cexternal%2Ctesting))

# Usage
TBD

Enable pipenv:
```
cd pyDrive/
$ pipenv shell
$ (pyDrive) pipenv install
```


Get files from google drive:
```
$ python3 pyDrive.py pull <file name>
```

upload a file to google drive:
```
$ python3 pyDrive.py push <Drive folder> <file to upload>
```

at first run google will ask you to grant access for application:
```
$ python3 pyDrive.py push file.txt
Please visit this URL to authorize this application: <url>
```
follow the link to authorize the application.
This autorization is a one time event, unless you change/update token.json file
2 changes: 1 addition & 1 deletion googleApi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from .files import DriveFiles
from .login import api_login
from .login import DriveLogin
93 changes: 75 additions & 18 deletions googleApi/files.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,78 @@
from io import FileIO
from googleapiclient.http import MediaIoBaseDownload
from googleapiclient.http import MediaFileUpload
class DriveFiles:
def __init__(self, service) -> None:
self.__service=service

def list_files(self, page_size):
# Call the Drive v3 API
results = self.__service.files().list(
pageSize=page_size, fields="nextPageToken, files(id, name)").execute()
items = results.get('files', [])

if not items:
print('No files found.')
return items
def __init__(self, service = None):
self.__service = service
self.__folders_mime="mimeType = 'application/vnd.google-apps.folder'"
self.__root_folder_id=None

def get_resource_metadata(self, name):
'''
Description: find specific resource in google drive, by name ( file and folder)
params: resource name
return: dict, keys = ["id", "kind", "name", "parents field"]
'''
serch_filter = "name="+ "'" + name + "'"
files_service = self.__service.files()
list_service = files_service.list(q = serch_filter,
pageSize=1,
# all possible fields here:
#https://developers.google.com/drive/api/v3/reference/files
fields="nextPageToken, files(kind, id, name, parents)")
search_list =list_service.execute()
if len(search_list['files']) == 0:
return None
else:
return items

def add_files(self, files):
pass

def get_files(self, file_name):
pass
return dict(search_list['files'][0])


def download_file(self, file_name):
'''
Description: download a file from google drive
params: file_name - name of the file to download
return: None
'''

file_meta = self.get_resource_metadata("file_name")
request = self.__service.files().get_media(fileId=file_meta['id'])
fh = FileIO(file_name, 'wb')
downloader = MediaIoBaseDownload(fh, request)
done = False
while done is False:
status, done = downloader.next_chunk()
print (f"Download {int(status.progress() * 100)}.")


def upload_file(self, file_name, parent_folder_id):
'''
Description: upload a file from local to google drive
params: file_name - name of the file to update
parent_folder_id - drive id of folder in which file will be uploaded
return: new_file_id['id'] - new file drive id
'''
file_metadata = {'name': file_name,
'parents': [parent_folder_id]}
media = MediaFileUpload(file_name, mimetype='text/plain')

files_service = self.__service.files()
create_service = files_service.create(body=file_metadata, media_body=media)
create_service.execute()
new_file_id =self.get_resource_metadata(file_name)
return new_file_id['id']


def create_folder(self, folder_name):
# TBD
if self.__service:
folder_metadata = {
'name': folder_name,
'mimeType': 'application/vnd.google-apps.folder'
}
files_service = self.__service.files()
create_service = files_service.create(body=folder_metadata,fields='id')
folder_id = create_service.execute()
return folder_id
else:
return "error: no service provided"
86 changes: 46 additions & 40 deletions googleApi/login.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,57 @@
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


# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']

def validate_creds(creds):
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
from os import environ

# TODO: Pass SCOPES and credential tokens as param
class DriveLogin():
def __init__(self) -> None:
# If modifying these scopes, delete the file token.json.
self.__scopes = ['https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.readonly',
'https://www.googleapis.com/auth/drive.metadata']
# TODO: read token and creds dirs form env variables, validate them

def validate_creds(self, creds):
'''
Description: Validate provided credential
params: cred - credential file (json) to validate
return: new_file_id['id'] - new file drive id
'''
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'pyDrive.json', self.__scopes)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'pyDrive.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
else:
pass
return creds
pass
return creds

# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']

def api_login():
creds = None
def api_login(self):
'''
Description: log in into google cloud service
params: none
return: service - open api session
'''
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.
# 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.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
else:
pass

validated_creds = validate_creds(creds)

try:
service = build('drive', 'v3', credentials=creds)
except HttpError as error:
service = None
print(f'An error occurred: {error}')
finally:
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', self.__scopes)
else:
pass
validated_creds = self.validate_creds(creds)

service = build('drive', 'v3', credentials=validated_creds)
return service
41 changes: 35 additions & 6 deletions pyDrive.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,38 @@
from googleApi import api_login
from googleApi import DriveFiles
from googleApi import DriveLogin
from sys import argv
from os import environ
from os import mkdir
from os import path
from os import chdir
from os import getcwd

api_service = api_login()
drive_files = DriveFiles(api_service)
files = drive_files.list_files(10)

for file in files:
print(file)
DOWNLOAD_DIR='downloads'
login = DriveLogin()
api_service = login.api_login()
drive = DriveFiles(api_service)

param = argv[1]

if param == "pull":
if not path.exists(DOWNLOAD_DIR):
mkdir(DOWNLOAD_DIR)
else:
pass

resource_name = argv[2]
base_dir = getcwd()
chdir(DOWNLOAD_DIR)
drive.download_file(resource_name)
chdir(base_dir)

elif param == "push":
if len(argv) < 4:
print("file or dir empty")
else:
file = argv[2]
dir = argv[3]
folder_meta = drive.get_resource_metadata(dir)
upload_id = drive.upload_file('test.txt', folder_meta['id'])
print(f" uploaded file id: {upload_id} ")

0 comments on commit c626862

Please sign in to comment.