From c3c424277be1ec4a2cc3b3a8dc52302cf1b6f2e5 Mon Sep 17 00:00:00 2001 From: adevopg <133045315+adevopg@users.noreply.github.com> Date: Mon, 18 Nov 2024 09:07:52 +0100 Subject: [PATCH] Arreglado VotePoints, y Implementado el Cambio de Correo --- home/__pycache__/admin.cpython-313.pyc | Bin 8718 -> 9117 bytes home/__pycache__/models.cpython-313.pyc | Bin 10560 -> 13372 bytes home/__pycache__/tasks.cpython-313.pyc | Bin 0 -> 1371 bytes home/__pycache__/urls.cpython-313.pyc | Bin 4054 -> 4310 bytes home/__pycache__/views.cpython-313.pyc | Bin 53516 -> 62430 bytes home/admin.py | 12 +- home/models.py | 43 +++- .../nw-js-handlers/change_email_response.js | 78 ++---- .../nw-js-handlers/vote_points_response.js | 75 ++++++ home/templates/emails/confirm_new_email.html | 28 +++ home/templates/emails/confirm_old_email.html | 28 +++ .../emails/old_email_notification.html | 27 ++ home/templates/partials/change_email.html | 40 ++- home/templates/partials/head.html | 1 + home/templates/partials/my-account.html | 14 +- home/templates/partials/vote_points.html | 142 ++--------- home/urls.py | 4 +- home/views.py | 233 ++++++++++++++++-- novawow/__pycache__/settings.cpython-313.pyc | Bin 4572 -> 4569 bytes novawow/settings.py | 2 +- 20 files changed, 525 insertions(+), 202 deletions(-) create mode 100644 home/__pycache__/tasks.cpython-313.pyc create mode 100644 home/static/nw-themes/nw-ryu/nw-js-handlers/vote_points_response.js create mode 100644 home/templates/emails/confirm_new_email.html create mode 100644 home/templates/emails/confirm_old_email.html create mode 100644 home/templates/emails/old_email_notification.html diff --git a/home/__pycache__/admin.cpython-313.pyc b/home/__pycache__/admin.cpython-313.pyc index 61458924eb85d7fa21834b994c86b3299f77a79a..5df01a29f1fb52d25dc293f142871220adb40ce5 100644 GIT binary patch delta 3005 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 Sun=u07n48f#yF55J^l~xOSEPH diff --git a/home/__pycache__/tasks.cpython-313.pyc b/home/__pycache__/tasks.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7732d18c7b63f7a19470a30b074665e330832bbc GIT binary patch literal 1371 zcmaJ>&u<$=6n?Y2UT?a)O;m?X6uGujN>me(LuinS2n7-(aF7W$OF^+@E%wCS*4eRU zHV);4IGIXS#i0UDNN@m-+&CijAIOSIYep#`ajMiqkU1bu%s5`VsECpE-uHg&n>X{m z@xZoEfmk;muC;blfZwH&EM)`+F9~o5s!&B+P(l#tqLV8Q zG*=sU`V@ext)t59Brid(`iu?0l=iq=SF6k=(TPs#%JI6WEpK?ZcIFdQSxC@CpBs-{ zd~-VSixd6t4lP)GbZWWeyNOPNCpsuVUQA#Y*3~@hqM}w7>{0xtkW*fxLH2|2_06}7 zGgJR%Sm6@ev$rvnl&1v+&vFPcO%rr6{xX?ebw}=`izL z&*+<(*gPwKee2Az4m0!d^kOu<*wgy+*)Pp6%%1(H4s+*YXE}0~V`nvTR)2UmUf+(^ zw-24wL+7p7xe_^7esbRHnZKA$-%tvN^04QbuY*@#t(0?;YrjJ)Pvhe*YPYZcB zJG=3$dUq8GSuRd-y@A`9-k_4R+-hF)f)-iX5B)Yf8K1sKnphZ;CNwRDoIjO!^c@U@ z1S%=WjTc1XejC3?#d`wzpTnLMLNtNUeaPL1#b4oK1Q&lp)*s3f$R4Pm*h56mi@bjT DvP&JI literal 0 HcmV?d00001 diff --git a/home/__pycache__/urls.cpython-313.pyc b/home/__pycache__/urls.cpython-313.pyc index 0e12934e5297b17394027644d444608227b34119..bd4ad0c1633dcb82a0a24181b4eccba13e8be8b2 100644 GIT binary patch delta 1116 zcmZvcPfXKr6vtckL)c(bkj|~!7|c-^I4Tat#y}W?Y!msjWf~)KAvjoyRI~A+*Yv$Mm*1^O=3z}#IMgL#1@EJ`+(Mk-)3~&{m|jV`lk1DAwVmdrjr4LVv+mwlds-=p zJ5A?m|77Xp_Bk2WN?+Zx98kVQC-uzD+ZR5VfXS@Ln&<^x;QS00@Q5~Y(Wy{j6HId0#+XFu2i l(o3gQ5USYJug(irZ+T<}$Se&beAz(fSjOOdrOV)N;13rPP{05H delta 793 zcmZva&2JJx7{+&Ch(NnbQVK4gTX9<;Y7vn_r61B3Td0+`1P`W>7}H=IH4(KZ6YUL? zCQ|p{UQ9W7=&^=N{|dA3r5jBe<9{&5yK&#)WYb9|ncd&>zVGu)=H$|eBK;9Xw_vTU zy-f4Ky)Vf`_!>88_D=1>q z?V)!4L*sp;n*(}<*{z?ysMBzT^tu_zK_q9)RDrHChpMfJ!JvhII|YZU9q5$IVHJke zL#r;sT&lJ!%2~vN7B*Z#y<~<{5KbL!11&NUiNr}j&zhkOgfhn|pcUp(wQr*AKt80s z@OW)r^`j(@;J2UaN4leCtO&89vGfpVgIz=zuX)1XJ3Y=zBYj#~IX|@idFz zHsO8w{pBH&H)hv>uCpRRIES$9@Ay6``$~5Q=s26_V4+{dAHf8KCyeQPK&z~T@ZA8r OO9V;Xb+?wS*ZB{fn(UYW diff --git a/home/__pycache__/views.cpython-313.pyc b/home/__pycache__/views.cpython-313.pyc index 8b17fbbabc5490ed6f656801a0013640f4a81ddf..ee78eb0d1aab0d8ba0166034f3bc49bf8a38ff44 100644 GIT binary patch delta 15133 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 KK73t{Q2zox>*RC* diff --git a/home/admin.py b/home/admin.py index 903fb61..78d2fc8 100644 --- a/home/admin.py +++ b/home/admin.py @@ -3,7 +3,7 @@ from django.contrib import admin from django import forms from .models import ( Noticia, ClienteCategoria, SistemaOperativo, ServerSelection, - RecruitAFriend, DownloadClientPage, ContentCreator, RecruitReward, GuildRenameSettings + RecruitAFriend, DownloadClientPage, ContentCreator, RecruitReward, GuildRenameSettings, VoteSite ) from django.db import connections import logging @@ -139,7 +139,15 @@ class GuildRenameSettingsAdmin(admin.ModelAdmin): (None, { 'fields': ('cost',) }), - ) + ) + + +@admin.register(VoteSite) +class VoteSiteAdmin(admin.ModelAdmin): + list_display = ('name', 'points', 'url', 'image_url') + search_fields = ('name',) + list_editable = ('points',) + list_display_links = ('name',) # Registro de modelos en el admin diff --git a/home/models.py b/home/models.py index 1800ab3..c636101 100644 --- a/home/models.py +++ b/home/models.py @@ -106,11 +106,13 @@ class ClaimedReward(models.Model): class AccountActivation(models.Model): username = models.CharField(max_length=17) email = models.EmailField() + old_email = models.EmailField(null=True, blank=True) password = models.CharField(max_length=64) # Hash de la contraseña salt = models.BinaryField(max_length=32) verifier = models.BinaryField(max_length=32) recruiter_id = models.IntegerField(null=True, blank=True) hash = models.CharField(max_length=32, unique=True) + old_email_hash = models.CharField(max_length=32, null=True, blank=True) created_at = models.DateTimeField(default=timezone.now) def is_expired(self): @@ -118,14 +120,14 @@ class AccountActivation(models.Model): class SecurityToken(models.Model): - user_id = models.IntegerField() # Referencia al ID del usuario en `acore_auth` + user = models.ForeignKey(User, on_delete=models.CASCADE) token = models.CharField(max_length=6) created_at = models.DateTimeField(auto_now_add=True) expires_at = models.DateTimeField() ip_address = models.GenericIPAddressField() def __str__(self): - return f"Token for user_id {self.user_id}" + return f"Token for {self.user.username}" class GuildRenameSettings(models.Model): @@ -136,5 +138,40 @@ class GuildRenameSettings(models.Model): class Meta: verbose_name = "Configuración de Renombrar Hermandad" - verbose_name_plural = "Configuraciones de Renombrar Hermandad" + verbose_name_plural = "Configuraciones de Renombrar Hermandad" + + +class VoteSite(models.Model): + name = models.CharField(max_length=100, unique=True) + url = models.URLField(max_length=200, help_text="URL del sitio de votación") + image_url = models.URLField(max_length=300, help_text="URL completa de la imagen") + points = models.IntegerField(default=1, help_text="Puntos otorgados por votar") + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return self.name + +class VoteLog(models.Model): + account_id = models.IntegerField() + vote_site = models.ForeignKey('VoteSite', on_delete=models.CASCADE) + created_at = models.DateTimeField(auto_now_add=True) + last_vote_time = models.DateTimeField(null=True, blank=True) + processed = models.BooleanField(default=False) + processed_at = models.DateTimeField(null=True, blank=True) + + def __str__(self): + return f"Voto para {self.vote_site.name} por cuenta {self.account_id}" + + +class HomeApiPoints(models.Model): + accountID = models.IntegerField(unique=True) + vp = models.IntegerField(default=0) + dp = models.IntegerField(default=0) + + class Meta: + db_table = 'home_api_points' + + def __str__(self): + return f"Cuenta {self.accountID} - PV: {self.vp}, DP: {self.dp}" \ No newline at end of file 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 28ddd43..cc0b6bb 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,70 +1,42 @@ -if (window.history.replaceState) { - window.history.replaceState(null, null, window.location.href); -}; - -$(function(){ - $(".toggle-password").click(function() { - $(this).toggleClass("fa-eye fa-eye-slash"); - var type = $(this).hasClass("fa-eye-slash") ? "text" : "password"; - $("#password").attr("type", type); - }); -}); - -$(function(){ - $(".toggle-token").click(function() { - $(this).toggleClass("fa-eye fa-eye-slash"); - var type = $(this).hasClass("fa-eye-slash") ? "text" : "password"; - $("#security-token").attr("type", type); - }); -}); - -$(function(){ - $('#conf-new-email').on("cut copy paste",function(e) { - e.preventDefault(); - }); -}); - -$(function(){ - $('.change-email-button').on('click', function(e) { - e.preventDefault(); - e.stopPropagation(); +$(document).ready(function() { + $('#nw-change-email-form').on('submit', function(e) { + e.preventDefault(); // Evitar el envío por defecto del formulario $("#change-email-response").empty(); - var button = $(this); - var buttonoriginal = button.html(); - var bValue = button.data('id'); - var data = {changeemail: bValue}; - data = $("#uw-change-email-form").serialize() + '&' + $.param(data); + var form = $(this); + var button = $('.change-email-button'); + var originalText = button.html(); - changeButton(button, 'Cambiando correo'); + button.html("Cambiando correo..."); + button.prop("disabled", true); $.ajax({ type: 'POST', - url: '', - data: data, + url: form.attr('action'), + data: form.serialize(), // Serializar los datos correctamente dataType: 'json', - success: function(data) { - $("#change-email-response").append(data.message).hide().slideDown(); + success: function(response) { + $("#change-email-response").html(response.message).hide().slideDown(); - if (data.success === true) { + if (response.success) { button.html("Correo cambiado"); - button.css("color","#d79602"); - } - else { + } else { setTimeout(function() { - $("#change-email-response").slideUp( function() { - $("#change-email-response").empty(); - restoreButton(button, buttonoriginal); + $("#change-email-response").slideUp(function() { + $("#change-email-response").empty(); + button.html(originalText); + button.prop("disabled", false); }); }, 5000); } }, - error: function() { - setTimeout(function() { - alert("Algo ha salido mal. Por favor intente más tarde"); - window.location.reload(); - }, 2000); + error: function(xhr, status, error) { + console.error("Error:", error); + console.error("Detalles:", xhr.responseText); + $("#change-email-response").html('Algo ha salido mal. Inténtelo de nuevo.'); + button.html(originalText); + button.prop("disabled", false); } }); }); -}); \ No newline at end of file +}); diff --git a/home/static/nw-themes/nw-ryu/nw-js-handlers/vote_points_response.js b/home/static/nw-themes/nw-ryu/nw-js-handlers/vote_points_response.js new file mode 100644 index 0000000..2f54003 --- /dev/null +++ b/home/static/nw-themes/nw-ryu/nw-js-handlers/vote_points_response.js @@ -0,0 +1,75 @@ +$(document).ready(function() { + $('.vote-button').each(function() { + var button = $(this); + var remainingTime = button.data('remaining-time'); + + if (remainingTime) { + startCooldownTimer(button, remainingTime); + } + }); + + $('.vote-button').on('click', function(e) { + e.preventDefault(); + $("#voteResponse").empty(); + + var button = $(this); + var voteUrl = button.data('url').trim(); + var data = { vote: voteUrl }; + + button.html("Votando..."); + button.prop("disabled", true); + + var otherWindow = window.open(voteUrl, "_blank"); + otherWindow.opener = null; + + $.ajax({ + type: 'POST', + url: '', + data: data, + dataType: 'json', + success: function(response) { + $("#voteResponse").html(response.message).hide().slideDown(); + + if (response.success) { + button.html("Votado"); + button.prop("disabled", true); + } else { + button.html("Votar"); + button.prop("disabled", false); + } + + // Ocultar el mensaje después de 5 segundos + setTimeout(function() { + $("#voteResponse").slideUp(function() { + $("#voteResponse").empty(); + }); + }, 5000); + }, + error: function() { + $("#voteResponse").html('Algo ha salido mal. Por favor, inténtalo más tarde.'); + + // Ocultar el mensaje después de 5 segundos en caso de error + setTimeout(function() { + $("#voteResponse").slideUp(function() { + $("#voteResponse").empty(); + }); + }, 5000); + } + }); + }); +}); + +function startCooldownTimer(button, remainingTime) { + var interval = setInterval(function() { + if (remainingTime <= 0) { + clearInterval(interval); + button.html("Votar"); + button.prop("disabled", false); + } else { + var hours = Math.floor(remainingTime / 3600); + var minutes = Math.floor((remainingTime % 3600) / 60); + button.html(`Espera ${hours}h ${minutes}m`); + remainingTime--; + } + }, 1000); +} diff --git a/home/templates/emails/confirm_new_email.html b/home/templates/emails/confirm_new_email.html new file mode 100644 index 0000000..ed97fd0 --- /dev/null +++ b/home/templates/emails/confirm_new_email.html @@ -0,0 +1,28 @@ + + + + + Activación del Nuevo Correo + + + + + + + + + +
+

