From 42148c50bc03a18264062369c3b490d47c754bfe Mon Sep 17 00:00:00 2001 From: Christian Krakau-Louis Date: Wed, 12 Feb 2025 00:03:58 +0100 Subject: [PATCH] added initial Dropbox code --- app/config.py | 1 + app/tasks/upload_to_dropbox.py | 69 ++++++++++++++++++++++++++++++++-- requirements.txt | 1 + 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/app/config.py b/app/config.py index d0cf6d48..f10f8017 100644 --- a/app/config.py +++ b/app/config.py @@ -18,6 +18,7 @@ class Settings(BaseSettings): dropbox_app_secret: str dropbox_token_file_path: str dropbox_folder: str + dropbox_refresh_token: str nextcloud_upload_url: str nextcloud_username: str nextcloud_password: str diff --git a/app/tasks/upload_to_dropbox.py b/app/tasks/upload_to_dropbox.py index b9353800..4875fa99 100644 --- a/app/tasks/upload_to_dropbox.py +++ b/app/tasks/upload_to_dropbox.py @@ -1,11 +1,74 @@ #!/usr/bin/env python3 +import os +import requests +import dropbox from app.config import settings from app.tasks.retry_config import BaseTaskWithRetry from app.celery_app import celery +def get_dropbox_access_token(): + """Refresh the Dropbox access token using the stored refresh token from ENV.""" + + token_url = "https://api.dropbox.com/oauth2/token" + headers = {"Content-Type": "application/x-www-form-urlencoded"} + data = { + "grant_type": "refresh_token", + "refresh_token": settings.dropbox_refresh_token, # Now using ENV + "client_id": settings.dropbox_app_key, + "client_secret": settings.dropbox_app_secret, + } + + response = requests.post(token_url, headers=headers, data=data) + + if response.status_code == 200: + return response.json()["access_token"] + else: + error_msg = f"Failed to refresh Dropbox token: {response.status_code} - {response.text}" + print(f"[ERROR] {error_msg}") + raise Exception(error_msg) + @celery.task(base=BaseTaskWithRetry) def upload_to_dropbox(file_path: str): - """Simulate uploading a file to Dropbox.""" - print(f"[INFO] Simulating upload to Dropbox: {file_path}") - return {"status": "Completed", "file": file_path} + """Uploads a file to Dropbox using the API.""" + + if not os.path.exists(file_path): + raise FileNotFoundError(f"File not found: {file_path}") + + # Extract filename and set target path + filename = os.path.basename(file_path) + dropbox_path = f"{settings.dropbox_folder}/{filename}" + + try: + # Get fresh access token + access_token = get_dropbox_access_token() + dbx = dropbox.Dropbox(access_token) + + file_size = os.path.getsize(file_path) + chunk_size = 4 * 1024 * 1024 # 4MB chunk size + + with open(file_path, "rb") as file_data: + if file_size <= chunk_size: + dbx.files_upload(file_data.read(), dropbox_path) + else: + upload_session_start_result = dbx.files_upload_session_start(file_data.read(chunk_size)) + cursor = dropbox.files.UploadSessionCursor( + session_id=upload_session_start_result.session_id, + offset=file_data.tell(), + ) + commit = dropbox.files.CommitInfo(path=dropbox_path) + + while file_data.tell() < file_size: + if (file_size - file_data.tell()) <= chunk_size: + dbx.files_upload_session_finish(file_data.read(chunk_size), cursor, commit) + else: + dbx.files_upload_session_append_v2(file_data.read(chunk_size), cursor) + cursor.offset = file_data.tell() + + print(f"[INFO] Successfully uploaded {filename} to Dropbox at {dropbox_path}.") + return {"status": "Completed", "file": file_path} + + except Exception as e: + error_msg = f"[ERROR] Failed to upload {filename} to Dropbox: {str(e)}" + print(error_msg) + raise Exception(error_msg) diff --git a/requirements.txt b/requirements.txt index e106427f..db69b66c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,3 +11,4 @@ openai #pymupdf==1.23.5 pymupdf requests +dropbox