feat: Add Password recuperation logic
Added: - Phase 1 Template + Logic - Phase 2 Template + Logic
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,27 @@
|
|||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="padding: 20px;">
|
||||||
|
<table width="600" border="0" cellspacing="0" cellpadding="0" style="border: 1px solid #eeeeee; background-color: #ffffff;">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="background-color: #007bff; padding: 40px;">
|
||||||
|
<h1 style="color: #ffffff; font-family: sans-serif; margin: 0;">¡Hola {{ name }}!</h1>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="padding: 40px">
|
||||||
|
<svg fill="#FF0000" width="128px" height="128px" viewBox="-3.2 -3.2 38.40 38.40" version="1.1" xmlns="http://www.w3.org/2000/svg" stroke="#FF0000" stroke-width="0.00032"><g id="SVGRepo_bgCarrier" stroke-width="0" transform="translate(6.4,6.4), scale(0.6)"><rect x="-3.2" y="-3.2" width="38.40" height="38.40" rx="19.2" fill="#1a5fb4" strokewidth="0"></rect></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" stroke="#CCCCCC" stroke-width="1.152"> <title>alert</title> <path d="M14.611 18.856c-0.346 0.352-0.52 0.782-0.52 1.292 0 0.551 0.197 1.014 0.59 1.389 0.363 0.346 0.799 0.519 1.309 0.519 0.521 0 0.971-0.188 1.346-0.566s0.562-0.828 0.562-1.35c0-0.504-0.182-0.943-0.545-1.318-0.363-0.381-0.801-0.571-1.311-0.571-0.567-0.001-1.044 0.201-1.431 0.605v0zM14.391 10.788c-0.299 0.451-0.447 1.011-0.447 1.679 0 0.545 0.092 1.146 0.276 1.802s0.435 1.271 0.751 1.846c0.428 0.779 0.76 1.169 0.994 1.169 0.24 0 0.557-0.305 0.949-0.914 0.346-0.539 0.622-1.152 0.83-1.841s0.312-1.332 0.312-1.93c0-0.902-0.244-1.6-0.73-2.092-0.363-0.375-0.805-0.563-1.326-0.563-0.703 0-1.24 0.282-1.609 0.844v0z"></path> </g><g id="SVGRepo_iconCarrier"> <title>alert</title> <path d="M14.611 18.856c-0.346 0.352-0.52 0.782-0.52 1.292 0 0.551 0.197 1.014 0.59 1.389 0.363 0.346 0.799 0.519 1.309 0.519 0.521 0 0.971-0.188 1.346-0.566s0.562-0.828 0.562-1.35c0-0.504-0.182-0.943-0.545-1.318-0.363-0.381-0.801-0.571-1.311-0.571-0.567-0.001-1.044 0.201-1.431 0.605v0zM14.391 10.788c-0.299 0.451-0.447 1.011-0.447 1.679 0 0.545 0.092 1.146 0.276 1.802s0.435 1.271 0.751 1.846c0.428 0.779 0.76 1.169 0.994 1.169 0.24 0 0.557-0.305 0.949-0.914 0.346-0.539 0.622-1.152 0.83-1.841s0.312-1.332 0.312-1.93c0-0.902-0.244-1.6-0.73-2.092-0.363-0.375-0.805-0.563-1.326-0.563-0.703 0-1.24 0.282-1.609 0.844v0z"></path> </g></svg>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 30px; font-family: sans-serif; line-height: 1.5; color: #444444;">
|
||||||
|
<p>¡Alguien esta intentando cambiar la contraseña de tu cuenta!</p>
|
||||||
|
<p>Si has sido tu, haga click en el siguiente enlace. Si no, <strong>Elimine el correo de inmediato</strong></p>
|
||||||
|
<p></p>
|
||||||
|
<p>Para resetear tu contraseña, <a href="{{ protocol }}://{{ domain }}/tienda/reset-password-phase2/{{ code }}">Haga click aqui</a></p>
|
||||||
|
<p>Este email ha sido enviado automaticamente, no responda a este correo.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
+25
-1
@@ -18,7 +18,8 @@ def enviar_correo_bienvenida(email_usuario: str, nombre_usuario: str):
|
|||||||
send_hemail(email_usuario, "Inicio de Sesión correcto", html_content, "Has iniciado sesión...")
|
send_hemail(email_usuario, "Inicio de Sesión correcto", html_content, "Has iniciado sesión...")
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def enviar_correo_confirmacion(usuario: User):
|
def enviar_correo_confirmacion(id: int):
|
||||||
|
usuario = User.objects.get(id=id)
|
||||||
code = VerificationCode.objects.create(
|
code = VerificationCode.objects.create(
|
||||||
user = usuario,
|
user = usuario,
|
||||||
code_mode = VerificationCode.VerificationModes.VERIFY_ACCOUNT,
|
code_mode = VerificationCode.VerificationModes.VERIFY_ACCOUNT,
|
||||||
@@ -27,3 +28,26 @@ def enviar_correo_confirmacion(usuario: User):
|
|||||||
|
|
||||||
message = verify_message.format(name = usuario.get_full_name(), protocol = settings.PROTOCOL, domain = settings.DOMAIN, code = code.code)
|
message = verify_message.format(name = usuario.get_full_name(), protocol = settings.PROTOCOL, domain = settings.DOMAIN, code = code.code)
|
||||||
email_result = send_email(usuario.email, "Verificación de cuenta", message)
|
email_result = send_email(usuario.email, "Verificación de cuenta", message)
|
||||||
|
|
||||||
|
@shared_task
|
||||||
|
def enviar_correo_recuperacion(email: str):
|
||||||
|
usuario = User.objects.get(email=email)
|
||||||
|
if usuario is not None:
|
||||||
|
ver_code = VerificationCode.objects.create(
|
||||||
|
code_mode = VerificationCode.VerificationModes.RESET_PASSWORD,
|
||||||
|
user = usuario,
|
||||||
|
code = ''.join(random.choices(string.digits, k=12))
|
||||||
|
)
|
||||||
|
ver_code.save()
|
||||||
|
html_content = render_to_string(
|
||||||
|
'emails/reset_pass.html',
|
||||||
|
{
|
||||||
|
"name": usuario.get_full_name(),
|
||||||
|
"domain": settings.DOMAIN,
|
||||||
|
"protocol": settings.PROTOCOL,
|
||||||
|
"code": ver_code.code
|
||||||
|
},
|
||||||
|
using='jinja2'
|
||||||
|
)
|
||||||
|
|
||||||
|
send_hemail(email, "Reset de Contraseña", html_content, "Estas reseteando la contraseña...")
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-3 text-center">
|
<div class="mt-3 text-center">
|
||||||
<a href="#" class="text-decoration-none">¿Olvidaste tu contraseña?</a>
|
<a href="{% url 'reset_password' %}" class="text-decoration-none">¿Olvidaste tu contraseña?</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-3">
|
<hr class="my-3">
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
{% extends "tienda/base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row justify-content-center mt-5">
|
||||||
|
<div class="col-md-6 col-lg-4">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="text-center mb-0">Recuperar contraseña</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="post" action="{% url 'reset_password' %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="loginEmail" class="form-label">Correo Electrónico</label>
|
||||||
|
<input type="email" class="form-control" id="loginEmail" name="email" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid gap-2">
|
||||||
|
<button type="submit" class="btn btn-primary">Recuperar contraseña</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="my-3">
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="mb-0">¿No tienes cuenta? <a href="{% url 'register' %}">Regístrate aquí</a></p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
{% extends "tienda/base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row justify-content-center mt-5">
|
||||||
|
<div class="col-md-6 col-lg-4">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="text-center mb-0">Recuperar contraseña</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="post" action="{% url 'reset_password_phase2' code %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="password" class="form-label">Contraseña</label>
|
||||||
|
<input type="password" class="form-control" id="password" name="password" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="verify_password" class="form-label">Verificar contraseña</label>
|
||||||
|
<input type="password" class="form-control" id="verify_password" name="verify_password" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid gap-2">
|
||||||
|
<button type="submit" class="btn btn-primary">Recuperar contraseña</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="my-3">
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="mb-0">¿No tienes cuenta? <a href="{% url 'register' %}">Regístrate aquí</a></p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
+3
-1
@@ -45,5 +45,7 @@ urlpatterns = [
|
|||||||
path("usuario/direcciones/<int:id>/eliminar/", views.eliminar_direccion, name="eliminar_direccion"),
|
path("usuario/direcciones/<int:id>/eliminar/", views.eliminar_direccion, name="eliminar_direccion"),
|
||||||
path("usuario/mensajes/", views.mensajes_comprador, name="mensajes_comprador"),
|
path("usuario/mensajes/", views.mensajes_comprador, name="mensajes_comprador"),
|
||||||
path("verify/<str:code>", views.verify, name="verify"),
|
path("verify/<str:code>", views.verify, name="verify"),
|
||||||
path("rgpd", views.rgpd, name="rgpd")
|
path("rgpd", views.rgpd, name="rgpd"),
|
||||||
|
path("reset-password", views.reset_password, name="reset_password"),
|
||||||
|
path("reset-password-phase2/<str:code>", views.reset_password_phase2, name="reset_password_phase2")
|
||||||
]
|
]
|
||||||
|
|||||||
+39
-2
@@ -1,5 +1,5 @@
|
|||||||
from django.shortcuts import render, redirect, get_object_or_404
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
from django.http import HttpRequest, HttpResponse, JsonResponse
|
from django.http import Http404, HttpRequest, HttpResponse, JsonResponse
|
||||||
from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout
|
from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout
|
||||||
|
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
@@ -237,7 +237,7 @@ def register(request: HttpRequest):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
tasks.enviar_correo_confirmacion.delay(user)
|
tasks.enviar_correo_confirmacion.delay(user.id)
|
||||||
messages.success(request, f"¡Cuenta creada exitosamente! Por favor, verifica tu correo entrando al Link enviado.")
|
messages.success(request, f"¡Cuenta creada exitosamente! Por favor, verifica tu correo entrando al Link enviado.")
|
||||||
return redirect("index")
|
return redirect("index")
|
||||||
|
|
||||||
@@ -1257,3 +1257,40 @@ def reset_password(request: HttpRequest):
|
|||||||
|
|
||||||
def rgpd(request: HttpRequest):
|
def rgpd(request: HttpRequest):
|
||||||
return render(request, "tienda/rgpd.html", {})
|
return render(request, "tienda/rgpd.html", {})
|
||||||
|
|
||||||
|
def reset_password(request: HttpRequest):
|
||||||
|
if request.method == "GET":
|
||||||
|
return render(request, "tienda/reset_password.html", {})
|
||||||
|
else:
|
||||||
|
tasks.enviar_correo_recuperacion.delay(request.POST["email"])
|
||||||
|
messages.info(request, "Si tienes una cuenta con ese correo electronico, se ha enviado un correo con un enlace")
|
||||||
|
return render(request, "tienda/index.html", {})
|
||||||
|
|
||||||
|
def reset_password_phase2(request: HttpRequest, code: str):
|
||||||
|
try:
|
||||||
|
ver_code = VerificationCode.objects.get(code=code)
|
||||||
|
except VerificationCode.DoesNotExist:
|
||||||
|
raise Http404()
|
||||||
|
|
||||||
|
if ver_code.code_mode != VerificationCode.VerificationModes.RESET_PASSWORD: raise Http404()
|
||||||
|
|
||||||
|
|
||||||
|
if request.method == "GET":
|
||||||
|
return render(request, "tienda/reset_password_phase2.html", {
|
||||||
|
"code": code
|
||||||
|
})
|
||||||
|
elif request.method == "POST":
|
||||||
|
password = request.POST["password"]
|
||||||
|
vpassword = request.POST["verify_password"]
|
||||||
|
if password != vpassword:
|
||||||
|
messages.error(request, "Las contraseñas no coinciden")
|
||||||
|
return render(request, "tienda/reset_password_phase2.html", {"code": code})
|
||||||
|
|
||||||
|
user = ver_code.user
|
||||||
|
user.set_password(password)
|
||||||
|
user.save()
|
||||||
|
messages.success(request, "Se ha cambiado la contraseña!")
|
||||||
|
return redirect(reverse("index"))
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise Http404()
|
||||||
|
|||||||
Reference in New Issue
Block a user