Activación de Nuevo Correo

+
+

Hola {{ username }},

+

Tu solicitud para cambiar el correo electrónico en {{ NOMBRE_SERVIDOR }} ha sido recibida.

+

Por favor, haz clic en el siguiente enlace para confirmar tu nuevo correo:

+

+ Activar nuevo correo +

+

Si no realizaste esta solicitud, por favor contacta con soporte.

+

Atentamente,
El equipo de {{ NOMBRE_SERVIDOR }}

+
+ + diff --git a/home/templates/emails/confirm_old_email.html b/home/templates/emails/confirm_old_email.html new file mode 100644 index 0000000..1c7c0f4 --- /dev/null +++ b/home/templates/emails/confirm_old_email.html @@ -0,0 +1,28 @@ + + + + + Confirmación de Cambio de Correo + + + + + + + + + +
+

Confirmación de Cambio de Correo

+
+

Hola {{ username }},

+

Has solicitado cambiar tu correo electrónico registrado en {{ NOMBRE_SERVIDOR }}.

+

Para confirmar este cambio, haz clic en el siguiente enlace:

+

+ Confirmar cambio +

+

Si no solicitaste este cambio, por favor ignora este correo.

+

Atentamente,
El equipo de {{ NOMBRE_SERVIDOR }}

+
+ + diff --git a/home/templates/emails/old_email_notification.html b/home/templates/emails/old_email_notification.html new file mode 100644 index 0000000..6afbed1 --- /dev/null +++ b/home/templates/emails/old_email_notification.html @@ -0,0 +1,27 @@ + + + + + Notificación de Cambio de Correo + + + + + + + + + +
+

