From 29ef6ff8dddc19bb3344173e778cd9efca45efba Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Wed, 2 Mar 2022 21:27:46 +0100 Subject: [PATCH] wip(22w9a): sql param fix --- .env.example | 4 +++- src/backup.py | 16 +++++++++------- src/cloud/__init__.py | 7 ++++++- src/cloud/gcs.py | 15 ++++++++++++++- src/db/database.py | 14 +++++++------- src/db/flags.py | 16 ---------------- src/db/sqlite.py | 9 +++++---- src/fs/fs.py | 3 ++- 8 files changed, 46 insertions(+), 38 deletions(-) delete mode 100644 src/db/flags.py diff --git a/.env.example b/.env.example index 9ba18a7..47ab5eb 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,9 @@ +# Path to the local folder to back up SOURCE_FOLDER= +# Name of the remote bucket (destination) TARGET_BUCKET= -# Cloud provider "gcs, aws, azure" +# Cloud provider (gcs, s3, azure) SERVICE_NAME= # Path to service account key file SERVICE_KEY= \ No newline at end of file diff --git a/src/backup.py b/src/backup.py index 7f625f8..7799ae2 100644 --- a/src/backup.py +++ b/src/backup.py @@ -32,7 +32,7 @@ class Backup(FileSystem): self.has_change = True - print(f"Uploading: '{item[0]}' ... ", end="") + print(f"⧖ | Uploading: '{item[0]}'", end="\r") blob = item # Upload as zip archive @@ -41,13 +41,15 @@ class Backup(FileSystem): # Upload to cloud if self.cloud.upload(blob): + print(f"✓ | Upload sucessful: '{item[0]}'") # Update local database - if self.db.set_item(item): - print("OK") - else: - print("OK, but failed to update database") + if not self.db.set_item(item): + print("🛈 | Failed to update database") else: - print("FAILED") + print(f"✕ | Upload failed: '{item[0]}'") + if self.cloud.error: + print("🛈 | " + str(self.cloud.error)) + # Remove temp zip if self.compress: @@ -61,4 +63,4 @@ class Backup(FileSystem): self.backup_item(item) if not self.has_change: - print("Up to date. No changes found") \ No newline at end of file + print("✓ | Up to date. No changes found") \ No newline at end of file diff --git a/src/cloud/__init__.py b/src/cloud/__init__.py index dccc947..9090067 100644 --- a/src/cloud/__init__.py +++ b/src/cloud/__init__.py @@ -8,6 +8,8 @@ class Storage: self._service = None self.service = os.getenv("SERVICE_NAME") + self.error = None + @property def service(self): return self._service @@ -27,4 +29,7 @@ class Storage: return values def upload(self, *argv): - return self.service.upload(*argv) \ No newline at end of file + upload = self.service.upload(*argv) + self.error = self.service.error + + return upload diff --git a/src/cloud/gcs.py b/src/cloud/gcs.py index 94d2716..1a98023 100644 --- a/src/cloud/gcs.py +++ b/src/cloud/gcs.py @@ -11,10 +11,21 @@ class StorageClient: client = storage.Client() self.bucket = client.bucket(self.get_bucket()) + self._error = None + + @property + def error(self): + return self._error + + @error.setter + def error(self, state): + self._error = state + def get_bucket(self): return os.getenv("TARGET_BUCKET") def upload(self, path: str) -> bool: + self.error = None name = get_file(path) blob = self.bucket.blob(name) @@ -22,5 +33,7 @@ class StorageClient: with open(path, "rb") as f: blob.upload_from_file(f) return True - except: + except Exception as e: + if e.response.status_code == 403: + self.error = "Account lacks 'storage.objects.create' permissions on this bucket " return False \ No newline at end of file diff --git a/src/db/database.py b/src/db/database.py index 8eebf39..c808e0f 100644 --- a/src/db/database.py +++ b/src/db/database.py @@ -27,15 +27,15 @@ class Database(SQLite): # Check if item exists in the database def item_exists(self, item: Union[list, tuple]) -> bool: - sql = f"SELECT anchor FROM manifest WHERE anchor = '{item[0]}'" - res = self.query(sql) + sql = "SELECT anchor FROM manifest WHERE anchor = ?" + res = self.query(sql, (item[0])) return res # Check if item should be backed up by comparing mtime and checksum def check_item(self, item: Union[list, tuple]) -> bool: - sql = f"SELECT {self.columns} FROM manifest WHERE anchor = '{item[0]}'" - db_item = self.query(sql) + sql = f"SELECT {self.columns} FROM manifest WHERE anchor = ?" + db_item = self.query(sql, (item[0])) # New item or item changed, so back it up if not db_item or (item != db_item[0]): @@ -44,10 +44,10 @@ class Database(SQLite): # Insert or update item in database def set_item(self, item: Union[list, tuple]) -> bool: - sql = f"UPDATE manifest SET anchor = '{item[0]}', chksum = {item[1]} WHERE anchor = '{item[0]}'" + sql = "UPDATE manifest SET anchor = ?, chksum = ? WHERE anchor = ?" if not self.item_exists(item): - sql = f"INSERT INTO manifest ({self.columns}) VALUES ('{item[0]}', {item[1]})" - self.query(sql) + sql = f"INSERT INTO manifest ({self.columns}) VALUES (?, ?)" + self.query(sql, (item[0], item[1], item[0])) return True \ No newline at end of file diff --git a/src/db/flags.py b/src/db/flags.py deleted file mode 100644 index a555a3e..0000000 --- a/src/db/flags.py +++ /dev/null @@ -1,16 +0,0 @@ -from .sqlite import SQLite - -class Flags(SQLite): - def __init__(self): - super().__init__() - - self._columns = ["k", "v"] - - @property - def columns(self): - return ",".join(self._columns) - - @columns.setter - def columns(self, columns: list): - self._columns = columns - diff --git a/src/db/sqlite.py b/src/db/sqlite.py index d15e1a4..3666637 100644 --- a/src/db/sqlite.py +++ b/src/db/sqlite.py @@ -1,6 +1,7 @@ import os import pathlib import sqlite3 as sqlite +from typing import Iterable dbname = "._cloudbackup.db" @@ -23,8 +24,8 @@ class SQLite(): return " ".join([s.strip() for s in sql.splitlines()]) # Run SQL query - def query(self, sql: str): - query = self.cursor.execute(sql) + def query(self, sql: str, params: Iterable = ()): + query = self.cursor.execute(sql, params) self.db.commit() result = query.fetchall() @@ -61,8 +62,8 @@ class SQLite(): if envar: return envar - sql = f"SELECT v FROM flags WHERE k = '{key}'" - res = self.query(sql) + sql = "SELECT v FROM flags WHERE k = ?" + res = self.query(sql, [key]) if not res: return False diff --git a/src/fs/fs.py b/src/fs/fs.py index 00314d9..befb0d6 100644 --- a/src/fs/fs.py +++ b/src/fs/fs.py @@ -26,7 +26,8 @@ class FileSystem: @staticmethod def zip(item) -> str: - dest = f"{tempfile.gettempdir()}/{str(item[1])}" + name = FileSystem.chksum(item[0]) + dest = f"{tempfile.gettempdir()}/{name}" # Make a temp zip file of single file or folder if file_exists(item[0]):