latapp 9 месяцев назад
Родитель
Сommit
4253d761f5
5 измененных файлов с 57 добавлено и 13 удалено
  1. 2 1
      .gitignore
  2. 11 9
      config/mails.py
  3. 3 0
      config/settings.py
  4. 1 0
      routes/products.py
  5. 40 3
      services/data_service.py

+ 2 - 1
.gitignore

@@ -11,4 +11,5 @@ dksdabjhvjhSADhsbjksf.txt
 data/data.db
 data/data.db
 /logs
 /logs
 mrda.txt
 mrda.txt
-.env
+.env
+public/images/

+ 11 - 9
config/mails.py

@@ -1,12 +1,14 @@
+from config.settings import APP_NAME, CURRENT_URL
+
 
 
 REGISTER_MAIL = {
 REGISTER_MAIL = {
-    "subject": "Bienvenido a Pedidos Express - Confirma tu registro",
+    "subject": f"Bienvenido a {APP_NAME} - Confirma tu registro",
     "body": """
     "body": """
 <html>
 <html>
 <head>
 <head>
     <meta charset="UTF-8">
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>¡Bienvenido a {app_name}!</title>
+    <title>¡Bienvenido a """+APP_NAME+"""!</title>
     <style>
     <style>
         body {{
         body {{
             margin: 0;
             margin: 0;
@@ -222,20 +224,20 @@ REGISTER_MAIL = {
             <!-- Header -->
             <!-- Header -->
             <div class="header">
             <div class="header">
                 <h1>¡Hola {name}!</h1>
                 <h1>¡Hola {name}!</h1>
-                <p>Bienvenido a {app_name}</p>
+                <p>Bienvenido a """+APP_NAME+"""</p>
             </div>
             </div>
             
             
             <!-- Content -->
             <!-- Content -->
             <div class="content">
             <div class="content">
                 <!-- Welcome Message -->
                 <!-- Welcome Message -->
                 <div class="welcome-message">
                 <div class="welcome-message">
-                    <h2>Te damos la bienvenida a {app_name}</h2>
+                    <h2>Te damos la bienvenida a """+APP_NAME+"""</h2>
                     <p>Tu registro ha sido exitoso. <br>Estamos emocionados de tenerte con nosotros. Para completar tu registro, necesitas crear tu PIN de seguridad.</p>
                     <p>Tu registro ha sido exitoso. <br>Estamos emocionados de tenerte con nosotros. Para completar tu registro, necesitas crear tu PIN de seguridad.</p>
                 </div>
                 </div>
                 
                 
                 <!-- Benefits Section -->
                 <!-- Benefits Section -->
                 <div class="benefits-section">
                 <div class="benefits-section">
-                    <h3 class="benefits-title">¿Qué puedes hacer con {app_name}?</h3>
+                    <h3 class="benefits-title">¿Qué puedes hacer con """+APP_NAME+"""?</h3>
                     <ul class="benefits-list">
                     <ul class="benefits-list">
                         <li>Realizar pedidos de forma rápida y sencilla</li>
                         <li>Realizar pedidos de forma rápida y sencilla</li>
                         <li>Acceder a promociones exclusivas</li>
                         <li>Acceder a promociones exclusivas</li>
@@ -250,12 +252,12 @@ REGISTER_MAIL = {
                     <div class="verification-icon">🔐</div>
                     <div class="verification-icon">🔐</div>
                     <div class="verification-description">Crea tu PIN de seguridad para comenzar</div>
                     <div class="verification-description">Crea tu PIN de seguridad para comenzar</div>
                     <div class="verification-description">Vence en <strong>1 hora</strong></div>
                     <div class="verification-description">Vence en <strong>1 hora</strong></div>
-                    <a href="http://179.57.171.91:5001/verify?q={verification_code}" class="cta-button">Crear mi PIN ahora</a>
+                    <a href='"""+CURRENT_URL+"""/verify?q={verification_code}' class="cta-button">Crear mi PIN ahora</a>
                 </div>
                 </div>
                 
                 
                 <!-- Security Note -->  
                 <!-- Security Note -->  
                 <div class="security-note">
                 <div class="security-note">
-                    <p>🔒 Tu PIN será tu clave personal para acceder de forma segura a {app_name}</p>
+                    <p>🔒 Tu PIN será tu clave personal para acceder de forma segura a """+APP_NAME+"""}</p>
                 </div>
                 </div>
                 
                 
                 <!-- Website Section -->
                 <!-- Website Section -->
@@ -437,7 +439,7 @@ PIN_RECOVERY_MAIL = {
                                 <tr>
                                 <tr>
                                     <td style="text-align: center; margin-bottom: 32px;">
                                     <td style="text-align: center; margin-bottom: 32px;">
                                         <h2 style="color: #101419; font-size: 24px; margin: 0 0 12px 0; font-weight: bold;">¿Olvidaste tu PIN?</h2>
                                         <h2 style="color: #101419; font-size: 24px; margin: 0 0 12px 0; font-weight: bold;">¿Olvidaste tu PIN?</h2>
-                                        <p style="color: #6b7280; font-size: 16px; line-height: 1.6; margin: 0;">No te preocupes, puedes crear un nuevo PIN de acceso a {app_name}.</p>
+                                        <p style="color: #6b7280; font-size: 16px; line-height: 1.6; margin: 0;">No te preocupes, puedes crear un nuevo PIN de acceso a """+APP_NAME+""".</p>
                                     </td>
                                     </td>
                                 </tr>
                                 </tr>
                             </table>
                             </table>
@@ -495,7 +497,7 @@ PIN_RECOVERY_MAIL = {
                                         <p style="color: #374151; font-size: 14px; line-height: 1.5; margin: 0;">
                                         <p style="color: #374151; font-size: 14px; line-height: 1.5; margin: 0;">
                                             1. Haz clic en "Crear Nuevo PIN"<br>
                                             1. Haz clic en "Crear Nuevo PIN"<br>
                                             2. Elige un PIN fácil de recordar pero seguro<br>
                                             2. Elige un PIN fácil de recordar pero seguro<br>
-                                            3. Ingresa a {app_name} con tu nuevo PIN<br>
+                                            3. Ingresa a """+APP_NAME+""" con tu nuevo PIN<br>
                                             4. ¡Disfruta de todos nuestros beneficios!
                                             4. ¡Disfruta de todos nuestros beneficios!
                                         </p>
                                         </p>
                                     </td>
                                     </td>

+ 3 - 0
config/settings.py

@@ -24,9 +24,12 @@ logging.basicConfig(
 )
 )
 
 
 # Configuration
 # Configuration
+APP_NAME = os.getenv("APP_NAME", "Pedidos Express")
 FEEDBACK_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'logs', 'feedback.json')
 FEEDBACK_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'logs', 'feedback.json')
 OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
 OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
+IMAGE_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'public', 'images')
 PORT = int(os.getenv("PORT", 6001))
 PORT = int(os.getenv("PORT", 6001))
+CURRENT_URL = os.getenv("CURRENT_URL", "http://localhost:6001")
 PIN_KEY = os.getenv("PIN_KEY", "-1")
 PIN_KEY = os.getenv("PIN_KEY", "-1")
 DEVELOPMENT = True if os.getenv("NODE_ENV", "development").lower() == "development" else False
 DEVELOPMENT = True if os.getenv("NODE_ENV", "development").lower() == "development" else False
 if PIN_KEY == "-1":
 if PIN_KEY == "-1":

+ 1 - 0
routes/products.py

@@ -101,6 +101,7 @@ async def edit_product(product_id: int, product: ProductEditRequest, current_use
     
     
     # Check if user has sufficient permissions (manager level or above)
     # Check if user has sufficient permissions (manager level or above)
     if user_data_service.permissions(current_user.id) > 0:
     if user_data_service.permissions(current_user.id) > 0:
+
         # Update product with provided data (excluding unset fields)
         # Update product with provided data (excluding unset fields)
         product_data_service.update(product_id, **product.model_dump(exclude_unset=True))
         product_data_service.update(product_id, **product.model_dump(exclude_unset=True))
         
         

+ 40 - 3
services/data_service.py

@@ -1,15 +1,16 @@
 import json
 import json
 from math import log
 from math import log
 import os
 import os
+import re
 import sqlite3
 import sqlite3
 from typing import List, Dict, Optional, Any
 from typing import List, Dict, Optional, Any
 from abc import ABC, abstractmethod
 from abc import ABC, abstractmethod
-from config.settings import BG_DATA_PATH, DB_PATH, PRODUCT_DATA_PATH
+from config.settings import BG_DATA_PATH, DB_PATH, IMAGE_PATH, PRODUCT_DATA_PATH, CURRENT_URL
 from logging import getLogger
 from logging import getLogger
 from datetime import datetime
 from datetime import datetime
 from cryptography.fernet import Fernet
 from cryptography.fernet import Fernet
 from config.settings import PIN_KEY
 from config.settings import PIN_KEY
-
+import base64 as b64
 # Import models
 # Import models
 from models.user import User
 from models.user import User
 from models.items import Product
 from models.items import Product
@@ -457,6 +458,12 @@ class ProductDataService(BaseDataService):
         """Add a new product to the database"""
         """Add a new product to the database"""
         conn = self._get_connection()
         conn = self._get_connection()
         cursor = conn.cursor()
         cursor = conn.cursor()
+        if image and "base64" in image:
+            extension = re.search(r'data:image/(.*?);base64,', image)
+            image_name = f"{id}_img"
+            if extension:
+                image_name += f".{extension.group(1)}"
+            image = self._image_process(image_name, image)
         try:
         try:
             cursor.execute(
             cursor.execute(
                 "INSERT INTO products (id, name, type, description, price, image, status) VALUES (?, ?, ?, ?, ?, ?, ?)",
                 "INSERT INTO products (id, name, type, description, price, image, status) VALUES (?, ?, ?, ?, ?, ?, ?)",
@@ -514,7 +521,7 @@ class ProductDataService(BaseDataService):
             ) for product in products
             ) for product in products
         ]
         ]
     
     
-    def get_by_id(self, product_id: int) -> Optional[Product]:
+    def     get_by_id(self, product_id: int) -> Optional[Product]:
         """Get product by ID"""
         """Get product by ID"""
         conn = self._get_connection()
         conn = self._get_connection()
         cursor = conn.cursor()
         cursor = conn.cursor()
@@ -594,10 +601,25 @@ class ProductDataService(BaseDataService):
         ]
         ]
     #endregion
     #endregion
     #region Update
     #region Update
+    def _image_process(self, image: str, base64: str) -> str:
+        """Process image for storage"""
+        if not image or not base64:
+            raise ValueError("Image and base64 data must be provided")
+        image_path = os.path.join(IMAGE_PATH, image)
+        if not os.path.exists(IMAGE_PATH):
+            os.makedirs(IMAGE_PATH)
+        with open(image_path, 'wb') as img_file:
+            img_file.write(b64.b64decode(base64.split(',')[1]))
+        return CURRENT_URL+"/images/" + image  # Return url
+
     def update(self, product_id: int, name=None, type=None, description=None, price=None, image=None, status=None) -> bool:
     def update(self, product_id: int, name=None, type=None, description=None, price=None, image=None, status=None) -> bool:
         """Update product information"""
         """Update product information"""
         conn = self._get_connection()
         conn = self._get_connection()
         cursor = conn.cursor()
         cursor = conn.cursor()
+        product = self.get_by_id(product_id)
+        if not product:
+            logger.error(f"Product with ID {product_id} not found.")
+            return False
         updates = []
         updates = []
         params = []
         params = []
         if name is not None:
         if name is not None:
@@ -613,6 +635,18 @@ class ProductDataService(BaseDataService):
             updates.append("price = ?")
             updates.append("price = ?")
             params.append(price)
             params.append(price)
         if image is not None:
         if image is not None:
+            if product.image and product.image != image:
+                if os.path.exists(os.path.join(IMAGE_PATH, product.image)):
+                    os.remove(os.path.join(IMAGE_PATH, product.image))
+                try:
+                    extension = re.search(r'data:image/(.*?);base64,', image)
+                    if not extension:
+                        raise ValueError("Invalid image format")
+                    extension = extension.group(1)
+                    image = self._image_process(f"{product.id}_img.{extension}", image)
+                except ValueError as e:
+                    logger.error(f"Failed to process image: {e}")
+                    return False
             updates.append("image = ?")
             updates.append("image = ?")
             params.append(image)
             params.append(image)
         if status is not None:
         if status is not None:
@@ -692,6 +726,9 @@ class ProductDataService(BaseDataService):
         """Delete a product from the database"""
         """Delete a product from the database"""
         conn = self._get_connection()
         conn = self._get_connection()
         cursor = conn.cursor()
         cursor = conn.cursor()
+        product = self.get_by_id(product_id)
+        if product and product.image:
+            os.remove(os.path.join(IMAGE_PATH, product.image.removeprefix(CURRENT_URL + "/images/")))
         cursor.execute("DELETE FROM products WHERE id = ?", (product_id,))
         cursor.execute("DELETE FROM products WHERE id = ?", (product_id,))
         conn.commit()
         conn.commit()
         success = cursor.rowcount > 0
         success = cursor.rowcount > 0