Cambio de Correo Exitoso

+
+

Hola {{ username }},

+

Te notificamos que tu correo electrónico en {{ NOMBRE_SERVIDOR }} ha sido cambiado exitosamente al siguiente correo:

+

+ {{ new_email }} +

+

Si no realizaste este cambio, por favor contacta inmediatamente con soporte.

+

Atentamente,
El equipo de {{ NOMBRE_SERVIDOR }}

+
+ + diff --git a/home/templates/partials/change_email.html b/home/templates/partials/change_email.html index a53d81f..175351f 100644 --- a/home/templates/partials/change_email.html +++ b/home/templates/partials/change_email.html @@ -14,10 +14,42 @@


- El cambio de correo ya no es una herramienta disponible por autogestión. -
-
-
+
+ {% csrf_token %} + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
+ + + + + +
diff --git a/home/templates/partials/head.html b/home/templates/partials/head.html index 05f7f72..4fdc02b 100644 --- a/home/templates/partials/head.html +++ b/home/templates/partials/head.html @@ -51,6 +51,7 @@ + diff --git a/home/templates/partials/my-account.html b/home/templates/partials/my-account.html index fd826c7..65d2334 100644 --- a/home/templates/partials/my-account.html +++ b/home/templates/partials/my-account.html @@ -20,9 +20,17 @@ Estado de la cuenta
Nivel 1 -

