python/ffId.py
from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.http import MediaFileUpload
def err(*m):
print('error in', __file__ + ':', *m)
x = 1 / 0
def credentials(crt):
if type(crt) != str or len(crt) < 1:
err(f"bad certification name: {crt} {type(crt)}")
""" load the credentials form google OAuth2,
see Google APPI Console https://console.developers.google.com/?authuser=0&project=quickstart-1611556606696
"""
# If modifying these scopes, delete the file token.pickle.
SCOPES =[ 'https://www.googleapis.com/auth/drive.metadata.readonly' # drive readonly
, 'https://www.googleapis.com/auth/drive' # drive file update
, 'https://www.googleapis.com/auth/documents.readonly' # docs readonly
#, 'https://www.googleapis.com/auth/documents' # docs readWrite
]
tokPiFi = f'token-{crt}.pickle' # the file to cache authorization
credJson = '/wkData/pc/googleAPIcredentials.json' # the credentials file generated by google API
creds = None
# The file token.pickle 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(tokPiFi):
with open(tokPiFi, 'rb') as token:
creds = pickle.load(token)
# 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:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(credJson, SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open(tokPiFi, 'wb') as token:
pickle.dump(creds, token)
return creds
def driveInfo():
global srvDrive, driveUs
# Call the Drive v3 API
ab = srvDrive.about().get(fields='user(displayName, emailAddress, kind), storageQuota').execute()
# print(ab)
driveUs = ab['user']['emailAddress']
print(ab['user']['kind'], ab['user']['displayName'], driveUs
, '; storage (MB) usage', round(int(ab['storageQuota']['usage'])/1048576), ', trash', round(int(ab['storageQuota']['usageInDriveTrash'])/1048576)
, ', limit', round(int(ab['storageQuota']['limit'])/1048576))
def fldWalkPrint(lv, fo, cnt):
print('{:39}'.format('{:30}'.format(' ' * lv + fo['name']) + ' ' + cnt), fo['id'])
fsE = frozenset()
def fldWalk(fo, cb, lv, done = fsE):
fFlds = "name, id, kind, mimeType, createdTime, modifiedTime, trashed, parents, owners(emailAddress)"
if type(fo) == str:
fo = srvDrive.files().get(fileId=fo,fields=fFlds).execute()
fo['path'] = ''
# print('got fo:', fo)
if fo['id'] in done:
fldWalkPrint(0, fo, 'already1')
return
elif lv == -1:
ff = [fo]
else:
ff = []
next = None
while True:
res = srvDrive.files().list(
pageSize=500, pageToken=next, fields=f"nextPageToken, files({fFlds})"
, q="'" + fo['id'] + "' in parents", orderBy="name"
).execute()
ff += res.get('files', [])
next = res.get('nextPageToken')
if next == None:
break
fc = 0
for f in ff:
fc += int(f['mimeType'] == 'application/vnd.google-apps.folder')
fldWalkPrint(lv, fo, '#' + str(fc) + '/' + str(len(ff)) + '#')
if type(done) == set:
done.add(fo['id'])
rec = []
for f in ff:
if f['id'] in done:
fldWalkPrint(lv+1, f, 'already2')
continue
if f['mimeType'] == 'application/vnd.google-apps.folder':
rec.append(f)
if 'parents' not in f:
if lv == -1:
f['parent'] = ''
f['path'] = ''
else:
err('no parent', f)
elif len(f['parents']) != 1:
err('parents in', f);
else:
f['parent'] = f['parents'][0]
del f['parents']
f['path'] = ('' if fo['path'] == '' else fo['path'] + '/') + f['name']
if len(f['owners']) != 1 or 'emailAddress' not in f['owners'][0]:
err('owners in', f);
f['owner'] = f['owners'][0]['emailAddress']
del f['owners']
# print(f)
cb(f)
for f in rec:
fldWalk(f, cb, lv+1, done)
import csv
def fo2csv(fo, fn):
with open(fn, 'w', newline='') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=['name', 'id', 'kind', 'mimeType', 'createdTime', 'modifiedTime', 'trashed', 'owner', 'path', 'parent'])
writer.writeheader()
fldWalk(fo, lambda d: writer.writerow(d), -1)
def upload(pa, fn, mime):
global srvDrive
file_metadata = {'name': fn, 'parents': [pa]}
media = MediaFileUpload(fn, mimetype=mime)
file = srvDrive.files().create(body=file_metadata,
media_body=media,
fields='id').execute()
print('created File ID:', file.get('id'))
def uploadVersion(fid, fn, mime):
global srvDrive
#file_metadata = {'name': fn, 'parents': [pa]}
media = MediaFileUpload(fn, mimetype=mime)
file = srvDrive.files().update(fileId=fid, # body=file_metadata,
media_body=media,
fields='id, name').execute()
print(f"updated File{file.get('name')}, id: {file.get('id')}")
def chownFi(fi):
global chownCnt, chownUs, driveUs
if fi['owner'] in chownCnt:
chownCnt[fi['owner']] += 1
else:
chownCnt[fi['owner']] = 1
if fi['owner'] == chownUs or fi['owner'] != driveUs:
return
if not fi['mimeType'].startswith('application/vnd.google-apps.'):
chownCnt['mimeNotGoogle'] += 1
return
chownCnt['chown'] += 1
chown2(fi, chownUs)
#print('chownFi', fi)
def chown2(fi, us):
# print('chown2', fi, us)
prms = srvDrive.permissions().list(fileId=fi['id'], fields='*').execute()['permissions']
# print('prms', prms)
pN = [p for p in prms if 'emailAddress' in p and p['emailAddress'] == us]
# print('pN ***', len(pN), pN)
try:
if len(pN) >= 1:
res = srvDrive.permissions().update(fileId=fi['id'], permissionId=pN[0]['id'], transferOwnership=True, body={'role': 'owner'}).execute()
else:
res = srvDrive.permissions().create(fileId=fi['id'], transferOwnership=True, body={'role': 'owner', 'type': 'user', 'emailAddress': us}).execute()
except BaseException as e:
print(fi, 'update/create except', e)
# print(res)
nn = srvDrive.files().get(fileId=fi['id'],fields='id, name, owners(emailAddress)').execute()
# print('after', nn)
if fi['name'] != nn['name'] or fi['id'] != nn['id'] :
err('chown2 mismatch fi', fi, '<==>', nn)
elif us == nn['owners'][0]['emailAddress']:
print(fi['name'], fi['id'], 'owner from', fi['owner'], 'changedTo', nn['owners'][0]['emailAddress'])
else:
err('could not chown fi', fi, 'to nn', nn, 'permissions', prms)
err('testend')
def chown(us):
global srvDrive, chownUs, chownCnt
chownUs = us
chownCnt = {'chown': 0, 'mimeNotGoogle': 0}
ff = []
next = None
while True:
res = srvDrive.files().list(pageSize=500, pageToken=next, fields="nextPageToken, files(id, name, parents)"
, q="'" + us + "' in owners and mimeType = 'application/vnd.google-apps.folder'").execute()
ff += res.get('files', [])
next = res.get('nextPageToken')
if next == None:
break
print('chown found', len(ff), 'folders owned by', us);
done = set()
for f in ff:
# print('walking', f)
fldWalk(f['id'], chownFi, -1, done=done)
print('chown', chownUs, 'cnt', chownCnt)
def chown7(fold):
global srvDrive, chownFlds
print('get', dUser := srvDrive.about().get(fields='user/emailAddress').execute())
print('fold', fo := srvDrive.files().get(fileId=fold,fields=chownFlds).execute())
print('my user', dUser['user']['emailAddress'], 'folder', fo['name'], 'owners', fo['owners'][0]['emailAddress'])
chown3(dUser['user']['emailAddress'], fo['owners'][0]['emailAddress'], fo)
def chown33(ownO, ownN, fold):
global srvDrive, chownFlds
print('chown3', ownO, '==>', ownN, 'in', fold)
fls = []
next = None
while True:
res = srvDrive.files().list(
pageSize=2, pageToken=next, fields="nextPageToken, files(" + chownFlds + ")"
, q="'" + fold['id'] + "' in parents and ('" + ownO + "' in owners or mimeType = 'application/vnd.google-apps.folder')").execute()
fls += res.get('files')
next = res.get('nextPageToken')
if next == None:
break
print('list got', [ f['name'] for f in fls])
for f in fls:
if f['owners'][0]['emailAddress'] == ownO :
print('f', f)
prms = srvDrive.permissions().list(fileId=f['id'], fields='*').execute()['permissions']
print('prms', prms)
pN = [p for p in prms if p['emailAddress'] == ownN]
print('pN ***', len(pN), pN)
res = srvDrive.permissions().update(fileId=f['id'], permissionId=pN[0]['id'], transferOwnership=True, body={'role': 'owner'}).execute()
print(res)
print('file now', srvDrive.files().get(fileId=f['id'],fields=chownFlds).execute())
for f in fls:
if f['mimeType'] == 'application/vnd.google-apps.folder':
chown3(ownO, ownN, f)
import argparse
def main():
global srvDrive
parser = argparse.ArgumentParser(description="ffId.py: google drive files folders Id's: list print to ffId-{cert}.csv")
parser.add_argument('cert', help='prefix for certificate. hint a=admin@spWallisellen.ch f=fiwiko@wlkl.ch w=wa@wlkl.ch')
parser.add_argument('fun', nargs='?', default='l', help='function to perform: l list to csv add new version, c=us chown us to cert user')
# parser.print_help()
# print('after print_help')
print(f"{(args := parser.parse_args())=}")
print(f"{args.cert=} {args.fun=}")
srvDrive = build('drive', 'v3', credentials=credentials(args.cert))
driveInfo()
if args.fun == 'l':
fn = f'ffId-{args.cert}.csv'
pa = 'root'
fo2csv(pa, fn)
res = srvDrive.files().list(pageSize=5, fields=f"files(id, name, parents)"
, q="'" + pa + "' in parents and name = '" + fn + "' and not trashed").execute().get('files', [])
print(f'list found {len(res)}: {res}');
if len(res) < 1:
print('no files found creating', fn)
upload('root', fn, 'text/csv')
elif len(res) > 1:
err(f'multiple files {fn} exists, please remove all but one')
else:
print('adding new version to', fn, res[0]['id'])
uploadVersion(res[0]['id'], fn, 'text/csv')
elif args.fun[0:2] == 'c=':
us = args.fun[2:]
print('chown', us)
chown(us)
elif args.fun[0:2] == 't':
id = '1jMnsw94SPsgKRg-5oDuapXqxaaLl3YG9'
fFlds = "name, id, kind, mimeType, createdTime, modifiedTime, trashed, parents, owners(emailAddress)"
fi = srvDrive.files().get(fileId=id,fields=fFlds).execute()
print('fi', fi)
co = srvDrive.files().copy(fileId=id,body={'name':'myCopy', 'parents':fi['parents']}, fields=fFlds).execute()
print('co', co)
res = srvDrive.files().delete(fileId=id).execute()
print('delete', res)
c2 = srvDrive.files().copy(fileId=co['id'],body={'name':fi['name'], 'id': fi['id'], 'parents':fi['parents']}, fields=fFlds).execute()
print('c2', c2)
else:
err('bad fun:', args.fun)
if __name__ == '__main__':
main()