refactor: reorganizar estructura del proyecto al estándar app/api_config
All checks were successful
DEPLOY_MULTI_BRACH/pipeline/head This commit looks good
All checks were successful
DEPLOY_MULTI_BRACH/pipeline/head This commit looks good
- core/ → app/api_config/ - apps/backend_admin/ → app/backend_admin/ - apps/common/ → app/common/ - apps/promociones/ → app/promociones/ - manage.py → app/manage.py - Añadir app/requirements.txt - Actualizar todos los imports y referencias (DJANGO_SETTINGS_MODULE, ROOT_URLCONF, WSGI_APPLICATION, INSTALLED_APPS) - Actualizar Dockerfile con nuevo WORKDIR Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
34
app/backend_admin/acciones.py
Normal file
34
app/backend_admin/acciones.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from django.contrib.auth import authenticate
|
||||
from rest_framework.authtoken.models import Token
|
||||
from rest_framework_simplejwt.tokens import RefreshToken
|
||||
|
||||
|
||||
class Admin:
|
||||
def get_status_action(self):
|
||||
# Tu lógica de status que ya tenías
|
||||
return {"status": "ok", "service": "Admin Infrastructure"}
|
||||
|
||||
|
||||
def obtener_token_action(self, params):
|
||||
"""
|
||||
Capa Action: Valida credenciales y genera un par de tokens JWT.
|
||||
"""
|
||||
username = params.get('username')
|
||||
password = params.get('password')
|
||||
|
||||
# 1. Autenticación
|
||||
user = authenticate(username=username, password=password)
|
||||
|
||||
if user is not None:
|
||||
# 2. Generación de JWT (Access & Refresh)
|
||||
refresh = RefreshToken.for_user(user)
|
||||
|
||||
return {
|
||||
'refresh': str(refresh),
|
||||
'access': str(refresh.access_token),
|
||||
'user': user.username,
|
||||
'status': 'success'
|
||||
}
|
||||
|
||||
return None
|
||||
|
||||
35
app/backend_admin/migrations/0001_initial.py
Normal file
35
app/backend_admin/migrations/0001_initial.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# Generated by Django 5.0.3 on 2026-04-14 23:15
|
||||
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Log',
|
||||
fields=[
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('user_id', models.IntegerField(default=0)),
|
||||
('user', models.CharField(default='anonimo', max_length=255)),
|
||||
('app_id', models.IntegerField(default=0)),
|
||||
('remote_address', models.GenericIPAddressField(blank=True, null=True)),
|
||||
('request', models.JSONField(blank=True, null=True)),
|
||||
('response', models.JSONField(blank=True, null=True)),
|
||||
('status_code', models.CharField(default='0', max_length=10)),
|
||||
('path', models.CharField(max_length=255)),
|
||||
('method', models.CharField(max_length=10)),
|
||||
('createdAt', models.DateTimeField(default=django.utils.timezone.now)),
|
||||
('updatedAt', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'audit_logs',
|
||||
},
|
||||
),
|
||||
]
|
||||
1
app/backend_admin/migrations/__init__.py
Normal file
1
app/backend_admin/migrations/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Archivo para marcar esta carpeta como paquete de migraciones
|
||||
26
app/backend_admin/models.py
Normal file
26
app/backend_admin/models.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
||||
class Log(models.Model):
|
||||
# Usamos BigAutoField para el BIGINT id de tu tabla
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
user_id = models.IntegerField(default=0)
|
||||
user = models.CharField(max_length=255, default='anonimo')
|
||||
app_id = models.IntegerField(default=0)
|
||||
# GenericIPAddressField para el tipo INET de Postgres
|
||||
remote_address = models.GenericIPAddressField(null=True, blank=True)
|
||||
request = models.JSONField(null=True, blank=True) # Para JSONB
|
||||
response = models.JSONField(null=True, blank=True) # Para JSONB
|
||||
status_code = models.CharField(max_length=10, default='0')
|
||||
path = models.CharField(max_length=255)
|
||||
method = models.CharField(max_length=10)
|
||||
createdAt = models.DateTimeField(default=timezone.now)
|
||||
updatedAt = models.DateTimeField(auto_now=True)
|
||||
|
||||
|
||||
class Meta:
|
||||
db_table = 'audit_logs'
|
||||
# managed = True <-- Asegúrate de que no esté en False
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.method} {self.path} ({self.status_code})"
|
||||
7
app/backend_admin/urls.py
Normal file
7
app/backend_admin/urls.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.urls import path
|
||||
from .views import status_view
|
||||
|
||||
urlpatterns = [
|
||||
# Ruta final: /admin/status/
|
||||
path('status/', status_view, name='admin_status'),
|
||||
]
|
||||
95
app/backend_admin/views.py
Normal file
95
app/backend_admin/views.py
Normal file
@@ -0,0 +1,95 @@
|
||||
from django.http import JsonResponse
|
||||
from .acciones import Admin
|
||||
import logging
|
||||
import json
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from django.utils import timezone
|
||||
from .models import Log
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def status_view(request):
|
||||
# BLOQUE 1: Log de iniciación
|
||||
logger.info("INICIO - Ejecutando Health Check de Administración.")
|
||||
|
||||
# BLOQUE 2: Limpieza y validación de datos
|
||||
# Para un status simple, el diccionario de limpieza está vacío
|
||||
data_cleaned = {}
|
||||
|
||||
# BLOQUE 3: Llamada a la acción
|
||||
try:
|
||||
# Instanciamos la clase Admin y llamamos al método
|
||||
admin_logic = Admin()
|
||||
response_data = admin_logic.get_status_action()
|
||||
status_code = 200
|
||||
except Exception as e:
|
||||
logger.error(f"ERROR - Fallo en get_status_action: {str(e)}")
|
||||
response_data = {"status": "error", "message": "Internal Server Error"}
|
||||
status_code = 500
|
||||
|
||||
# BLOQUE 4: Log de cierre y retorno
|
||||
logger.info(f"FIN - Health Check completado. Status: {status_code}")
|
||||
return JsonResponse(response_data, status=status_code)
|
||||
|
||||
@csrf_exempt
|
||||
@staticmethod
|
||||
def api_token(request):
|
||||
"""
|
||||
Endpoint: api/token/
|
||||
Patrón: 4 bloques con persistencia en Log DB.
|
||||
"""
|
||||
# --- BLOQUE 1: LOG INITIATION ---
|
||||
logger.info("INICIO - Petición de JWT (api/token/)")
|
||||
|
||||
# Iniciamos el registro en la base de datos (Estándar compañeros)
|
||||
log_entry = Log.objects.create(
|
||||
user='anonimo',
|
||||
path='api/token/',
|
||||
method='POST',
|
||||
createdAt=timezone.now(),
|
||||
status_code='0'
|
||||
)
|
||||
|
||||
try:
|
||||
if request.method == 'POST':
|
||||
# --- BLOQUE 2: DATA CLEANING ---
|
||||
body_data = json.loads(request.body)
|
||||
log_entry.request = body_data # Guardamos lo que entró
|
||||
log_entry.save()
|
||||
|
||||
params = {
|
||||
'username': body_data.get('username'),
|
||||
'password': body_data.get('password')
|
||||
}
|
||||
|
||||
# --- BLOQUE 3: ACTION CALL ---
|
||||
admin_logic = Admin()
|
||||
resultado = admin_logic.obtener_token_action(params)
|
||||
|
||||
# --- BLOQUE 4: LOG CLOSURE & RESPONSE ---
|
||||
if resultado:
|
||||
status = 200
|
||||
log_entry.user = resultado['user']
|
||||
log_entry.response = resultado
|
||||
log_entry.status_code = str(status)
|
||||
log_entry.updatedAt = timezone.now()
|
||||
log_entry.save()
|
||||
|
||||
logger.info(f"FIN - JWT generado para: {log_entry.user}")
|
||||
return JsonResponse(resultado, status=status)
|
||||
else:
|
||||
status = 401
|
||||
response_error = {"error": "Credenciales inválidas"}
|
||||
log_entry.status_code = str(status)
|
||||
log_entry.response = response_error
|
||||
log_entry.save()
|
||||
return JsonResponse(response_error, status=status)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"ERROR CRÍTICO en api_token: {str(e)}")
|
||||
log_entry.status_code = '500'
|
||||
log_entry.response = {'error': str(e)}
|
||||
log_entry.save()
|
||||
return JsonResponse({'error': 'Error interno'}, status=500)
|
||||
Reference in New Issue
Block a user