Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ Brewfile.lock.json
.DS_Store

examples/*.mp3
promotions.log
72 changes: 72 additions & 0 deletions automatizacion_promociones.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Automatización de Publicación de Promociones para tryonyou.pro

Esta guía explica el funcionamiento de los scripts diseñados para validar, monitorizar y desplegar automáticamente las promociones en el entorno de producción.

## Componentes del sistema

El sistema se compone de varios scripts, todos ellos preparados para operar en español:

1. **`deploy_promotions.py`**:
- Toma el archivo JSON con el contenido de la promoción.
- Valida su estructura asegurando que los campos obligatorios existen.
- Ejecuta la petición HTTP para enviar los datos a la API en producción.
- Soporta un modo `--dry-run` para validar sin realizar la petición de red.

2. **`automate_promotions.sh`**:
- Itera a través del directorio `promotions/`.
- Llama a `deploy_promotions.py` para cada archivo JSON.
- Mueve los archivos procesados exitosamente a `promotions_processed/` o a `promotions_failed/` en caso de error.

3. **`watch_promotions.sh`**:
- Utiliza `inotifywait` para monitorizar continuamente el directorio `promotions/`.
- Cuando se añade o modifica un archivo JSON de promoción, dispara automáticamente `automate_promotions.sh`.

4. **`rutina_desatendida_promociones.sh`**:
- Es el punto de entrada principal para la automatización en background.
- Lanza `watch_promotions.sh` en modo desacoplado (utilizando `nohup`).
- Redirige todas las salidas (logs y errores) al archivo central `promotions.log`.

## Cómo usar el sistema

### Despliegue manual e interactivo

Si deseas probar o desplegar un único archivo promocional:

```bash
./scripts/auto_deploy_promotions.sh <archivo.json>
```

Para simularlo sin afectar a la API real, asegúrate de que no esté definida la variable `TRYONYOU_API_KEY` o utiliza explícitamente `--dry-run` donde se soporte.

### Configuración del Despliegue Desatendido (Background)

Para que el servidor esté permanentemente escuchando y desplegando nuevos archivos que se depositen en la carpeta `promotions/`, ejecuta:

```bash
./scripts/rutina_desatendida_promociones.sh
```

Esto iniciará el proceso en background. El sistema te mostrará un número de proceso (PID).
Puedes monitorizar la actividad revisando el archivo de log:

```bash
tail -f promotions.log
```

### Configuración con Cron (Alternativa)

Si prefieres ejecutar el despliegue de forma periódica en lugar de reaccionar a eventos (inotify), puedes añadir una tarea cron para ejecutar el procesamiento en bloque:

1. Abre la configuración de cron:
```bash
crontab -e
```
2. Añade la siguiente línea para que se ejecute cada hora (por ejemplo):
```cron
0 * * * * /ruta/absoluta/al/proyecto/scripts/automate_promotions.sh >> /ruta/absoluta/al/proyecto/promotions.log 2>&1
```
*(Nota: Si usas cron, no es necesario ejecutar la rutina desatendida con `watch_promotions.sh`, ya que ambos cumplirían propósitos similares.)*

## Variables de Entorno

- **`TRYONYOU_API_KEY`**: Es requerida para realizar peticiones reales a la API de producción. Si no está configurada, los scripts de despliegue operarán o advertirán en modo *dry-run* o simulación.
20 changes: 10 additions & 10 deletions scripts/auto_deploy_promotions.sh
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
#!/bin/bash

# Default to promotion_example.json if no argument is provided
# Por defecto a promotion_example.json si no se proporciona argumento
PROMO_FILE="${1:-promotion_example.json}"

if [ ! -f "$PROMO_FILE" ]; then
echo "Error: Promotional content file '$PROMO_FILE' not found."
echo "Error: No se encontró el archivo de contenido promocional '$PROMO_FILE'."
exit 1
fi

# Check if API key is provided for unattended deployment
# Comprobar si se proporciona clave de API para despliegue desatendido
if [ -z "$TRYONYOU_API_KEY" ]; then
echo "Warning: TRYONYOU_API_KEY environment variable is not set."
echo "Running deployment in dry-run mode for validation..."
echo "Advertencia: La variable de entorno TRYONYOU_API_KEY no está configurada."
echo "Ejecutando despliegue en modo dry-run para validación..."
DRY_RUN="--dry-run"
else
echo "TRYONYOU_API_KEY is set. Proceeding with production deployment..."
echo "TRYONYOU_API_KEY está configurada. Procediendo con el despliegue en producción..."
DRY_RUN=""
fi

# Execute the deployment script
echo "Executing deployment..."
# Ejecutar el script de despliegue
echo "Ejecutando despliegue..."
python3 scripts/deploy_promotions.py "$PROMO_FILE" $DRY_RUN

EXIT_CODE=$?

if [ $EXIT_CODE -eq 0 ]; then
echo "Routine completed successfully."
echo "Rutina completada exitosamente."
else
echo "Routine failed with exit code $EXIT_CODE."
echo "La rutina falló con código de salida $EXIT_CODE."
exit $EXIT_CODE
fi
32 changes: 16 additions & 16 deletions scripts/deploy_promotions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def validate_promotion(data: Dict[str, Any]) -> bool:
required_fields = ["title", "description", "discount_code", "valid_until"]
for field in required_fields:
if field not in data:
raise ValueError(f"Missing required field: {field}")
raise ValueError(f"Falta un campo requerido: {field}")
return True

def deploy_promotion(data: Dict[str, Any], api_url: str, api_key: str) -> bool:
Expand All @@ -26,52 +26,52 @@ def deploy_promotion(data: Dict[str, Any], api_url: str, api_key: str) -> bool:
title = data.get("title")
if not isinstance(title, str):
title = str(title)
print(f"Deploying promotion '{title}' to {api_url}...")
print(f"Desplegando promoción '{title}' en {api_url}...")
response = urllib.request.urlopen(req)
response_data = response.read()
print(f"Deployment successful: {response_data}")
print(f"Despliegue exitoso: {response_data}")
return True
except urllib.error.URLError as e:
print(f"Failed to deploy: {e}")
print(f"Error al desplegar: {e}")
return False

def main() -> None:
parser = argparse.ArgumentParser(description="Deploy promotional content for tryonyou.pro")
parser.add_argument("file", help="Path to the JSON file containing promotional content")
parser.add_argument("--api-url", default="https://api.tryonyou.pro/v1/promotions", help="API Endpoint URL")
parser.add_argument("--dry-run", action="store_true", help="Simulate deployment without making the HTTP request")
parser = argparse.ArgumentParser(description="Desplegar contenido promocional para tryonyou.pro")
parser.add_argument("file", help="Ruta al archivo JSON que contiene el contenido promocional")
parser.add_argument("--api-url", default="https://api.tryonyou.pro/v1/promotions", help="URL del endpoint de la API")
parser.add_argument("--dry-run", action="store_true", help="Simular despliegue sin realizar la petición HTTP")

args = parser.parse_args()

if not os.path.exists(args.file):
print(f"Error: File {args.file} not found.")
print(f"Error: El archivo {args.file} no existe.")
sys.exit(1)

try:
with open(args.file, 'r', encoding='utf-8') as f:
loaded_data = json.load(f)
if not isinstance(loaded_data, dict):
raise ValueError("JSON file must contain a dictionary")
raise ValueError("El archivo JSON debe contener un diccionario")
data = cast(Dict[str, Any], loaded_data)
except (json.JSONDecodeError, ValueError) as e:
print(f"Error parsing JSON: {e}")
print(f"Error al procesar JSON: {e}")
sys.exit(1)

try:
validate_promotion(data)
print("Validation passed.")
print("Validación exitosa.")
except ValueError as e:
print(f"Validation failed: {e}")
print(f"Fallo en la validación: {e}")
sys.exit(1)

api_key = os.environ.get("TRYONYOU_API_KEY")
if not api_key and not args.dry_run:
print("Error: TRYONYOU_API_KEY environment variable is missing.")
print("Error: La variable de entorno TRYONYOU_API_KEY no está configurada.")
sys.exit(1)

if args.dry_run:
print("Simulating deployment (dry-run mode)...")
print("Deployment successful.")
print("Simulando despliegue (modo dry-run)...")
print("Despliegue simulado exitoso.")
else:
if api_key is None:
api_key = ""
Expand Down
15 changes: 15 additions & 0 deletions scripts/rutina_desatendida_promociones.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# scripts/rutina_desatendida_promociones.sh
# Inicia la monitorización y despliegue automático de promociones en background.

BASE_DIR="$(pwd)"
LOG_FILE="${BASE_DIR}/promotions.log"

echo "Iniciando rutina desatendida de promociones..."
echo "Los registros se guardarán en: $LOG_FILE"

# Ejecutar el script watch_promotions.sh en background y redirigir la salida al log
nohup "${BASE_DIR}/scripts/watch_promotions.sh" "$@" > "$LOG_FILE" 2>&1 &
PID=$!

echo "Rutina ejecutándose en background con PID: $PID"
Loading