Files
NightSpire/home/views/characters.py
T
Inna 68cfe7594b Fase 3 (isla): recuperar ítems (restore_items) en React/TSX, flujo de 2 pasos
restore_items_view ahora responde JSON cuando la petición es AJAX (X-Requested-With):
GET con character_name -> {items}; POST recover_id -> {success, message}. Se conserva
el flujo legacy (redirect+messages) para no-AJAX. RestoreItemsForm.tsx: paso 1 elegir
personaje y buscar ítems borrados (SOAP), paso 2 elegir ítem y recuperarlo; refresca la
lista tras recuperar. La vista pasa character_names por json_script.

Verificado: check OK, render de la isla, redirige a login sin sesión.

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

1006 lines
46 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from ._base import *
def rename_character_view(request):
username = request.session.get('username')
if not username:
return redirect('login')
# 🔹 Obtener información de la cuenta desde acore_auth
with connections['acore_auth'].cursor() as cursor:
cursor.execute("""
SELECT id, email, last_ip FROM account WHERE username = %s
""", [username])
account_info = cursor.fetchone()
if not account_info:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Error: Cuenta no encontrada.</span>'})
account_id, email, acore_ip = account_info
client_ip = request.META.get('REMOTE_ADDR', '')
# 🔹 Obtener personajes del usuario desde la base de datos `acore_characters`
with connections['acore_characters'].cursor() as cursor:
cursor.execute("""
SELECT name FROM characters WHERE account = %s
""", [account_id])
characters = [row[0] for row in cursor.fetchall()]
# 🔹 Obtener el precio del renombrado
price_obj = RenamePrice.objects.first()
price = price_obj.price if price_obj else 2.00
# 🔹 Ejecutar el comando SOAP para verificar el servidor
command = f".server info"
response = execute_soap_command(command)
if request.method == 'POST':
character_name = request.POST.get('character')
if response is None:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Error de comunicación con el servidor. Intente nuevamente más tarde.</span>'})
if not character_name:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Por favor, seleccione un personaje.</span>'})
if character_name not in characters:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">No tienes permiso para renombrar este personaje.</span>'})
# 🔹 Crear sesión de pago con Stripe
success_url = request.build_absolute_uri(reverse('rename-success'))
cancel_url = request.build_absolute_uri(reverse('rename-cancel'))
stripe_response = create_checkout_session(
account_id=account_id,
username=username,
email=email,
acore_ip=acore_ip,
amount=price,
character_name=character_name,
success_url=success_url,
cancel_url=cancel_url,
product_name=f"Renombrar personaje: {character_name}"
)
if stripe_response["success"]:
request.session['rename_character'] = character_name
return JsonResponse({
'success': True,
'session_id': stripe_response["session_id"],
'stripe_public_key': settings.STRIPE_PUBLIC_KEY
})
else:
return JsonResponse({'success': False, 'message': f'<span class="red-form-response">Error al iniciar el pago: {stripe_response["error"]}</span>'})
return render(request, 'account/rename_character.html', {'characters': characters, 'price': price})
@require_paid_stripe()
def rename_success_view(request):
# Procesar el comando SOAP tras el pago exitoso
character_name = request.session.get('rename_character')
if not character_name:
return redirect('rename-character')
command = f".char rename {character_name}"
response = execute_soap_command(command)
if response is None or response.strip() == "":
message = f"El personaje {character_name} ha sido marcado para renombrar."
request.session.pop('rename_character', None) # Limpiar la sesión
return render(request, 'account/rename_success.html', {'message': message})
else:
return render(request, 'account/rename_success.html', {'message': f"Error: {response}"})
def rename_cancel_view(request):
username = request.session.get('username')
if not username:
return redirect('login')
return render(request, 'account/rename_cancel.html')
def restore_character_view(request):
# Verifica si el usuario está autenticado y obtiene su nombre de usuario
username = request.session.get('username')
if not username:
return redirect('login') # Redirige si no hay sesión
# Obtener la ID de cuenta del usuario conectado a partir del sistema de autenticación personalizada
try:
with connections['acore_auth'].cursor() as cursor:
cursor.execute("SELECT id FROM account WHERE username = %s", [username])
result = cursor.fetchone()
if not result:
# Si no se encuentra la cuenta, mostrar un error
messages.error(request, "No se encontró la cuenta asociada a ese usuario.")
return redirect('login') # Redirige al login si no se encuentra la cuenta
account_id = result[0] # Obtén el ID de la cuenta
except Exception as e:
messages.error(request, f"Ocurrió un error al recuperar la cuenta: {str(e)}")
return redirect('login')
# Verificar si se ha seleccionado un personaje para restaurar
if request.method == 'POST':
# Obtener el GUID del personaje seleccionado para restaurar
guid = request.POST.get('guid')
if not guid:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">No se seleccionó un personaje para restaurar.</span>'})
# Restaurar vía SOAP y responder en JSON (isla React)
try:
command = f".char del restore {guid}" # Comando SOAP para restaurar el personaje
response = execute_soap_command(command) # Ejecuta el comando SOAP
if response == "success":
return JsonResponse({
'success': True,
'message': '<span class="ok-form-response">Personaje restaurado exitosamente.</span>',
'redirect': reverse('my-account'),
})
else:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Hubo un error al restaurar el personaje.</span>'})
except Exception as e:
return JsonResponse({'success': False, 'message': f'<span class="red-form-response">Hubo un error al intentar restaurar el personaje: {str(e)}</span>'})
# Realizar la consulta para obtener los personajes eliminados de la cuenta
with connections['acore_characters'].cursor() as cursor:
cursor.execute("""
SELECT guid, level, deleteInfos_Name, deleteInfos_Account, deleteDate
FROM characters
WHERE deleteInfos_Account = %s AND deleteDate IS NOT NULL
""", [account_id]) # Filtra por account_id
# Obtener los resultados de la consulta
deleted_characters = cursor.fetchall()
# Si no hay personajes eliminados
if not deleted_characters:
return render(request, 'account/restore_character.html', {
'message': 'No hay personajes eliminados que puedas recuperar.'
})
# Crear un listado de personajes eliminados con su nombre y nivel (si lo tienes)
character_list = []
for character in deleted_characters:
guid, level, name, account_id, delete_date = character
# Agregar la información del personaje al listado
character_list.append({
'name': name,
'guid': guid,
'level': level,
'delete_date': delete_date
})
# Renderiza la plantilla con los personajes eliminados
return render(request, 'account/restore_character.html', {
'character_list': character_list,
'character_data': [
{'guid': c['guid'], 'name': c['name'], 'level': c['level']}
for c in character_list
],
})
def restore_items_view(request):
username = request.session.get('username')
if not username:
return redirect('login')
characters = []
deleted_items = []
selected_character = None
try:
# Obtener la ID de cuenta del usuario
with connections['acore_auth'].cursor() as cursor:
cursor.execute("SELECT id FROM account WHERE username = %s", [username])
result = cursor.fetchone()
if result:
account_id = result[0]
else:
messages.error(request, "No se encontró la cuenta asociada.")
return redirect('login')
# Obtener los personajes del usuario
with connections['acore_characters'].cursor() as cursor:
cursor.execute("SELECT name FROM characters WHERE account = %s", [account_id])
characters = [row[0] for row in cursor.fetchall()]
except Exception as e:
messages.error(request, f"Error al obtener los personajes: {str(e)}")
# La isla React usa AJAX (X-Requested-With); en ese caso respondemos JSON.
is_ajax = request.headers.get('X-Requested-With') == 'XMLHttpRequest'
if request.method == "GET" and "character_name" in request.GET:
selected_character = request.GET.get("character_name")
if selected_character:
try:
# Ejecutar comando SOAP para obtener ítems eliminados del personaje seleccionado
command = f".item restore list {selected_character}"
response = execute_soap_command(command)
# Procesar la respuesta del servidor
for line in response.split("\n"):
match = re.search(r"Recover id: (\d+) \| Item: (.+) \((\d+)\) \| Count: (\d+)", line)
if match:
recover_id = match.group(1)
item_name = match.group(2)
item_id = match.group(3)
count = match.group(4)
deleted_items.append({
"recover_id": recover_id,
"item_name": item_name,
"item_id": item_id,
"count": count
})
except Exception as e:
if is_ajax:
return JsonResponse({'error': f'Error al obtener los ítems eliminados: {str(e)}'})
messages.error(request, f"Error al obtener los ítems eliminados: {str(e)}")
if is_ajax:
return JsonResponse({'items': deleted_items})
if request.method == "POST":
recover_id = request.POST.get("recover_id")
selected_character = request.POST.get("character_name")
if not recover_id or not selected_character:
if is_ajax:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Selecciona un personaje y un ítem para restaurar.</span>'})
messages.error(request, "Selecciona un personaje y un ítem para restaurar.")
return redirect('restore-items')
try:
# Ejecutar comando SOAP para restaurar el ítem
command = f".item restore {recover_id} {selected_character}"
response = execute_soap_command(command)
ok = "success" in response.lower()
except Exception as e:
if is_ajax:
return JsonResponse({'success': False, 'message': f'<span class="red-form-response">Error al restaurar el ítem: {str(e)}</span>'})
messages.error(request, f"Error al restaurar el ítem: {str(e)}")
return redirect('restore-items')
if is_ajax:
msg = ('<span class="ok-form-response">Ítem restaurado exitosamente.</span>' if ok
else '<span class="red-form-response">No se pudo restaurar el ítem.</span>')
return JsonResponse({'success': ok, 'message': msg})
messages.success(request, "Ítem restaurado exitosamente.") if ok else messages.error(request, "No se pudo restaurar el ítem.")
return redirect('restore-items')
return render(request, 'account/restore_items.html', {
'characters': characters,
'deleted_items': deleted_items,
'selected_character': selected_character,
'character_names': characters,
})
def quest_character_view(request):
username = request.session.get('username')
if not username:
return redirect('login')
return render(request, 'account/quest_character.html')
def send_gift_view(request):
username = request.session.get('username')
if not username:
return redirect('login')
return render(request, 'account/send_gift.html')
def customize_character_view(request):
username = request.session.get('username')
if not username:
return redirect('login')
# ?? Obtener información de la cuenta desde acore_auth
with connections['acore_auth'].cursor() as cursor:
cursor.execute("""
SELECT id, email, last_ip FROM account WHERE username = %s
""", [username])
account_info = cursor.fetchone()
if not account_info:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Error: Cuenta no encontrada.</span>'})
account_id, email, acore_ip = account_info
client_ip = request.META.get('REMOTE_ADDR', '')
# ?? Obtener personajes del usuario desde la base de datos `acore_characters`
with connections['acore_characters'].cursor() as cursor:
cursor.execute("""
SELECT name FROM characters WHERE account = %s
""", [account_id])
characters = [row[0] for row in cursor.fetchall()]
# Obtener el precio de la personalización (si se gestiona desde el admin)
price_obj = CustomizePrice.objects.first()
price = price_obj.price if price_obj else 1.00
if request.method == 'POST':
character_name = request.POST.get('character')
# Validar si el personaje fue seleccionado
if not character_name:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Por favor, seleccione un personaje.</span>'})
# Verificar si el personaje pertenece al usuario
if character_name not in characters:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">No tienes permiso para personalizar este personaje.</span>'})
# Crear sesión de pago con Stripe
success_url = request.build_absolute_uri(reverse('customize-success'))
cancel_url = request.build_absolute_uri(reverse('customize-cancel'))
stripe_response = create_checkout_session(
account_id=account_id,
username=username,
email=email,
acore_ip=acore_ip,
amount=price,
character_name=character_name,
success_url=success_url,
cancel_url=cancel_url,
product_name=f"Personalizar personaje: {character_name}"
)
if stripe_response["success"]:
# Guardar temporalmente el nombre del personaje en la sesión
request.session['customize_character'] = character_name
return JsonResponse({
'success': True,
'session_id': stripe_response["session_id"],
'stripe_public_key': settings.STRIPE_PUBLIC_KEY
})
else:
return JsonResponse({'success': False, 'message': f'<span class="red-form-response">Error al iniciar el pago: {stripe_response["error"]}</span>'})
return render(request, 'account/customize_character.html', {'characters': characters, 'price': price})
@require_paid_stripe()
def customize_success_view(request):
# Procesar el comando SOAP tras el pago exitoso
character_name = request.session.get('customize_character')
if not character_name:
return redirect('customize-character')
command = f".char customi {character_name}"
response = execute_soap_command(command)
if response is None or response.strip() == "":
message = f"El personaje {character_name} ha sido marcado para personalización."
request.session.pop('customize_character', None) # Limpiar la sesión
return render(request, 'account/customize_success.html', {'message': message})
else:
return render(request, 'account/customize_success.html', {'message': f"Error: {response}"})
def customize_cancel_view(request):
return render(request, 'account/customize_cancel.html')
def change_race_character_view(request):
username = request.session.get('username')
if not username:
return redirect('login')
# Obtener personajes del usuario desde la base de datos `acore_characters`
with connections['acore_auth'].cursor() as cursor:
cursor.execute("""
SELECT id, email, last_ip FROM account WHERE username = %s
""", [username])
account_info = cursor.fetchone()
if not account_info:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Error: Cuenta no encontrada.</span>'})
account_id, email, acore_ip = account_info
client_ip = request.META.get('REMOTE_ADDR', '')
# ?? Obtener personajes del usuario desde la base de datos `acore_characters`
with connections['acore_characters'].cursor() as cursor:
cursor.execute("""
SELECT name FROM characters WHERE account = %s
""", [account_id])
characters = [row[0] for row in cursor.fetchall()]
# Obtener el precio del cambio de raza
price_obj = ChangeRacePrice.objects.first()
price = price_obj.price if price_obj else 10.00 # Precio predeterminado si no hay registro
if request.method == 'POST':
character_name = request.POST.get('character')
# Validar si el personaje fue seleccionado
if not character_name:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Por favor, seleccione un personaje.</span>'})
# Verificar si el personaje pertenece al usuario
if character_name not in characters:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">No tienes permiso para cambiar la raza de este personaje.</span>'})
# Crear sesión de pago con Stripe
success_url = request.build_absolute_uri(reverse('change-race-success'))
cancel_url = request.build_absolute_uri(reverse('change-race-cancel'))
stripe_response = create_checkout_session(
account_id=account_id,
username=username,
email=email,
acore_ip=acore_ip,
amount=price,
character_name=character_name,
success_url=success_url,
cancel_url=cancel_url,
product_name=f"Cambio de Raza del personaje: {character_name}"
)
if stripe_response["success"]:
# Guardar el personaje en la sesión para el cambio
request.session['change_race_character'] = character_name
return JsonResponse({
'success': True,
'session_id': stripe_response["session_id"],
'stripe_public_key': settings.STRIPE_PUBLIC_KEY
})
else:
return JsonResponse({'success': False, 'message': f'<span class="red-form-response">Error al iniciar el pago: {stripe_response["error"]}</span>'})
return render(request, 'account/change_race.html', {'characters': characters, 'price': price})
@require_paid_stripe()
def change_race_success_view(request):
# Procesar el comando SOAP tras el pago exitoso
character_name = request.session.get('change_race_character')
if not character_name:
return redirect('change-race')
command = f".char changerace {character_name}"
response = execute_soap_command(command)
if response is None or response.strip() == "":
message = f"El personaje {character_name} ha sido marcado para cambio de raza."
request.session.pop('change_race_character', None) # Limpiar la sesión
return render(request, 'account/change_race_success.html', {'message': message})
else:
return render(request, 'account/change_race_success.html', {'message': f"Error: {response}"})
def change_race_cancel_view(request):
return render(request, 'account/change_race_cancel.html')
def change_faction_character_view(request):
username = request.session.get('username')
if not username:
return redirect('login')
# Obtener personajes del usuario desde la base de datos `acore_characters`
with connections['acore_auth'].cursor() as cursor:
cursor.execute("""
SELECT id, email, last_ip FROM account WHERE username = %s
""", [username])
account_info = cursor.fetchone()
if not account_info:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Error: Cuenta no encontrada.</span>'})
account_id, email, acore_ip = account_info
client_ip = request.META.get('REMOTE_ADDR', '')
# ?? Obtener personajes del usuario desde la base de datos `acore_characters`
with connections['acore_characters'].cursor() as cursor:
cursor.execute("""
SELECT name FROM characters WHERE account = %s
""", [account_id])
characters = [row[0] for row in cursor.fetchall()]
# Obtener el precio del cambio de facción
price_obj = ChangeFactionPrice.objects.first()
price = price_obj.price if price_obj else 10.00
if request.method == 'POST':
character_name = request.POST.get('character')
# Validar si el personaje fue seleccionado
if not character_name:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Por favor, seleccione un personaje.</span>'})
# Verificar si el personaje pertenece al usuario
if character_name not in characters:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">No tienes permiso para cambiar la facción de este personaje.</span>'})
# Crear sesión de pago con Stripe
success_url = request.build_absolute_uri(reverse('change-faction-success'))
cancel_url = request.build_absolute_uri(reverse('change-faction-cancel'))
stripe_response = create_checkout_session(
account_id=account_id,
username=username,
email=email,
acore_ip=acore_ip,
amount=price,
character_name=character_name,
success_url=success_url,
cancel_url=cancel_url,
product_name=f"Cambiar Faccion del personaje: {character_name}"
)
if stripe_response["success"]:
# Guardar el personaje seleccionado en la sesión
request.session['change_faction_character'] = character_name
return JsonResponse({
'success': True,
'session_id': stripe_response["session_id"],
'stripe_public_key': settings.STRIPE_PUBLIC_KEY
})
else:
return JsonResponse({'success': False, 'message': f'<span class="red-form-response">Error al iniciar el pago: {stripe_response["error"]}</span>'})
return render(request, 'account/change_faction.html', {'characters': characters, 'price': price})
@require_paid_stripe()
def change_faction_success_view(request):
# Procesar el comando SOAP tras el pago exitoso
character_name = request.session.get('change_faction_character')
if not character_name:
return redirect('change-faction-character')
command = f".char changef {character_name}"
response = execute_soap_command(command)
if response is None or response.strip() == "":
message = f"El personaje {character_name} ha cambiado de facción con éxito."
request.session.pop('change_faction_character', None) # Limpiar la sesión
return render(request, 'account/change_faction_success.html', {'message': message})
else:
return render(request, 'account/change_faction_success.html', {'message': f"Error: {response}"})
def change_faction_cancel_view(request):
return render(request, 'account/change_faction_cancel.html')
def level_up_character_view(request):
username = request.session.get('username')
if not username:
return redirect('login')
# Obtener personajes del usuario desde la base de datos `acore_characters`
with connections['acore_auth'].cursor() as cursor:
cursor.execute("""
SELECT id, email, last_ip FROM account WHERE username = %s
""", [username])
account_info = cursor.fetchone()
if not account_info:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Error: Cuenta no encontrada.</span>'})
account_id, email, acore_ip = account_info
client_ip = request.META.get('REMOTE_ADDR', '')
# ?? Obtener personajes del usuario desde la base de datos `acore_characters`
with connections['acore_characters'].cursor() as cursor:
cursor.execute("""
SELECT name FROM characters WHERE account = %s
""", [account_id])
characters = [row[0] for row in cursor.fetchall()]
# Obtener el precio de subir a nivel 80
price_obj = LevelUpPrice.objects.first()
price = price_obj.price if price_obj else 10.00
if request.method == 'POST':
character_name = request.POST.get('character')
# Validar si el personaje fue seleccionado
if not character_name:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Por favor, seleccione un personaje.</span>'})
# Verificar si el personaje pertenece al usuario
if character_name not in characters:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">No tienes permiso para subir de nivel a este personaje.</span>'})
# Crear sesión de pago con Stripe
success_url = request.build_absolute_uri(reverse('level-up-success'))
cancel_url = request.build_absolute_uri(reverse('level-up-cancel'))
stripe_response = create_checkout_session(
account_id=account_id,
username=username,
email=email,
acore_ip=acore_ip,
amount=price,
character_name=character_name,
success_url=success_url,
cancel_url=cancel_url,
product_name=f"Subir el Nivel 80 del personaje: {character_name}"
)
if stripe_response["success"]:
# Guardar el personaje en la sesión para usarlo después del pago
request.session['levelup_character'] = character_name
return JsonResponse({
'success': True,
'session_id': stripe_response["session_id"],
'stripe_public_key': settings.STRIPE_PUBLIC_KEY
})
else:
return JsonResponse({'success': False, 'message': f'<span class="red-form-response">Error al iniciar el pago: {stripe_response["error"]}</span>'})
return render(request, 'account/level_up.html', {'characters': characters, 'price': price})
@require_paid_stripe()
def level_up_success_view(request):
character_name = request.session.get('levelup_character')
if not character_name:
return redirect('level-up-character')
# Ejecutar el comando SOAP
command = f".char level {character_name} 80"
response = execute_soap_command(command)
if response is None or response.strip() == "":
message = f"El personaje {character_name} ha sido subido al nivel 80."
else:
message = f"Error: {response}"
# Limpiar la sesión
request.session.pop('levelup_character', None)
return render(request, 'account/level_up_success.html', {'message': message})
def level_up_cancel_view(request):
return render(request, 'account/level_up_cancel.html')
def gold_character_view(request):
username = request.session.get('username')
if not username:
return redirect('login')
# Obtener personajes y estado de conexión del usuario
try:
with connections['acore_auth'].cursor() as cursor:
cursor.execute("""
SELECT id, email, last_ip FROM account WHERE username = %s
""", [username])
account_info = cursor.fetchone()
if not account_info:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Error: Cuenta no encontrada.</span>'})
account_id, email, acore_ip = account_info
client_ip = request.META.get('REMOTE_ADDR', '')
# Obtener personajes del usuario desde la base de datos `acore_characters`
with connections['acore_characters'].cursor() as cursor:
cursor.execute("""
SELECT name, online, money FROM characters WHERE account = %s
""", [account_id])
characters_data = cursor.fetchall()
characters = {row[0]: {'online': row[1], 'money': row[2]} for row in characters_data}
except Exception as e:
return JsonResponse({'success': False, 'message': f'<span class="red-form-response">Error al obtener los personajes: {str(e)}</span>'})
# Obtener precios del oro
gold_prices = GoldPrice.objects.all().order_by('gold_amount')
if request.method == 'POST':
character_name = request.POST.get('character')
gold_amount = request.POST.get('gold_amount')
# Validaciones iniciales
if not character_name or not gold_amount:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Seleccione un personaje y una cantidad de oro.</span>'})
if character_name not in characters:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">No tienes permiso para enviar oro a este personaje.</span>'})
if characters[character_name]['online'] == 1:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">El personaje debe estar desconectado para recibir oro.</span>'})
try:
gold_amount = int(gold_amount)
except ValueError:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Cantidad de oro no válida.</span>'})
gold_price = GoldPrice.objects.filter(gold_amount=gold_amount).first()
if not gold_price:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Cantidad de oro no válida.</span>'})
# El precio va en euros (con decimales); el helper lo pasa a céntimos (×100)
stripe_price = gold_price.price
# Crear sesión de pago con Stripe
success_url = request.build_absolute_uri(reverse('gold-success'))
cancel_url = request.build_absolute_uri(reverse('gold-cancel'))
# Llamada corregida a create_checkout_session con todos los parámetros requeridos
stripe_response = create_checkout_session(
account_id=account_id,
username=username,
email=email,
acore_ip=acore_ip,
amount=stripe_price, # El precio calculado
character_name=character_name,
success_url=success_url,
cancel_url=cancel_url,
product_name=f"Aumentar el Oro: {gold_amount} al Personaje: {character_name}"
)
if stripe_response["success"]:
# Guardar en sesión los datos para el callback tras el pago
request.session['gold_transaction'] = {
'character_name': character_name,
'gold_amount': gold_amount
}
return JsonResponse({
'success': True,
'session_id': stripe_response["session_id"],
'stripe_public_key': settings.STRIPE_PUBLIC_KEY
})
else:
return JsonResponse({'success': False, 'message': f'<span class="red-form-response">Error al iniciar el pago: {stripe_response["error"]}</span>'})
return render(request, 'account/gold_character.html', {
'characters': characters,
'gold_prices': gold_prices,
'character_names': list(characters.keys()),
'gold_options': [{'gold_amount': p.gold_amount, 'price': str(p.price)} for p in gold_prices],
})
@require_paid_stripe()
def gold_success_view(request):
# Procesar el pago exitoso
transaction = request.session.pop('gold_transaction', None)
if not transaction:
return redirect('gold-character')
character_name = transaction['character_name']
gold_amount = int(transaction['gold_amount'])
# Calcular el oro en formato del juego
game_gold_amount = gold_amount * 10000
# Actualizar la cantidad de oro en la base de datos
with connections['acore_characters'].cursor() as cursor:
cursor.execute("""
UPDATE characters
SET money = money + %s
WHERE name = %s
""", [game_gold_amount, character_name])
return render(request, 'account/gold_success.html', {'character_name': character_name, 'gold_amount': gold_amount})
def gold_cancel_view(request):
return render(request, 'account/gold_cancel.html')
def transfer_character_view(request):
username = request.session.get('username')
if not username:
return redirect('login')
# Obtener el precio de transferencia
price_obj = TransferPrice.objects.first()
price = price_obj.price if price_obj else 10.00
# Obtener el ID de usuario desde acore_auth.account
with connections['acore_auth'].cursor() as cursor:
cursor.execute("SELECT id, email, last_ip FROM account WHERE username = %s", [username])
user_data = cursor.fetchone()
if not user_data:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Cuenta no encontrada. Por favor, inicie sesión nuevamente.</span>'})
user_id, email, acore_ip = user_data # ID de la cuenta, email y la última IP
# Obtener personajes de la cuenta de origen
with connections['acore_characters'].cursor() as cursor:
cursor.execute("""
SELECT name, class, online
FROM characters
WHERE account = %s
""", [user_id])
characters = cursor.fetchall()
if request.method == 'POST':
character_name = request.POST.get('character')
destination_account = request.POST.get('destination_account')
token = request.POST.get('security_token')
# Validaciones
if not all([character_name, destination_account, token]):
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Por favor, complete todos los campos.</span>'})
character = next((char for char in characters if char[0] == character_name), None)
if not character:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">No tienes permiso para transferir este personaje.</span>'})
# Verificar si el personaje está desconectado
if character[2] == 1: # Si está conectado
return JsonResponse({'success': False, 'message': '<span class="red-form-response">El personaje debe estar desconectado para ser transferido.</span>'})
# Verificar el token de seguridad
security_token = SecurityToken.objects.filter(user_id=user_id, token=token).first()
if not security_token:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Token de seguridad incorrecto.</span>'})
# Verificar si el token ha expirado
if security_token.expires_at < timezone.now():
return JsonResponse({'success': False, 'message': '<span class="red-form-response">El token ha expirado. Solicite uno nuevo.</span>'})
# Verificar si la cuenta de destino existe
with connections['acore_auth'].cursor() as cursor:
cursor.execute("SELECT id FROM account WHERE username = %s", [destination_account])
destination_account_data = cursor.fetchone()
if not destination_account_data:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">La cuenta de destino no existe.</span>'})
# Verificar restricciones en la cuenta de destino
destination_account_id = destination_account_data[0]
with connections['acore_characters'].cursor() as cursor:
cursor.execute("""
SELECT account, name, class, level, online
FROM characters
WHERE account = %s
""", [destination_account_id])
destination_characters = cursor.fetchall()
if not any(char[3] >= 55 and char[2] != 6 for char in destination_characters):
return JsonResponse({'success': False, 'message': '<span class="red-form-response">La cuenta destino debe tener al menos un personaje de nivel 55 o superior que no sea Caballero de la Muerte.</span>'})
if any(char[2] == 6 for char in destination_characters):
return JsonResponse({'success': False, 'message': '<span class="red-form-response">La cuenta destino no puede tener un Caballero de la Muerte.</span>'})
# Verificar que ninguna cuenta esté online
for char in destination_characters:
if char[4] == 1:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Todos los personajes de la cuenta destino deben estar desconectados.</span>'})
for char in characters:
if char[2] == 1:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Todos los personajes de la cuenta origen deben estar desconectados.</span>'})
# Crear sesión de pago con Stripe
success_url = request.build_absolute_uri(reverse('transfer-success'))
cancel_url = request.build_absolute_uri(reverse('transfer-cancel'))
# Llamada corregida a create_checkout_session con todos los parámetros requeridos
stripe_response = create_checkout_session(
username=username,
email=email,
acore_ip=acore_ip,
account_id=user_id, # Pasar el account_id
amount=price, # El precio de la transferencia
character_name=character_name,
success_url=success_url,
cancel_url=cancel_url,
product_name=f"Transferir el personaje: {character_name} a la cuenta de destino: {destination_account}"
)
if stripe_response["success"]:
# Guardar los datos de la transferencia en la sesión para usarlos después del pago
request.session['transfer_data'] = {
'character_name': character_name,
'destination_account': destination_account
}
return JsonResponse({
'success': True,
'session_id': stripe_response["session_id"],
'stripe_public_key': settings.STRIPE_PUBLIC_KEY
})
else:
return JsonResponse({'success': False, 'message': f'<span class="red-form-response">Error al iniciar el pago: {stripe_response["error"]}</span>'})
return render(request, 'account/transfer_character.html', {
'characters': characters,
'price': price,
'character_names': [c[0] for c in characters],
})
@require_paid_stripe()
def transfer_success_view(request):
transfer_data = request.session.get('transfer_data')
if not transfer_data:
return redirect('transfer-character')
character_name = transfer_data['character_name']
destination_account = transfer_data['destination_account']
# Ejecutar comando SOAP
command = f".char changeaccount {destination_account} {character_name}"
response = execute_soap_command(command)
if response is None or response.strip() == "":
message = f"El personaje {character_name} ha sido transferido a la cuenta {destination_account}."
request.session.pop('transfer_data', None) # Limpiar sesión
return render(request, 'account/transfer_success.html', {'message': message})
else:
return render(request, 'account/transfer_success.html', {'message': f"Error: {response}"})
def transfer_cancel_view(request):
return render(request, 'account/transfer_cancel.html')
def revive_character_view(request):
username = request.session.get('username')
if not username:
return redirect('login')
# Obtener personajes del usuario desde la base de datos `acore_characters`
with connections['acore_characters'].cursor() as cursor:
cursor.execute("""
SELECT name, online
FROM characters
WHERE account = (
SELECT id
FROM acore_auth.account
WHERE username = %s
)
""", [username])
characters_data = cursor.fetchall()
characters = {row[0]: row[1] for row in characters_data} # Diccionario con nombre y estado de conexión
if request.method == 'POST':
character_name = request.POST.get('character')
# Validar si el personaje fue seleccionado
if not character_name:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Por favor, seleccione un personaje.</span>'})
# Verificar si el personaje pertenece al usuario
if character_name not in characters:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">No tienes permiso para revivir este personaje.</span>'})
# Verificar si el personaje está desconectado
if characters[character_name] == 1: # Si está conectado
return JsonResponse({'success': False, 'message': '<span class="red-form-response">El personaje debe estar desconectado para ser revivido.</span>'})
# Verificar el historial de uso del comando `revive`
last_revive = ReviveHistory.objects.filter(character_name=character_name).order_by('-used_at').first()
if last_revive and last_revive.used_at > now() - timedelta(hours=12):
return JsonResponse({'success': False, 'message': '<span class="red-form-response">El personaje solo puede revivirse una vez cada 12 horas.</span>'})
# Ejecutar el comando SOAP
command = f".revive {character_name}"
response = execute_soap_command(command)
# None = fallo de comunicación con el servidor
if response is None:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Error de comunicación con el servidor. Intente nuevamente más tarde.</span>'})
# Respuesta vacía = éxito (el comando .revive no devuelve texto si va bien)
if response.strip() == "":
ReviveHistory.objects.create(character_name=character_name, used_at=now())
return JsonResponse({'success': True, 'message': f'<span class="ok-form-response">El personaje {character_name} ha sido revivido con éxito.</span>'})
# Respuesta no vacía = el servidor devolvió un mensaje/error
return JsonResponse({'success': False, 'message': f'<span class="red-form-response">{response}</span>'})
return render(request, 'account/revive_character.html', {'characters': characters.keys()})
def unstuck_character_view(request):
username = request.session.get('username')
if not username:
return redirect('login')
# Obtener personajes del usuario desde la base de datos `acore_characters`
with connections['acore_characters'].cursor() as cursor:
cursor.execute("""
SELECT name, online
FROM characters
WHERE account = (
SELECT id
FROM acore_auth.account
WHERE username = %s
)
""", [username])
characters_data = cursor.fetchall()
characters = {row[0]: row[1] for row in characters_data} # Diccionario con nombre y estado de conexión
if request.method == 'POST':
character_name = request.POST.get('character')
# Validar si el personaje fue seleccionado
if not character_name:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Por favor, seleccione un personaje.</span>'})
# Verificar si el personaje pertenece al usuario
if character_name not in characters:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">No tienes permiso para desbloquear este personaje.</span>'})
# Verificar si el personaje está desconectado
if characters[character_name] == 1: # Si está conectado
return JsonResponse({'success': False, 'message': '<span class="red-form-response">El personaje debe estar desconectado para ser desbloqueado.</span>'})
# Verificar el historial de uso del comando
last_unstuck = UnstuckHistory.objects.filter(character_name=character_name).order_by('-used_at').first()
if last_unstuck and last_unstuck.used_at > now() - timedelta(hours=12):
return JsonResponse({'success': False, 'message': '<span class="red-form-response">El personaje solo puede desbloquearse una vez cada 12 horas.</span>'})
# Ejecutar el comando SOAP
command = f".unstuck {character_name} startzone"
response = execute_soap_command(command)
if response is None:
return JsonResponse({'success': False, 'message': '<span class="red-form-response">Error de comunicación con el servidor. Intente nuevamente más tarde.</span>'})
# Analizar la respuesta
if f"You are summoning {character_name} (offline)" in response:
# Registrar el uso del comando
UnstuckHistory.objects.create(character_name=character_name, used_at=now())
return JsonResponse({'success': True, 'message': f'<span class="ok-form-response">El personaje {character_name} ha sido desbloqueado con éxito.</span>'})
else:
return JsonResponse({'success': False, 'message': f'<span class="red-form-response">Error: {response}</span>'})
return render(request, 'account/unstuck_character.html', {'characters': characters.keys()})