Files
NightSpire/home/views/recruit.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

162 lines
7.0 KiB
Python

from ._base import *
from .account import get_account_status, get_account_characters
def recruit_a_friend_view(request):
username = request.session.get('username')
account_status = None
characters = []
claimed_rewards_count = 0
# Si el usuario está logueado, obtener su información
if username:
# Obtener información del usuario
with connections['acore_auth'].cursor() as cursor:
cursor.execute("SELECT id, last_ip FROM account WHERE username = %s", [username])
account_data = cursor.fetchone()
if account_data:
account_id = account_data[0]
user_ip = account_data[1]
account_status = get_account_status(account_id)
characters = get_account_characters(account_id)
claimed_rewards_count = ClaimedReward.objects.filter(account_id=account_id).count()
else:
account_id = None
user_ip = None
else:
account_id = None
user_ip = None
# Obtener todas las recompensas
all_rewards = RecruitReward.objects.all()
available_rewards = []
# Si el usuario está logueado, filtrar recompensas disponibles
if account_id:
available_rewards = [reward for reward in all_rewards if not ClaimedReward.objects.filter(account_id=account_id, recruit_reward=reward).exists()]
# Manejar solicitudes POST (solo si el usuario está logueado)
if request.method == 'POST':
if not username:
return JsonResponse({'success': False, 'message': 'Debes estar logueado para reclamar una recompensa.'})
if not account_id or account_status is None:
return JsonResponse({'success': False, 'message': 'No se ha encontrado tu cuenta.'})
reward_id = request.POST.get('reward_id')
character_name = request.POST.get('character')
if not reward_id or not character_name:
return JsonResponse({'success': False, 'message': 'Selecciona una recompensa y un personaje.'})
try:
reward = RecruitReward.objects.get(id=reward_id)
# Verificar si ya se ha reclamado la recompensa
if ClaimedReward.objects.filter(account_id=account_id, recruit_reward=reward).exists():
return JsonResponse({'success': False, 'message': 'Ya has reclamado esta recompensa.'})
# Verificar si cumple los requisitos
if account_status['recruited_level_80_count'] < reward.required_friends:
return JsonResponse({'success': False, 'message': 'No cumples con los requisitos.'})
# Obtener amigos reclutados que han alcanzado el nivel 80
recruited_friends = get_recruited_friends_at_level_80(account_id, reward.required_friends)
# Comprobar si alguno de los reclutados es válido
if len(recruited_friends) < reward.required_friends:
return JsonResponse({'success': False, 'message': 'No cumples con los requisitos o los amigos tienen la misma IP.'})
# Comprobar si alguno de los reclutados tiene la misma IP que el usuario
if check_recruited_ip_conflict(recruited_friends, user_ip):
return JsonResponse({'success': False, 'message': 'No puedes reclamar recompensas de amigos que tienen la misma IP.'})
# Ejecutar el comando SOAP
command = f".send items {character_name} 'Recompensa de Recluta Amigo' 'Tu amigo alcanzó el Nivel 80' {reward.item_id}:{reward.item_quantity}"
response = execute_soap_command(command)
if response and "Mail sent to" in response:
# Registrar la recompensa como reclamada
ClaimedReward.objects.create(
account_id=account_id,
username=username,
recruit_reward=reward,
character_name=character_name,
claimed_at=timezone.now(),
ip_address=request.META.get('REMOTE_ADDR')
)
claimed_rewards_count = ClaimedReward.objects.filter(account_id=account_id).count()
return JsonResponse({
'success': True,
'message': f"Recompensa '{reward.reward_name}' entregada a {character_name}.",
'claimed_count': claimed_rewards_count
})
else:
return JsonResponse({'success': False, 'message': 'Error al entregar la recompensa.'})
except RecruitReward.DoesNotExist:
return JsonResponse({'success': False, 'message': 'Recompensa no encontrada.'})
# Renderizar la página para usuarios no logueados y logueados
return render(request, 'recruit/recruit_a_friend.html', {
'account_status': account_status,
'all_rewards': all_rewards,
'available_rewards': available_rewards,
'characters': characters,
'claimed_rewards_count': claimed_rewards_count,
'is_logged_in': username is not None
})
def check_recruited_ip_conflict(recruited_accounts, user_ip):
"""
Verifica si alguna de las cuentas reclutadas tiene la misma IP que la cuenta del reclutador.
"""
if not recruited_accounts:
return False
with connections['acore_auth'].cursor() as cursor:
cursor.execute("""
SELECT last_ip FROM account WHERE id IN %s
""", [tuple(recruited_accounts)])
recruited_ips = [ip[0] for ip in cursor.fetchall()]
return user_ip in recruited_ips
def get_recruited_friends_at_level_80(account_id, required_count):
"""
Obtiene una lista de IDs de amigos reclutados que han alcanzado el nivel 80 y
no tienen la misma IP que el reclutador.
"""
# Primero obtener los IDs de cuentas reclutadas desde `acore_auth`
with connections['acore_auth'].cursor() as auth_cursor:
auth_cursor.execute("""
SELECT id, last_ip FROM account WHERE recruiter = %s
""", [account_id])
recruited_accounts = auth_cursor.fetchall()
if not recruited_accounts:
return []
# Extraer IDs y IPs de las cuentas reclutadas
recruited_ids = [acc[0] for acc in recruited_accounts]
recruited_ips = {acc[0]: acc[1] for acc in recruited_accounts}
# Obtener la IP del usuario actual
with connections['acore_auth'].cursor() as cursor:
cursor.execute("SELECT last_ip FROM account WHERE id = %s", [account_id])
user_ip = cursor.fetchone()[0]
# Luego, verificar cuáles de esas cuentas tienen personajes al nivel 80 en `acore_characters`
with connections['acore_characters'].cursor() as char_cursor:
char_cursor.execute("""
SELECT DISTINCT account FROM characters
WHERE level = 80 AND account IN %s
LIMIT %s
""", [tuple(recruited_ids), required_count])
recruited_at_level_80 = [acc[0] for acc in char_cursor.fetchall()]
# Filtrar cuentas que no tienen la misma IP que el usuario actual
valid_recruits = [acc for acc in recruited_at_level_80 if recruited_ips[acc] != user_ip]
return valid_recruits