Reflect the current year in all TechnoLibre license headers across script/, test/, and docker/. Generated by Claude Code 2.1.74 model claude-sonnet-4-6 Co-Authored-By: Mathieu Benoit <mathben@technolibre.ca>
115 lines
3.7 KiB
Python
115 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
# © 2021-2026 TechnoLibre (http://www.technolibre.ca)
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
|
|
print(
|
|
"This script only work with localhost:8069, not working with remote instance."
|
|
)
|
|
|
|
import logging
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import requests
|
|
|
|
ODOO_URL = "" # Your Odoo server URL
|
|
DATABASE_NAME = ""
|
|
MASTER_PASSWORD = ""
|
|
# BACKUP_FORMAT = env('BACKUP_FORMAT', default='zip') # 'zip' or 'dump'
|
|
BACKUP_FORMAT = "zip" # 'zip' or 'dump'
|
|
OUTPUT_FILE_NAME = f"{DATABASE_NAME}_backup.{BACKUP_FORMAT}"
|
|
|
|
# --- Logger Setup ---
|
|
logging.basicConfig(level=logging.INFO)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# TODO not working with remote, only localhost
|
|
logger.error(
|
|
"This script is not working with remote instance, only http://127.0.0.1:8069"
|
|
)
|
|
|
|
|
|
# --- Function to download the database ---
|
|
def download_odoo_db():
|
|
logger.info(
|
|
f"Attempting to download database '{DATABASE_NAME}' from URL '{ODOO_URL}'..."
|
|
)
|
|
|
|
# URL for the backup endpoint
|
|
backup_url = f"{ODOO_URL}/web/database/backup"
|
|
|
|
# Form data for the POST request
|
|
payload = {
|
|
"master_pwd": MASTER_PASSWORD,
|
|
"name": DATABASE_NAME,
|
|
"backup_format": BACKUP_FORMAT,
|
|
}
|
|
|
|
try:
|
|
# Execute the POST request to start the backup
|
|
response = requests.post(backup_url, data=payload, stream=True)
|
|
response.raise_for_status() # Raise an exception for bad status codes
|
|
|
|
# --- VALIDATION ---
|
|
content_type = response.headers.get("Content-Type", "").split(";")[0]
|
|
|
|
# Check if the content type is valid
|
|
expected_types = ["application/zip", "application/octet-stream"]
|
|
if content_type not in expected_types:
|
|
logger.error(
|
|
f"ERROR: Expected one of {expected_types} but got {content_type}."
|
|
)
|
|
logger.error(
|
|
"This usually indicates a server-side error or an incorrect master password."
|
|
)
|
|
sys.exit(1)
|
|
|
|
# Check if the content is an HTML page (to handle incorrect passwords)
|
|
first_chunk = next(response.iter_content(chunk_size=128), b"")
|
|
if first_chunk.startswith(b"<"):
|
|
logger.error(
|
|
"ERROR: It seems the server returned an HTML page instead of a database file."
|
|
)
|
|
logger.error(
|
|
"This is often due to an incorrect master password or an invalid request."
|
|
)
|
|
logger.error("Server Response (First 200 chars):")
|
|
logger.error(response.text[:200])
|
|
sys.exit(1)
|
|
|
|
# --- DOWNLOAD ---
|
|
logger.info(f"Download started, saving to '{OUTPUT_FILE_NAME}'...")
|
|
|
|
output_path = Path(OUTPUT_FILE_NAME)
|
|
with open(output_path, "wb") as f:
|
|
# Write the content from the first chunk to the file
|
|
f.write(first_chunk)
|
|
# Continue writing the rest of the stream in chunks
|
|
for chunk in response.iter_content(chunk_size=8192):
|
|
f.write(chunk)
|
|
|
|
logger.info(
|
|
f"Download successful! File saved at: {output_path.resolve()}"
|
|
)
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
logger.error(
|
|
f"An error occurred while connecting to the Odoo server: {e}"
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"An unexpected error occurred: {e}")
|
|
|
|
|
|
# --- Script execution ---
|
|
if __name__ == "__main__":
|
|
# Add a simple check to ensure the user has configured the variables
|
|
if (
|
|
ODOO_URL == "http://localhost:8069"
|
|
and DATABASE_NAME == "your_database_name"
|
|
):
|
|
logger.error(
|
|
"Please configure the ODOO_URL, DATABASE_NAME, and MASTER_PASSWORD variables at the start of the script."
|
|
)
|
|
sys.exit(1)
|
|
|
|
download_odoo_db()
|