PD: 0

-

PV: 0

-

Token de Seguridad: Sin solicitar

+

PD: {{ dp }}

+

PV: {{ vp }}

+

Token de Seguridad: + + {% if token_status == "Solicitado" %} + {{ token_status }} - {{ token_date }} + {% else %} + {{ token_status }} + {% endif %} + +

{% if account_status.is_banned %}

Cuenta baneada:

diff --git a/home/templates/partials/vote_points.html b/home/templates/partials/vote_points.html index c69b3f3..db203e0 100644 --- a/home/templates/partials/vote_points.html +++ b/home/templates/partials/vote_points.html @@ -52,122 +52,32 @@

Nota: Gtop100 puede demorar unos minutos en acreditar el voto.


-
- - - - - - - - - - - - - - - - - - - - - - -
Gtop100
Gtop100

PV: 1

-
- -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - -
TopG
TopG

PV: 1

-
- -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - -
Top100arena
Top100arena

PV: 1

-
- -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - -
Arena-Top100
Arena-Top100

PV: 1

-
- -
-
-
+
+
+ {% for site in vote_sites %} +
+ + + + + + + + + + + + + +
{{ site.name }}
{{ site.name }}
PV: {{ site.points }}
+
+ {% csrf_token %} + +
+
+
+{% endfor %} +

