93 lines
4.6 KiB
Python
93 lines
4.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
drive_upload.py — push Drogheda branded artifacts to the Project-Drogheda Drive folders.
|
|
|
|
WHY THIS EXISTS
|
|
The Drive MCP connector can create folders/native Docs but NOT upload binary files,
|
|
and the browser extension can't drive Drive's native file-picker dialog. This script
|
|
uses the Google Drive API directly, so it CAN upload the PDFs/xlsx. It "upserts":
|
|
if a file with the same name already exists in the target folder, it updates it;
|
|
otherwise it creates it. Run it again any time you rebuild a doc.
|
|
|
|
ONE-TIME SETUP
|
|
1) pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
|
|
2) In Google Cloud Console: create an OAuth client (Desktop app), enable the Drive API,
|
|
download the JSON as credentials.json next to this script.
|
|
3) Run: python3 drive_upload.py → a browser opens once to authorize; a token.json
|
|
is cached so future runs are non-interactive.
|
|
|
|
USAGE
|
|
cd ~/Documents/Claude/Projects/Drogheda
|
|
python3 00-Project-Management/Drive-Upload/drive_upload.py # upload all
|
|
python3 00-Project-Management/Drive-Upload/drive_upload.py --dry-run # show plan only
|
|
"""
|
|
import os, sys, argparse
|
|
REPO = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
|
|
|
# file (relative to repo root) -> Drive folder ID (Project-Drogheda subfolders)
|
|
MAPPING = [
|
|
("01-Requirements/Drogheda-HBOX-Ficha-Tecnica.pdf", "1R_ysNsVV7_f0vHevfMcSkXAdaSYgzI95"), # 01-Requirements
|
|
("01-Requirements/Drogheda-SRS-Requerimientos.pdf", "1R_ysNsVV7_f0vHevfMcSkXAdaSYgzI95"), # 01-Requirements
|
|
("01-Requirements/Drogheda-Requirements-Tracker.xlsx", "1R_ysNsVV7_f0vHevfMcSkXAdaSYgzI95"), # 01-Requirements
|
|
("03-Architecture-Hardware/Drogheda-Manual-Instalacion-Operacion.pdf", "1LBUHOk9dnrrb5UxD5q9k-jBbO7lTlXos"), # 03-Architecture-Hardware
|
|
("03-Architecture-Hardware/Drogheda-BOM-Maestro.xlsx", "1LBUHOk9dnrrb5UxD5q9k-jBbO7lTlXos"), # 03-Architecture-Hardware
|
|
("06-Testing-Validation/Drogheda-RCA-Informe-Falla.pdf", "1CNLnjSa7ro3rkRGQ6w_DBUOIp5ukizi2"), # 06-Testing-Validation
|
|
("Marketing/HBOX-Datasheet/Drogheda-HBOX-Datasheet.pdf", "1orZKyRi36nebjuHBXDLZIroXx_eWHXYZ"), # Commercial (Cliente) — ficha técnica
|
|
("Marketing/HBOX-Brochure-RTK/Drogheda-HBOX-Brochure.pdf", "1orZKyRi36nebjuHBXDLZIroXx_eWHXYZ"), # Commercial (Cliente) — flyer intro
|
|
]
|
|
SCOPES = ["https://www.googleapis.com/auth/drive.file"]
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
|
def service():
|
|
from google.oauth2.credentials import Credentials
|
|
from google_auth_oauthlib.flow import InstalledAppFlow
|
|
from google.auth.transport.requests import Request
|
|
from googleapiclient.discovery import build
|
|
tok, cred = os.path.join(HERE, "token.json"), os.path.join(HERE, "credentials.json")
|
|
creds = Credentials.from_authorized_user_file(tok, SCOPES) if os.path.exists(tok) else None
|
|
if not creds or not creds.valid:
|
|
if creds and creds.expired and creds.refresh_token:
|
|
creds.refresh(Request())
|
|
else:
|
|
if not os.path.exists(cred):
|
|
sys.exit("Missing credentials.json — see ONE-TIME SETUP in this file's header.")
|
|
creds = InstalledAppFlow.from_client_secrets_file(cred, SCOPES).run_local_server(port=0)
|
|
open(tok, "w").write(creds.to_json())
|
|
return build("drive", "v3", credentials=creds)
|
|
|
|
|
|
def upsert(svc, path, folder_id, dry):
|
|
from googleapiclient.http import MediaFileUpload
|
|
name = os.path.basename(path)
|
|
full = os.path.join(REPO, path)
|
|
if not os.path.exists(full):
|
|
print(f" SKIP {name} (not found at {path})"); return
|
|
if dry:
|
|
print(f" PLAN {name} -> {folder_id}"); return
|
|
q = f"name = '{name}' and '{folder_id}' in parents and trashed = false"
|
|
hits = svc.files().list(q=q, fields="files(id)").execute().get("files", [])
|
|
media = MediaFileUpload(full, resumable=True)
|
|
if hits:
|
|
svc.files().update(fileId=hits[0]["id"], media_body=media).execute()
|
|
print(f" UPDATED {name}")
|
|
else:
|
|
svc.files().create(body={"name": name, "parents": [folder_id]},
|
|
media_body=media, fields="id").execute()
|
|
print(f" CREATED {name}")
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--dry-run", action="store_true")
|
|
args = ap.parse_args()
|
|
svc = None if args.dry_run else service()
|
|
print("Uploading Drogheda artifacts to Project-Drogheda (Drive):")
|
|
for path, fid in MAPPING:
|
|
upsert(svc, path, fid, args.dry_run)
|
|
print("Done.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|