diff --git a/home/__pycache__/models.cpython-313.pyc b/home/__pycache__/models.cpython-313.pyc
index 37632d7..5b1bf2b 100644
Binary files a/home/__pycache__/models.cpython-313.pyc and b/home/__pycache__/models.cpython-313.pyc differ
diff --git a/home/__pycache__/urls.cpython-313.pyc b/home/__pycache__/urls.cpython-313.pyc
index bd4ad0c..a07f2f1 100644
Binary files a/home/__pycache__/urls.cpython-313.pyc and b/home/__pycache__/urls.cpython-313.pyc differ
diff --git a/home/__pycache__/views.cpython-313.pyc b/home/__pycache__/views.cpython-313.pyc
index ab5a134..449bca5 100644
Binary files a/home/__pycache__/views.cpython-313.pyc and b/home/__pycache__/views.cpython-313.pyc differ
diff --git a/home/models.py b/home/models.py
index 1ed077f..f986ee9 100644
--- a/home/models.py
+++ b/home/models.py
@@ -16,6 +16,10 @@ class Noticia(models.Model):
def __str__(self):
return self.titulo
+
+class UnstuckHistory(models.Model):
+ character_name = models.CharField(max_length=50)
+ used_at = models.DateTimeField()
class ClienteCategoria(models.Model):
diff --git a/home/static/nw-themes/nw-ryu/nw-js-handlers/change_email_response.js b/home/static/nw-themes/nw-ryu/nw-js-handlers/change_email_response.js
index cc0b6bb..ffed7b2 100644
--- a/home/static/nw-themes/nw-ryu/nw-js-handlers/change_email_response.js
+++ b/home/static/nw-themes/nw-ryu/nw-js-handlers/change_email_response.js
@@ -1,34 +1,45 @@
$(document).ready(function() {
- $('#nw-change-email-form').on('submit', function(e) {
- e.preventDefault(); // Evitar el envío por defecto del formulario
+ function handleResponse(response, button, originalText) {
+ $("#change-email-response").html(response.message).hide().slideDown();
+
+ if (response.redirect_url) {
+ setTimeout(function() {
+ window.location.href = response.redirect_url;
+ }, 2000);
+ return;
+ }
+
+ if (response.success) {
+ button.html("Proceso completado");
+ } else {
+ setTimeout(function() {
+ $("#change-email-response").slideUp(function() {
+ $("#change-email-response").empty();
+ button.html(originalText);
+ button.prop("disabled", false);
+ });
+ }, 5000);
+ }
+ }
+
+ // Manejar los enlaces de confirmación
+ $('.confirm-link').on('click', function(e) {
+ e.preventDefault();
$("#change-email-response").empty();
- var form = $(this);
- var button = $('.change-email-button');
+ var button = $(this);
+ var url = button.attr('href');
var originalText = button.html();
- button.html("Cambiando correo...");
+ button.html("Verificando...");
button.prop("disabled", true);
$.ajax({
- type: 'POST',
- url: form.attr('action'),
- data: form.serialize(), // Serializar los datos correctamente
+ type: 'GET',
+ url: url,
dataType: 'json',
success: function(response) {
- $("#change-email-response").html(response.message).hide().slideDown();
-
- if (response.success) {
- button.html("Correo cambiado");
- } else {
- setTimeout(function() {
- $("#change-email-response").slideUp(function() {
- $("#change-email-response").empty();
- button.html(originalText);
- button.prop("disabled", false);
- });
- }, 5000);
- }
+ handleResponse(response, button, originalText);
},
error: function(xhr, status, error) {
console.error("Error:", error);
diff --git a/home/static/nw-themes/nw-ryu/nw-js-handlers/unstuck_response.js b/home/static/nw-themes/nw-ryu/nw-js-handlers/unstuck_response.js
new file mode 100644
index 0000000..ab7bb27
--- /dev/null
+++ b/home/static/nw-themes/nw-ryu/nw-js-handlers/unstuck_response.js
@@ -0,0 +1,41 @@
+$(function() {
+ $('.unstuck-button').on('click', function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ $("#unstuck-response").empty();
+
+ var button = $(this);
+ var originalText = button.html();
+ var data = $("#uw-unstuck-form").serialize();
+
+ button.html("Desbloqueando...");
+ button.prop("disabled", true);
+
+ $.ajax({
+ type: 'POST',
+ url: '',
+ data: data,
+ dataType: 'json',
+ success: function(data) {
+ $("#unstuck-response").html(data.message).hide().slideDown();
+
+ if (data.success) {
+ button.html("Desbloqueado");
+ setTimeout(function() {
+ $("#uw-unstuck-form")[0].reset();
+ button.html(originalText);
+ button.prop("disabled", false);
+ }, 5000);
+ } else {
+ button.html(originalText);
+ button.prop("disabled", false);
+ }
+ },
+ error: function() {
+ $("#unstuck-response").html('Algo ha salido mal. Inténtelo más tarde.');
+ button.html(originalText);
+ button.prop("disabled", false);
+ }
+ });
+ });
+});
diff --git a/home/templates/account/confirm_new_email_success.html b/home/templates/account/confirm_new_email_success.html
new file mode 100644
index 0000000..40745ea
--- /dev/null
+++ b/home/templates/account/confirm_new_email_success.html
@@ -0,0 +1,9 @@
+
+
+ {% include 'partials/head.html' %}
+ {% include 'partials/header.html' %}
+ {% include 'partials/video.html' %}
+ {% include 'partials/confirm_new_email_success.html' %}
+ {% include 'partials/social.html' %}
+ {% include 'partials/footer.html' %}
+ {% include 'partials/final.html' %}
\ No newline at end of file
diff --git a/home/templates/account/confirm_old_email_success.html b/home/templates/account/confirm_old_email_success.html
new file mode 100644
index 0000000..e507d48
--- /dev/null
+++ b/home/templates/account/confirm_old_email_success.html
@@ -0,0 +1,9 @@
+
+
+ {% include 'partials/head.html' %}
+ {% include 'partials/header.html' %}
+ {% include 'partials/video.html' %}
+ {% include 'partials/confirm_old_email_success.html' %}
+ {% include 'partials/social.html' %}
+ {% include 'partials/footer.html' %}
+ {% include 'partials/final.html' %}
\ No newline at end of file
diff --git a/home/templates/account/expired_link.html b/home/templates/account/expired_link.html
new file mode 100644
index 0000000..1e11adf
--- /dev/null
+++ b/home/templates/account/expired_link.html
@@ -0,0 +1,9 @@
+
+
+ {% include 'partials/head.html' %}
+ {% include 'partials/header.html' %}
+ {% include 'partials/video.html' %}
+ {% include 'partials/expired_link.html' %}
+ {% include 'partials/social.html' %}
+ {% include 'partials/footer.html' %}
+ {% include 'partials/final.html' %}
\ No newline at end of file
diff --git a/home/templates/account/unstuck_character.html b/home/templates/account/unstuck_character.html
new file mode 100644
index 0000000..4fa7a83
--- /dev/null
+++ b/home/templates/account/unstuck_character.html
@@ -0,0 +1,9 @@
+
+
+ {% include 'partials/head.html' %}
+ {% include 'partials/header.html' %}
+ {% include 'partials/video.html' %}
+ {% include 'partials/unstuck_character.html' %}
+ {% include 'partials/social.html' %}
+ {% include 'partials/footer.html' %}
+ {% include 'partials/final.html' %}
\ No newline at end of file
diff --git a/home/templates/partials/confirm_new_email_success.html b/home/templates/partials/confirm_new_email_success.html
new file mode 100644
index 0000000..918a284
--- /dev/null
+++ b/home/templates/partials/confirm_new_email_success.html
@@ -0,0 +1,15 @@
+
+
+
+
+ Confirmación de Nuevo Correo
+
+
+
+
+
Cambio de Correo Completado
+
El cambio de correo ha sido confirmado y completado con éxito.
+
Regresar a Mi Cuenta
+
+
+
diff --git a/home/templates/partials/confirm_old_email_success.html b/home/templates/partials/confirm_old_email_success.html
new file mode 100644
index 0000000..b96b992
--- /dev/null
+++ b/home/templates/partials/confirm_old_email_success.html
@@ -0,0 +1,15 @@
+
+
+
+
+ Confirmación de Correo Anterior
+
+
+
+
+
Confirmación de Correo Anterior Exitosa
+
Has confirmado tu correo anterior. Se ha enviado un enlace al nuevo correo para completar el cambio.
+
Regresar a Mi Cuenta
+
+
+
diff --git a/home/templates/partials/expired_link.html b/home/templates/partials/expired_link.html
new file mode 100644
index 0000000..286eab0
--- /dev/null
+++ b/home/templates/partials/expired_link.html
@@ -0,0 +1,27 @@
+
+
+
+
+
Enlace Expirado
+
+
+
+
+
diff --git a/home/templates/partials/head.html b/home/templates/partials/head.html
index 4fdc02b..576b91f 100644
--- a/home/templates/partials/head.html
+++ b/home/templates/partials/head.html
@@ -52,6 +52,7 @@
+
diff --git a/home/templates/partials/my-account.html b/home/templates/partials/my-account.html
index 65d2334..03f8752 100644
--- a/home/templates/partials/my-account.html
+++ b/home/templates/partials/my-account.html
@@ -207,6 +207,201 @@
+ {% for character in characters %}
+ OPCIONES DE PERSONAJE
+
+
+
+
+
+
HISTORIALES
diff --git a/home/templates/partials/unstuck_character.html b/home/templates/partials/unstuck_character.html
new file mode 100644
index 0000000..39ba380
--- /dev/null
+++ b/home/templates/partials/unstuck_character.html
@@ -0,0 +1,43 @@
+
+
+
+
+
Desbloquear personaje
+
+
+
+
+
La herramienta Desbloquear personaje te permite desbloquear un personaje que esté atascado y lo mueve a la ubicación de su Piedra Hogar.
+
Usa esta opción cuando tu personaje se encuentre atrapado y ninguna otra opción te sirva.
+
+
+
Escoge el personaje que quieres desbloquear
+
+
+
+
+
+
+
+
+
diff --git a/home/urls.py b/home/urls.py
index 6be487d..41f8a1f 100644
--- a/home/urls.py
+++ b/home/urls.py
@@ -26,6 +26,7 @@ urlpatterns = [
path('change-email/', views.change_email_view, name='change-email'),
path('confirm-old-email/', views.confirm_old_email_view, name='confirm-old-email'),
path('confirm-new-email/', views.confirm_new_email_view, name='confirm-new-email'),
+ path('expired-link/', views.expired_link_view, name='expired-link'),
path('promo-code/', views.promo_code_view, name='promo_code'),
path('transfer-d-points/', views.transfer_d_points_view, name='transfer_d_points'),
path('rename-guild/', views.rename_guild_view, name='rename-guild'),
@@ -39,6 +40,7 @@ urlpatterns = [
path('activate-account', views.activate_account_view, name='activate_account'),
path('help', views.help_view, name='help'),
path('novawow-players', views.novawow_players_view, name='novawow_players'),
+ path('unstuck-character/', views.unstuck_character_view, name='unstuck-character'),
]
diff --git a/home/views.py b/home/views.py
index aee4310..83187e6 100644
--- a/home/views.py
+++ b/home/views.py
@@ -5,12 +5,13 @@ import binascii
import os
import re
from django.shortcuts import render, redirect
+from django.urls import reverse
from django.http import HttpResponse, JsonResponse
from django.db import connections
from django.contrib import messages
from django.contrib.auth import logout
from django import forms
-from .models import Noticia, ClienteCategoria, ServerSelection, RecruitAFriend, DownloadClientPage, ContentCreator, RecruitReward, ClaimedReward, AccountActivation, SecurityToken, GuildRenameSettings, VoteSite, VoteLog, HomeApiPoints
+from .models import Noticia, ClienteCategoria, ServerSelection, RecruitAFriend, DownloadClientPage, ContentCreator, RecruitReward, ClaimedReward, AccountActivation, SecurityToken, GuildRenameSettings, VoteSite, VoteLog, HomeApiPoints, UnstuckHistory
from django.views.decorators.csrf import csrf_exempt
import logging
from datetime import datetime, timedelta
@@ -1001,22 +1002,22 @@ def change_email_view(request):
# Validar los campos
if not all([current_password, current_email_input, new_email, conf_new_email, token]):
- return JsonResponse({'success': False, 'message': 'Por favor, complete todos los campos.'})
+ return JsonResponse({'success': False, 'message': 'Por favor, complete todos los campos.'})
if current_email_input != current_email:
- return JsonResponse({'success': False, 'message': 'El correo actual no es correcto.'})
+ return JsonResponse({'success': False, 'message': 'El correo actual no es correcto.'})
if new_email != conf_new_email:
- return JsonResponse({'success': False, 'message': 'Los correos no coinciden.'})
+ return JsonResponse({'success': False, 'message': 'Los correos no coinciden.'})
if not re.match(r'^[a-zA-Z0-9._%+-]+@gmail\.com$', new_email):
- return JsonResponse({'success': False, 'message': 'El nuevo correo no es válido.'})
+ return JsonResponse({'success': False, 'message': 'El nuevo correo no es válido.'})
if not security_token or security_token.token != token:
- return JsonResponse({'success': False, 'message': 'Token de seguridad incorrecto.'})
+ return JsonResponse({'success': False, 'message': 'Token de seguridad incorrecto.'})
if not authenticate(username, current_password):
- return JsonResponse({'success': False, 'message': 'Contraseña incorrecta.'})
+ return JsonResponse({'success': False, 'message': 'Contraseña incorrecta.'})
# Generar hashes
old_email_hash = secrets.token_urlsafe(16)
@@ -1049,7 +1050,7 @@ def change_email_view(request):
context=context_old_email
)
- return JsonResponse({'success': True, 'message': 'Se ha enviado un correo de confirmación al correo actual.'})
+ return JsonResponse({'success': True, 'message': 'Se ha enviado un correo de confirmación al correo actual.'})
return render(request, 'account/change_email.html')
@@ -1059,7 +1060,11 @@ def confirm_old_email_view(request):
activation = AccountActivation.objects.filter(old_email_hash=hash, is_used=False).first()
if not activation or activation.is_expired():
- return HttpResponse('Enlace no válido o expirado.', status=400)
+ return JsonResponse({
+ 'success': False,
+ 'message': 'Enlace no válido o expirado.',
+ 'redirect_url': reverse('expired-link')
+ })
# Marcar solo el old_email_hash como usado
activation.is_used = True
@@ -1079,15 +1084,18 @@ def confirm_old_email_view(request):
context=context_new_email
)
- return HttpResponse('Correo confirmado. Se ha enviado un enlace al nuevo correo.')
-
+ return JsonResponse({'success': True, 'message': 'Correo confirmado. Se ha enviado un enlace al nuevo correo.'})
def confirm_new_email_view(request):
hash = request.GET.get('hash')
activation = AccountActivation.objects.filter(hash=hash, is_new_email_used=False).first()
if not activation or activation.is_expired():
- return HttpResponse('Enlace no válido o expirado.', status=400)
+ return JsonResponse({
+ 'success': False,
+ 'message': 'Enlace no válido o expirado.',
+ 'redirect_url': reverse('expired-link')
+ })
# Marcar solo el new_email_hash como usado
activation.is_new_email_used = True
@@ -1114,11 +1122,72 @@ def confirm_new_email_view(request):
context=context_old_email
)
- return HttpResponse('El cambio de correo ha sido confirmado y completado con éxito.')
+ return JsonResponse({'success': True, 'message': 'El cambio de correo ha sido confirmado y completado con éxito.'})
+
+def expired_link_view(request):
+ return render(request, 'account/expired_link.html')
-
def promo_code_view(request):
return render(request, 'account/promo_code.html')
+
+from django.utils.timezone import now
+from datetime import timedelta
+
+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': 'Por favor, seleccione un personaje.'})
+
+ # Verificar si el personaje pertenece al usuario
+ if character_name not in characters:
+ return JsonResponse({'success': False, 'message': 'No tienes permiso para desbloquear este personaje.'})
+
+ # Verificar si el personaje está desconectado
+ if characters[character_name] == 1: # Si está conectado
+ return JsonResponse({'success': False, 'message': 'El personaje debe estar desconectado para ser desbloqueado.'})
+
+ # 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': 'El personaje solo puede desbloquearse una vez cada 12 horas.'})
+
+ # Ejecutar el comando SOAP
+ command = f".unstuck {character_name} startzone"
+ response = execute_soap_command(command)
+
+ if response is None:
+ return JsonResponse({'success': False, 'message': 'Error de comunicación con el servidor. Intente nuevamente más tarde.'})
+
+ # 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'El personaje {character_name} ha sido desbloqueado con éxito.'})
+ else:
+ return JsonResponse({'success': False, 'message': f'Error: {response}'})
+
+ return render(request, 'account/unstuck_character.html', {'characters': characters.keys()})
def transfer_d_points_view(request):
# Renderizar la plantilla para la transferencia de puntos
diff --git a/novawow/__pycache__/settings.cpython-313.pyc b/novawow/__pycache__/settings.cpython-313.pyc
index 93e06ad..b334c19 100644
Binary files a/novawow/__pycache__/settings.cpython-313.pyc and b/novawow/__pycache__/settings.cpython-313.pyc differ
diff --git a/novawow/__pycache__/urls.cpython-313.pyc b/novawow/__pycache__/urls.cpython-313.pyc
index 14d4b53..41612c3 100644
Binary files a/novawow/__pycache__/urls.cpython-313.pyc and b/novawow/__pycache__/urls.cpython-313.pyc differ
diff --git a/novawow/settings.py b/novawow/settings.py
index 29a3463..7c47601 100644
--- a/novawow/settings.py
+++ b/novawow/settings.py
@@ -27,7 +27,6 @@ DEBUG = True
ALLOWED_HOSTS = ['*']
-
# Application definition
INSTALLED_APPS = [