diff --git a/home/models.py b/home/models.py index e3666f3..a4a6400 100644 --- a/home/models.py +++ b/home/models.py @@ -282,6 +282,7 @@ class LoginAttempt(models.Model): return f"{self.username} - {self.status} - {self.timestamp}" + class StripeLog(models.Model): account_id = models.IntegerField() # ID de la cuenta en acore_auth username = models.CharField(max_length=100) # Nombre de la cuenta diff --git a/home/templates/partials/ban_history.html b/home/templates/partials/ban_history.html index 2aa5006..7fc56e2 100644 --- a/home/templates/partials/ban_history.html +++ b/home/templates/partials/ban_history.html @@ -1,45 +1,95 @@
-
-
-

Historial de sanciones

-
- -
-
-

Aquí podrás ver todas las sanciones que ha tenido la cuenta.

-

Si tienes una sanción vigente, verás que su estado indica Activo.

-

Para evitar que tu cuenta sea sancionada, recuerda respetar las normas de nuestro servidor.

-
-
-

Importante:

-

Si tu cuenta aparece como sancionada o cerrada al intentar ingresar al reino, pero tu historial no tiene ninguna sanción activa, significa que has tenido un bloqueo automático temporal por demasiados intentos de inicio de sesión fallidos.

-

Espera al menos 10 minutos para volver a intentar y asegúrate de usar nombre de cuenta y contraseña correctas.

-
-
-

Para realizar un reclamo de sanción, por favor ingresa en nuestro foro y visita la sección Reclamaciones.

-
-
- -
-

Historial de baneos

-
- - - - -
No hay baneos
-
-
-
-

Historial de muteos

-
- - - - -
No hay muteos
-
-
+
+
+
+

Historial de sanciones

+
+
+
+

Información

+ + +
+
+
+

Aquí podrás ver todas las sanciones que ha tenido la cuenta.

+

Si tienes una sanción vigente, verás que su estado indica Activo.

+

Para evitar que tu cuenta sea sancionada, recuerda respetar las normas de nuestro servidor.

+
-
\ No newline at end of file + + +
+
+

Historial de baneos

+
+
+ + + + + + + + + + + + {% if account_bans %} + {% for ban in account_bans %} + + + + + + + + {% endfor %} + {% else %} + + + + {% endif %} + + {% if character_bans %} + {% for ban in character_bans %} + + + + + + + + {% endfor %} + {% else %} + + + + {% endif %} + +
Fecha de BaneoFecha de DesbaneoMotivoEstado + {% if account_bans and character_bans %} + Cuenta / Personaje + {% elif account_bans %} + Cuenta + {% elif character_bans %} + Personaje + {% else %} + Fuente + {% endif %} +
{{ ban.0|default:"No disponible" }}{{ ban.1|default:"No disponible" }}{{ ban.2 }} + {% if ban.3 == 1 %} + Activo + {% else %} + Inactivo + {% endif %} + Cuenta: {{ ban.4 }}
No hay baneos en la cuenta.
{{ ban.0|default:"No disponible" }}{{ ban.1|default:"No disponible" }}{{ ban.2 }} + {% if ban.3 == 1 %} + Activo + {% else %} + Inactivo + {% endif %} + Personaje: {{ ban.4 }}
No hay baneos en los personajes.
+
+
\ No newline at end of file diff --git a/home/templates/partials/restore_character.html b/home/templates/partials/restore_character.html index 5affd51..3344305 100644 --- a/home/templates/partials/restore_character.html +++ b/home/templates/partials/restore_character.html @@ -1,36 +1,53 @@
-
-
-

Recuperar personaje

-
- -
-
-

La herramienta Recuperar personaje te permite restaurar un personaje que haya sido borrado.

-
-

Sólo disponible para personajes que cumplan las siguientes dos condiciones:

-

- Nivel superior a 60.

-

- Borrado en un período menor a 30 días.

-

Para personajes Caballeros de la Muerte:

-

- No es posible recuperar un personaje Caballero de la Muerte si ya hay otro activo en la cuenta.

-
-

Cuando ingreses a la lista de personajes de tu cuenta, verás al personaje recuperado.

-
-
- NOTA -
-

Personajes borrados que no cumplan dichas condiciones ya no son recuperables.

-

Se puede repetir la acción en un mismo personaje cada 12 horas.

-
-
-
-
-
- No hay personajes -
-
+
+
+

Recuperar personaje

+
+
+