diff --git a/home/urls.py b/home/urls.py index c8988be..6be487d 100644 --- a/home/urls.py +++ b/home/urls.py @@ -23,7 +23,9 @@ urlpatterns = [ path('not-found/', views.not_found, name='not-found'), path('change-password/', views.change_password_view, name='change_password'), path('security-token/', views.security_token_view, name='security_token'), - path('change-email/', views.change_email_view, name='change_email'), + 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('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'), diff --git a/home/views.py b/home/views.py index 263ec29..b4f7d90 100644 --- a/home/views.py +++ b/home/views.py @@ -5,12 +5,12 @@ import binascii import os import re from django.shortcuts import render, redirect -from django.http import JsonResponse +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 +from .models import Noticia, ClienteCategoria, ServerSelection, RecruitAFriend, DownloadClientPage, ContentCreator, RecruitReward, ClaimedReward, AccountActivation, SecurityToken, GuildRenameSettings, VoteSite, VoteLog, HomeApiPoints from django.views.decorators.csrf import csrf_exempt import logging from datetime import datetime, timedelta @@ -22,7 +22,6 @@ from django.utils.crypto import get_random_string from django.conf import settings import secrets - # Configuración del logger logger = logging.getLogger(__name__) @@ -340,7 +339,7 @@ def register_view(request): ) # Enviar correo de activación - activation_link = f"http://localhost:8009/es/activate-account?act={activation_hash}" + activation_link = f"{settings.URL_PRINCIPAL}/es/activate-account?act={activation_hash}" context = { 'username': username, 'password': password, @@ -610,6 +609,21 @@ def my_account(request): # Obtener el estado de la cuenta account_status = get_account_status(account_id) + + # Obtener los puntos (DP y VP) del usuario desde la tabla `home_api_points` + user_points = HomeApiPoints.objects.filter(accountID=account_id).first() + dp = user_points.dp if user_points else 0 + vp = user_points.vp if user_points else 0 + + + # Obtener el estado del token de seguridad + security_token = SecurityToken.objects.filter(user_id=account_id).first() + if security_token: + token_status = "Solicitado" + token_date = security_token.created_at.strftime('%H:%M:%S %d-%m-%Y') + else: + token_status = "Sin solicitar" + token_date = None return render(request, 'my-account/my-account.html', { 'is_logged_in': is_logged_in, @@ -620,10 +634,15 @@ def my_account(request): 'last_ip': account_data[4], 'last_attempt_ip': account_data[5], 'joindate': formatear_fecha(account_data[6]), + }, 'account_status': account_status, 'characters': characters, 'has_characters': has_characters, + 'dp': dp, + 'vp': vp, + 'token_status': token_status, + 'token_date': token_date }) @@ -951,15 +970,146 @@ def send_security_token_email(email, username, token, ip_address): context=context ) - - def change_email_view(request): - """ - Vista para la página de 'Cambiar Correo'. - Simplemente renderiza un template con información relevante. - """ + username = request.session.get('username') + if not username: + return redirect('login') + + # Obtener el usuario desde la base de datos de `acore_auth` + with connections['acore_auth'].cursor() as cursor: + cursor.execute(""" + SELECT id, email, reg_mail + FROM account + WHERE username = %s + """, [username]) + account_data = cursor.fetchone() + + if not account_data: + return redirect('login') + + user_id, current_email, reg_email = account_data + security_token = SecurityToken.objects.filter(user_id=user_id).first() + + if request.method == 'POST': + print("Datos recibidos:", request.POST) + + current_password = request.POST.get('cur-password', '').strip() + current_email_input = request.POST.get('cur-email', '').strip() + new_email = request.POST.get('new-email', '').strip() + conf_new_email = request.POST.get('conf-new-email', '').strip() + token = request.POST.get('security-token', '').strip() + + # 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.'}) + + if current_email_input != current_email: + 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.'}) + + 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.'}) + + if not security_token or security_token.token != token: + return JsonResponse({'success': False, 'message': 'Token de seguridad incorrecto.'}) + + if not authenticate(username, current_password): + return JsonResponse({'success': False, 'message': 'Contraseña incorrecta.'}) + + # Generar hashes + old_email_hash = secrets.token_urlsafe(16) + new_email_hash = secrets.token_urlsafe(16) + + # Guardar en `AccountActivation` + AccountActivation.objects.create( + username=username, + email=new_email, + old_email=current_email, + password='', + salt=b'', + verifier=b'', + recruiter_id=user_id, + hash=new_email_hash, + old_email_hash=old_email_hash + ) + + # Enviar confirmación al correo actual + confirm_old_email_link = f"{settings.URL_PRINCIPAL}/es/confirm-old-email?hash={old_email_hash}" + context_old_email = { + 'username': username, + 'confirm_link': confirm_old_email_link, + 'NOMBRE_SERVIDOR': settings.NOMBRE_SERVIDOR + } + enviar_correo( + subject=f'Confirme el cambio de correo para {username}', + to_email=current_email, + template='emails/confirm_old_email.html', + context=context_old_email + ) + + return JsonResponse({'success': True, 'message': 'Se ha enviado un correo de confirmación al correo actual.'}) + return render(request, 'account/change_email.html') - + + +def confirm_old_email_view(request): + hash = request.GET.get('hash') + activation = AccountActivation.objects.filter(old_email_hash=hash).first() + + if not activation: + return HttpResponse('Enlace no válido o expirado.', status=400) + + # Enviar correo al nuevo correo para confirmar el cambio + activation_link = f"{settings.URL_PRINCIPAL}/es/confirm-new-email?hash={activation.hash}" + context_new_email = { + 'username': activation.username, + 'activation_link': activation_link, + 'NOMBRE_SERVIDOR': settings.NOMBRE_SERVIDOR + } + enviar_correo( + subject=f'Confirme su nuevo correo para {activation.username}', + to_email=activation.email, + template='emails/confirm_new_email.html', + context=context_new_email + ) + + return HttpResponse('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).first() + + if not activation: + return HttpResponse('Enlace no válido o expirado.', status=400) + + # Actualizar el correo en la base de datos + with connections['acore_auth'].cursor() as cursor: + cursor.execute(""" + UPDATE account + SET email = %s, reg_mail = %s + WHERE username = %s + """, [activation.email, activation.email, activation.username]) + + # Enviar notificación al correo anterior + context_old_email = { + 'username': activation.username, + 'new_email': activation.email, + 'NOMBRE_SERVIDOR': settings.NOMBRE_SERVIDOR + } + enviar_correo( + subject=f'Su correo ha sido cambiado en {settings.NOMBRE_SERVIDOR}', + to_email=activation.old_email, + template='emails/old_email_notification.html', + context=context_old_email + ) + + return HttpResponse('El cambio de correo ha sido confirmado y completado con éxito.') + + + def promo_code_view(request): return render(request, 'account/promo_code.html') @@ -967,9 +1117,6 @@ def transfer_d_points_view(request): # Renderizar la plantilla para la transferencia de puntos return render(request, 'account/transfer_d_points.html') - -from .models import GuildRenameSettings - def rename_guild_view(request): # Verificar si el usuario está autenticado mediante la sesión username = request.session.get('username') @@ -1037,12 +1184,60 @@ def rename_guild_view(request): 'rename_cost': rename_cost }) - def vote_points_view(request): - """ - Vista para la página de puntos de votación. - """ - return render(request, 'account/vote_points.html') + # 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` basado en el `username` + with connections['acore_auth'].cursor() as cursor: + cursor.execute("SELECT id FROM account WHERE username = %s", [username]) + account_data = cursor.fetchone() + + if not account_data: + return JsonResponse({'success': False, 'message': 'Cuenta no encontrada.'}) + + account_id = account_data[0] + + if request.method == 'POST': + vote_url = request.POST.get('vote').strip() + + site = VoteSite.objects.filter(url=vote_url).first() + if not site: + return JsonResponse({'success': False, 'message': 'Sitio de votación no encontrado.'}) + + # Verificar si ya ha votado en las últimas 12 horas y 30 minutos + last_vote = VoteLog.objects.filter(account_id=account_id, vote_site=site).order_by('-created_at').first() + now = timezone.now() + if last_vote: + time_diff = now - last_vote.created_at + cooldown_period = timedelta(hours=12, minutes=30) + + if time_diff < cooldown_period: + remaining_time = cooldown_period - time_diff + hours, remainder = divmod(remaining_time.seconds, 3600) + minutes, _ = divmod(remainder, 60) + return JsonResponse({ + 'success': False, + 'message': f'Tienes que esperar {hours} horas y {minutes} minutos antes de volver a votar.' + }) + + # Acreditar puntos al usuario y registrar el voto + user_points = HomeApiPoints.objects.filter(accountID=account_id).first() + if user_points: + user_points.vp += site.points + user_points.save() + else: + HomeApiPoints.objects.create(accountID=account_id, vp=site.points, dp=0) + + # Registrar el voto + VoteLog.objects.create(account_id=account_id, vote_site=site, last_vote_time=now) + + return JsonResponse({'success': True, 'message': f'Has votado en {site.name}. Se han acreditado {site.points} PV.'}) + + vote_sites = VoteSite.objects.all() + return render(request, 'account/vote_points.html', {'vote_sites': vote_sites}) def d_points_view(request): """ diff --git a/novawow/__pycache__/settings.cpython-313.pyc b/novawow/__pycache__/settings.cpython-313.pyc index 8246ab738b4f1fb78b33315b4e41f2a43b5b0e44..3fcba2307484510a552f17e5b31338544c08cb0c 100644 GIT binary patch delta 203 zcmcbkd{deCGcPX}0}xDCuuAXU$eYf>R>h(K1e0r7t}20KZgD2&WTxlkrskF0V$Uxv zNdYm~GV?%m5!d7rRue|9$tzi>F^X??V2fh$H38}=G6fN4Ai^9(Sbzvi5TOqwZV4nN z=NF~MCubxUB_@}o78PqU7jb}Otw4kgknjVWP~|b%kXvIiKld|6>CNA`%a|B7H|O&4 XGBTD-uI5i<6y1E6|2HE`5l}q<1Qj(W delta 150 zcmcbqd`Fr0GcPX}0}w0^HBO(fkvE-%^A@|Kb9}JBW5DDpmaB~1lLJ^4fMg-736NaI zI*n0cvn^W`%j7v+lKNIajYS4P;+8;Sa(+>2d~!x&QDSmQYEiK!a}g&<)*3|E0tvq& pv(5Lpgc%uSHh<$XGhLf