Drogheda/00-Project-Management/Drive-Upload/drive_upload.py

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()