Skip to content
Merged
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
77 changes: 67 additions & 10 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
# 1. IMPORTANTE: Importar ProxyFix para Google Cloud Run/Render
from werkzeug.middleware.proxy_fix import ProxyFix

from flask_apscheduler import APScheduler
from sqlalchemy import text

# Imports de modelos y rutas
from core.models import db, Usuario
from auth.routes import auth_bp
Expand All @@ -33,6 +36,8 @@
from components.funcionesAdmin.routes import admin_bp
from components.categorias.routes import categorias_bp
from components.contactos.routes import contactos_bp
from core.models import db, Usuario, Notificacion
from datetime import datetime, timezone

from dotenv import load_dotenv
import firebase_admin
Expand All @@ -51,6 +56,11 @@
x_prefix=1
)


app.config['SCHEDULER_API_ENABLED'] = True
scheduler = APScheduler()


def cerrar_sesion():
"""
Cierra la sesión de base de datos de forma segura.
Expand Down Expand Up @@ -146,15 +156,62 @@ def handle_options():
headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, PATCH, DELETE, OPTIONS"
return resp


@app.route('/')
def health_check():
return "Ok"


# MAIN
# Inicializas socketio con la app
socketio.init_app(app)

def tarea_archivar_publicaciones():
with app.app_context():
try:
print(f"[{datetime.now()}] Iniciando proceso de archivado...")
sql_query = text("""
UPDATE publicaciones
SET estado = 1
WHERE estado = 0
AND COALESCE(fecha_modificacion, fecha_creacion) < NOW() - INTERVAL '6 months'
RETURNING id, id_usuario, titulo
""")

result = db.session.execute(sql_query)
archivos_procesados = result.fetchall()
if archivos_procesados:
print(f"Se encontraron {len(archivos_procesados)} publicaciones para archivar.")

for pub in archivos_procesados:
p_id = pub.id
p_usuario = pub.id_usuario
p_titulo = pub.titulo

nueva_noti = Notificacion(
id_usuario=p_usuario,
titulo='Publicación Archivada',
descripcion=f'Tu publicación "{p_titulo}" ha sido archivada automáticamente por inactividad (6 meses). Puedes desarchivarla desde tu perfil.',
tipo='sistema',
fecha_creacion=datetime.now(timezone.utc),
leido=False,
id_publicacion=p_id,
id_referencia=None
)
db.session.add(nueva_noti)

db.session.commit()
print(f"ÉXITO: {len(archivos_procesados)} publicaciones archivadas y usuarios notificados.")

else:
# Si no hay nada que archivar, hacemos commit igual para cerrar la transacción limpia
db.session.commit()
print("Sin cambios: No hay publicaciones antiguas pendientes.")

except Exception as e:
print(f"ERROR CRÍTICO en tarea programada: {e}")
db.session.rollback() # Deshace todo si algo falla


if __name__ == '__main__':
scheduler.init_app(app)
scheduler.start()
scheduler.add_job(
id='archivar_job',
func=tarea_archivar_publicaciones,
trigger='cron',
hour=3,
minute=0
)

app.run(host='0.0.0.0', port=5000, debug=True)
1 change: 1 addition & 0 deletions components/publicaciones/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def serializar_publicacion_lista(pub):
"etiquetas": [et.nombre for et in pub.etiquetas],
"fecha_creacion": pub.fecha_creacion.astimezone(zona_arg).isoformat() if pub.fecha_creacion else None,
"coordenadas": pub.coordenadas,
"estado": pub.estado,
# No enviamos descripción completa para ahorrar datos en listas
}

Expand Down
102 changes: 0 additions & 102 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,102 +0,0 @@
alembic==1.16.1
annotated-types==0.7.0
anyio==4.11.0
astroid==3.3.11
bidict==0.23.1
blinker==1.9.0
CacheControl==0.14.3
cachetools==5.5.2
certifi==2025.4.26
cffi==1.17.1
charset-normalizer==3.4.2
click==8.2.0
cloudinary==1.44.1
colorama==0.4.6
cryptography==45.0.2
deprecation==2.1.0
dill==0.4.0
dnspython==2.8.0
eventlet==0.40.3
firebase==4.0.1
firebase-admin==6.8.0
Flask==3.1.1
flask-cors==6.0.0
Flask-Migrate==4.1.0
Flask-SocketIO==5.5.1
Flask-SQLAlchemy==3.1.1
google-api-core==2.25.0rc1
google-api-python-client==2.169.0
google-auth==2.40.2
google-auth-httplib2==0.2.0
google-cloud-core==2.4.3
google-cloud-firestore==2.20.2
google-cloud-storage==3.1.0
google-crc32c==1.7.1
google-resumable-media==2.7.2
googleapis-common-protos==1.70.0
greenlet==3.2.2
grpcio==1.71.0
grpcio-status==1.71.0
h11==0.16.0
h2==4.3.0
hpack==4.1.0
httpcore==1.0.9
httplib2==0.22.0
httpx==0.28.1
hyperframe==6.1.0
idna==3.10
isort==6.0.1
itsdangerous==2.2.0
Jinja2==3.1.6
Mako==1.3.10
MarkupSafe==3.0.2
mccabe==0.7.0
msgpack==1.1.0
packaging==25.0
pillow==11.3.0
platformdirs==4.4.0
postgrest==2.20.0
proto-plus==1.26.1
protobuf==5.29.4
psycopg2==2.9.10
psycopg2-binary==2.9.10
pyasn1==0.6.1
pyasn1_modules==0.4.2
pycparser==2.22
pydantic==2.11.9
pydantic_core==2.33.2
PyJWT==2.10.1
pylint==3.3.8
pylint-flask==0.6
pylint-plugin-utils==0.9.0
pylint-sqlalchemy==0.3.0
pyparsing==3.2.3
python-dotenv==1.1.1
python-engineio==4.12.2
python-socketio==5.13.0
pytz==2025.2
qrcode==8.2
realtime==2.20.0
reportlab==4.4.2
requests==2.32.3
rsa==4.9.1
simple-websocket==1.1.0
six==1.17.0
slugify==0.0.1
sniffio==1.3.1
SQLAlchemy==2.0.41
storage3==2.20.0
StrEnum==0.4.15
supabase==2.20.0
supabase-auth==2.20.0
supabase-functions==2.20.0
tomlkit==0.13.3
typing-inspection==0.4.1
typing_extensions==4.15.0
uritemplate==4.1.1
urllib3==2.4.0
waitress==3.0.2
websockets==15.0.1
Werkzeug==3.1.3
wsproto==1.2.0