From a80947d89228658bdb7e7adc4bf91bdc951a5923 Mon Sep 17 00:00:00 2001
From: Kentai Radiquum <kentai.waah@gmail.com>
Date: Mon, 17 Feb 2025 20:56:42 +0500
Subject: [PATCH] feat/admin: early return if file already exists

---
 admin/main.py               | 68 ++++++++++++++++++++++++++++---------
 admin/requirements.txt      |  2 +-
 admin/templates/Upload.html | 20 +++++++----
 3 files changed, 66 insertions(+), 24 deletions(-)

diff --git a/admin/main.py b/admin/main.py
index 65bd011..eb0be5d 100644
--- a/admin/main.py
+++ b/admin/main.py
@@ -10,7 +10,9 @@ import boto3
 from botocore.client import Config
 from botocore.exceptions import ClientError, SSLError
 import firebase_admin
-from firebase_admin import firestore, credentials, exceptions
+from firebase_admin import firestore, credentials
+from firebase_admin import exceptions as FB_EXCEPTION
+from google.api_core import exceptions as GOOGLE_EXCEPTION
 
 load_dotenv()
 UPLOAD_FOLDER = "./temp"
@@ -123,19 +125,6 @@ def ApiUpload():
         )
 
     Image = PIL.Image.open(os.path.join(app.config["UPLOAD_FOLDER"], filename))
-    TMP_FILE = open(os.path.join(app.config["UPLOAD_FOLDER"], filename), "rb")
-    file_path = filename.split(".")[0]
-    file_ext = filename.split(".")[-1]
-
-    s3OrigFileResponse = upload_file(
-        TMP_FILE, os.getenv("AWS_BUCKET"), f"{file_path}/{filename}", file.mimetype
-    )
-    if s3OrigFileResponse is not True:
-        return Response(
-            json.dumps({"status": "error", "message": f"S3 ERR: {s3OrigFileResponse}"}),
-            500,
-        )
-
     try:
         db.collection(os.getenv("PREFIX")).add(
             {
@@ -149,9 +138,56 @@ def ApiUpload():
             },
             request.files["file"].filename,
         )
-    except exceptions.CONFLICT:
+    except (FB_EXCEPTION.ConflictError, FB_EXCEPTION.AlreadyExistsError, GOOGLE_EXCEPTION.AlreadyExists) as e:
+        Image.close()
+        os.remove(os.path.join(app.config["UPLOAD_FOLDER"], filename))
         return Response(
-            '{"status": "error", "message": "FIRESTORE ERR: CONFLICT"}', 400
+            json.dumps({"status": "error", "message": f"FIRESTORE ERR: {e}"}), 400
         )
 
+    file_path = filename.split(".")[0]
+    file_ext = filename.split(".")[-1]
+
+    temp_file = open(os.path.join(app.config["UPLOAD_FOLDER"], filename), "rb")
+    s3OrigFileResponse = upload_file(
+        temp_file, os.getenv("AWS_BUCKET"), f"{file_path}/{filename}", file.mimetype
+    )
+    if s3OrigFileResponse is not True:
+        return Response(
+            json.dumps({"status": "error", "message": f"S3 ERR: {s3OrigFileResponse}"}),
+            500,
+        )
+    temp_file.close()
+
+    size = 24, 24
+    Image.thumbnail(size, PIL.Image.Resampling.LANCZOS)
+    Image.save(
+        os.path.join(app.config["UPLOAD_FOLDER"], f"{file_path}-24px.{file_ext}")
+    )
+    Image.close()
+
+    temp_file = open(
+        os.path.join(app.config["UPLOAD_FOLDER"], f"{file_path}-24px.{file_ext}"), "rb"
+    )
+    s3BlurFileResponse = upload_file(
+        temp_file,
+        os.getenv("AWS_BUCKET"),
+        f"{file_path}/{file_path}-24px.{file_ext}",
+        file.mimetype,
+    )
+    if s3BlurFileResponse is not True:
+        db.collection(os.getenv("PREFIX")).document(
+            request.files["file"].filename
+        ).delete()
+        s3.delete_object(Bucket=os.getenv("AWS_BUCKET"), Key=f"{file_path}/{filename}")
+        s3.delete_object(Bucket=os.getenv("AWS_BUCKET"), Key=f"{file_path}")
+        return Response(
+            json.dumps({"status": "error", "message": f"S3 ERR: {s3BlurFileResponse}"}),
+            500,
+        )
+    temp_file.close()
+
+    os.remove(os.path.join(app.config["UPLOAD_FOLDER"], filename))
+    os.remove(os.path.join(app.config["UPLOAD_FOLDER"], f"{file_path}-24px.{file_ext}"))
+
     return {"status": "ok", "message": "Uploaded"}
diff --git a/admin/requirements.txt b/admin/requirements.txt
index c923232..e2b7ae7 100644
--- a/admin/requirements.txt
+++ b/admin/requirements.txt
@@ -1,7 +1,7 @@
 python-dotenv   # Load environment variables from .env
 
 boto3==1.35.99           # AWS SDK for Python (S3)
-boto3-stubs[essential]
+boto3-stubs[essential]==1.35.99
 firebase-admin  # Firebase Admin SDK for Python (FireStore)
 
 Flask           # Web framework
diff --git a/admin/templates/Upload.html b/admin/templates/Upload.html
index 96d271e..341bf40 100644
--- a/admin/templates/Upload.html
+++ b/admin/templates/Upload.html
@@ -35,8 +35,8 @@
     </div>
 
     <div class="flex gap-4">
-        <div id="datepicker-inline" inline-datepicker datepicker-buttons
-            datepicker-format="dd/mm/yyyy" datepicker-title="Shoot Date" data-date="today"></div>
+        <div id="datepicker-inline" inline-datepicker datepicker-buttons datepicker-format="dd/mm/yyyy"
+            datepicker-title="Shoot Date" data-date="today"></div>
         <div class="w-full flex flex-col gap-4">
             <div class="w-full">
                 <label for="tags-input"
@@ -184,7 +184,6 @@
     });
     form.addEventListener('submit', (e) => {
         e.preventDefault();
-        btnSubmit.disabled = true;
 
         const formFields = form.elements;
         const formData = new FormData(form);
@@ -215,20 +214,27 @@
             }
         }
 
+        btnSubmit.setAttribute('disabled', true);
+
         fetch('{{ url_for("ApiUpload") }}', {
             method: 'POST',
             body: formData
         })
-            .then(res => res.json())
+            .then(res => {
+                return res.json();
+            })
             .then(data => {
                 console.log(data);
-                btnSubmit.disabled = false;
+                btnSubmit.removeAttribute('disabled');
                 alert(data.message);
-                window.location.href = "{{ url_for('Home') }}";
+                if (data.status != "error") {
+                    window.location.href = "{{ url_for('Home') }}";
+                }
             })
             .catch(err => {
                 console.log(err);
-                btnSubmit.disabled = false;
+                btnSubmit.removeAttribute('disabled');
+                alert(err.message);
             })
     });