Files
NightSpire/home/views/_base.py
T
Inna b3184fbdfe Divide home/views.py en el paquete home/views/ por secciones
El módulo monolítico (~3200 líneas) se convierte en un paquete cuyo
__init__.py re-exporta todas las vistas, de modo que `views.X`,
`from home.views import X` y la cadena 'home.views.not_found' (handler404)
siguen funcionando sin tocar urls.py.

Módulos por sección: _base (imports comunes + require_paid_stripe), auth,
pages, account, recruit, characters, store, points, guild, history,
players y payments. Cada submódulo hereda los imports con
`from ._base import *`; las dependencias entre secciones se resuelven con
imports explícitos (guild->auth, recruit/history->account).

Se eliminan dos definiciones duplicadas que quedaban muertas al cargar:
- get_character_image (primera copia, idéntica a la efectiva)
- store_novawow_success_view (stub sin SOAP, pisado por la versión real)

Validado con `manage.py check` (0 issues), resolución de las 100 rutas y
un chequeo estático de nombres no definidos por módulo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 19:09:40 +00:00

69 lines
2.8 KiB
Python

"""Imports y utilidades compartidas por el paquete de vistas (`home.views`).
Cada submódulo de vistas hace `from ._base import *` para heredar estos imports
y el decorador `require_paid_stripe`.
"""
import socket, hashlib, gmpy2, binascii, os, re, json, logging, secrets
from collections import Counter
from datetime import datetime, timedelta
from decimal import Decimal, ROUND_HALF_UP
from functools import wraps
from django import forms
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import logout
from django.db import connections
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render, redirect
from django.urls import reverse
from django.utils import timezone
from django.utils.crypto import get_random_string
from django.utils.timezone import now
from django.views.decorators.csrf import csrf_exempt
import stripe
from ..ac_soap import execute_soap_command
from ..library_correo import enviar_correo
from ..pagos_stripe import create_checkout_session, is_session_paid
from ..pagos_sumup import crear_checkout, crear_checkout_battlepay, obtener_checkout
from ..zone_definitions import get_zone_name
from .. import bnet
from ..models import (
Noticia, ClienteCategoria, ServerSelection, RecruitAFriend, DownloadClientPage,
ContentCreator, RecruitReward, ClaimedReward, AccountActivation, SecurityToken,
GuildRenameSettings, VoteSite, VoteLog, HomeApiPoints, UnstuckHistory, ReviveHistory,
RenamePrice, CustomizePrice, ChangeRacePrice, ChangeFactionPrice, LevelUpPrice,
GoldPrice, TransferPrice, Category, Item, StripeLog, LoginAttempt, Pedido,
)
# Configuración del logger
logger = logging.getLogger(__name__)
def require_paid_stripe(redirect_to='index'):
"""
Protege las vistas de "éxito" de pago: exige un `session_id` de Stripe
realmente PAGADO en la URL (Stripe lo añade tras el pago) y evita re-entregas
marcando el StripeLog como `fulfilled`. Cierra el bypass de ir directo a la
success-url sin pagar.
"""
def deco(view):
@wraps(view)
def wrapper(request, *args, **kwargs):
session_id = request.GET.get('session_id')
if not is_session_paid(session_id):
messages.error(request, 'No se ha podido verificar el pago.')
return redirect(redirect_to)
log = StripeLog.objects.filter(session_id=session_id).first()
if log is not None and log.fulfilled:
messages.info(request, 'Este pago ya había sido procesado.')
return redirect(redirect_to)
response = view(request, *args, **kwargs)
if log is not None:
log.fulfilled = True
log.save(update_fields=['fulfilled'])
return response
return wrapper
return deco