Información

+ + +
+
+
+

La herramienta Recuperar personaje te permite restaurar un personaje que haya sido borrado.

+
+

Sólo disponible para personajes que cumplan las siguientes dos condiciones:

+

- Nivel superior a 60.

+

- Borrado en un período menor a 30 días.

+

Para personajes Caballeros de la Muerte:

+

- No es posible recuperar un personaje Caballero de la Muerte si ya hay otro activo en la cuenta.

+
+

Cuando ingreses a la lista de personajes de tu cuenta, verás al personaje recuperado.

+
+
+ NOTA +
+

Personajes borrados que no cumplan dichas condiciones ya no son recuperables.

+

Se puede repetir la acción en un mismo personaje cada 12 horas.

-
+ +
+

+ {% if message %} +

{{ message }}

+ {% endif %} + {% if character_list %} +
+ {% csrf_token %} + + +
+ {% else %} + No hay personajes eliminados disponibles para restaurar. + {% endif %} +
-
\ No newline at end of file +
+
+
diff --git a/home/templates/partials/restore_items.html b/home/templates/partials/restore_items.html index d17b76b..479d686 100644 --- a/home/templates/partials/restore_items.html +++ b/home/templates/partials/restore_items.html @@ -1,45 +1,53 @@
-
- diff --git a/home/views.py b/home/views.py index d8d088d..0f46786 100644 --- a/home/views.py +++ b/home/views.py @@ -199,19 +199,19 @@ def login_view(request): password = form.cleaned_data['password'] ip_address = request.META.get('REMOTE_ADDR') # Obtener la IP del cliente - # Llamar a la funcin de autenticacin + # Llamar a la función de autenticación if authenticate(username, password): # Guardar el intento exitoso log_login_attempt(username, "Exito", ip_address) - # Guardar el nombre de usuario en maysculas en la sesin + # Guardar el nombre de usuario en mayúsculas en la sesión request.session['username'] = username.upper() return JsonResponse({'success': True}) else: # Guardar el intento fallido log_login_attempt(username, "Fracaso", ip_address) - return JsonResponse({'success': False, 'error': "Usuario o contrase?a incorrectos"}) + return JsonResponse({'success': False, 'error': "Usuario o contraseña incorrectos"}) else: return JsonResponse({'success': False, 'error': "Formulario no valido"}) @@ -675,7 +675,6 @@ def my_account(request): }) - def get_account_status(account_id): with connections['acore_auth'].cursor() as cursor: # Obtener información de la tabla 'account' @@ -737,7 +736,7 @@ def get_account_status(account_id): unban_timestamp, current_timestamp = ban_data remaining_time = unban_timestamp - current_timestamp user_info['is_banned'] = True - user_info['unban_date'] = datetime.datetime.fromtimestamp(unban_timestamp).strftime("%A %d de %B del %Y a las %H:%M:%S Horas") + user_info['unban_date'] = datetime.fromtimestamp(unban_timestamp).strftime("%A %d de %B del %Y a las %H:%M:%S Horas") user_info['remaining_time'] = remaining_time else: user_info['is_banned'] = False @@ -1259,17 +1258,173 @@ def rename_cancel_view(request): return redirect('login') return render(request, 'account/rename_cancel.html') +@csrf_exempt 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') - return render(request, 'account/restore_character.html') + 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: + messages.error(request, "No se seleccionó un personaje para restaurar.") + return redirect('restore-character') + + # Aquí es donde usamos SOAP en lugar de la actualización directa + try: + command = f".char del restore {guid}" # Comando SOAP para restaurar el personaje + response = execute_soap_command(command) # Ejecuta el comando SOAP + + # Si la respuesta es exitosa, informamos al usuario + if response == "success": + messages.success(request, "Personaje restaurado exitosamente.") + return redirect('my-account') # Redirigir a la cuenta del usuario + else: + messages.error(request, "Hubo un error al restaurar el personaje.") + return redirect('restore-character') + + except Exception as e: + messages.error(request, f"Hubo un error al intentar restaurar el personaje: {str(e)}") + return redirect('restore-character') + + # 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 + }) + +@csrf_exempt def restore_items_view(request): username = request.session.get('username') if not username: return redirect('login') - return render(request, 'account/restore_items.html') + + 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)}") + + 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: + messages.error(request, f"Error al obtener los ítems eliminados: {str(e)}") + + 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: + 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) + + if "success" in response.lower(): + messages.success(request, "Ítem restaurado exitosamente.") + else: + messages.error(request, "No se pudo restaurar el ítem.") + except Exception as e: + messages.error(request, f"Error al restaurar el ítem: {str(e)}") + + return redirect('restore-items') + + return render(request, 'account/restore_items.html', { + 'characters': characters, + 'deleted_items': deleted_items, + 'selected_character': selected_character + }) + def quest_character_view(request): username = request.session.get('username') @@ -1288,7 +1443,7 @@ def customize_character_view(request): if not username: return redirect('login') - # ?? Obtener informaci��n de la cuenta desde acore_auth + # ?? 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 @@ -2318,13 +2473,20 @@ def d_points_view(request): def points_history_view(request): return render(request, 'account/points_history.html') - + + + +def format_datetime(timestamp): + if timestamp: + return datetime.utcfromtimestamp(timestamp).strftime('%d-%m-%Y %H:%M:%S') + return "No disponible" + def trans_history_view(request): """ Vista para mostrar el historial de transacciones de la cuenta y sus personajes. """ - username = request.session.get('username') # Obtener el nombre de usuario de la sesin + username = request.session.get('username') # Obtener el nombre de usuario de la sesión if username: # Filtramos las transacciones que corresponden al usuario y a los personajes asociados @@ -2335,22 +2497,90 @@ def trans_history_view(request): # Renderizamos la vista con el historial de transacciones return render(request, 'account/trans_history.html', {'transactions': transactions}) - -def ban_history_view(request): - return render(request, 'account/ban_history.html') +def get_account_id(username): + # Consulta para obtener el account_id a partir del username + with connections['acore_auth'].cursor() as cursor: + cursor.execute(""" + SELECT id + FROM account + WHERE username = %s + """, [username]) + result = cursor.fetchone() + return result[0] if result else None + + +def get_ban_history(account_id): + # Consulta de baneos de la cuenta + with connections['acore_auth'].cursor() as cursor: + cursor.execute(""" + SELECT bandate, unbandate, banreason, active, account.username + FROM account_banned + JOIN account ON account_banned.id = account.id + WHERE account_banned.id = %s + """, [account_id]) + account_bans = cursor.fetchall() + + # Formatear las fechas + account_bans = [(format_datetime(ban[0]), format_datetime(ban[1]), ban[2], ban[3], ban[4]) for ban in account_bans] + + # Consulta de baneos de los personajes asociados a la cuenta + with connections['acore_characters'].cursor() as cursor: + cursor.execute(""" + SELECT bandate, unbandate, banreason, active, characters.name + FROM character_banned + JOIN characters ON character_banned.guid = characters.guid + WHERE characters.account = %s + """, [account_id]) + character_bans = cursor.fetchall() + + # Formatear las fechas + character_bans = [(format_datetime(ban[0]), format_datetime(ban[1]), ban[2], ban[3], ban[4]) for ban in character_bans] + + return account_bans, character_bans + + +def calculate_unmute_date(mute_date, mute_duration): + if isinstance(mute_date, int): + mute_date = datetime.fromtimestamp(mute_date) + return mute_date + timedelta(seconds=mute_duration) + + + +def ban_history_view(request): + # Verificar si el usuario tiene un `username` en la sesión + username = request.session.get('username') + if not username: + return redirect('login') + + # Obtener el account_id a partir del username + account_id = get_account_id(username) + if not account_id: + return redirect('login') # O redirigir a otra página si no se encuentra el account_id + + print(f"Account ID: {account_id}") # Depurar el account_id + + account_bans, character_bans = get_ban_history(account_id) + + return render(request, 'account/ban_history.html', { + 'account_bans': account_bans, + 'character_bans': character_bans, + 'now': datetime.now(), + }) + + def security_history_view(request): username = request.session.get('username') if not username: - return redirect('login') # Si no est autenticado, redirigir al login + return redirect('login') # Si no está autenticado, redirigir al login - # Obtener los ltimos 20 intentos de inicio de sesin + # Obtener los últimos 20 intentos de inicio de sesión login_attempts = LoginAttempt.objects.filter(username=username).order_by('-timestamp')[:20] return render(request, 'account/security_history.html', {'login_attempts': login_attempts}) def log_login_attempt(username, status, ip_address): - # Registrar intento de inicio de sesin en el historial + # Registrar intento de inicio de sesión en el historial LoginAttempt.objects.create( username=username, status=status,