feat: reset password working
This commit is contained in:
@@ -191,6 +191,11 @@ SPECTACULAR_SETTINGS = {
|
|||||||
"SERVE_INCLUDE_SCHEMA": False,
|
"SERVE_INCLUDE_SCHEMA": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EMAIL_USE_TLS = True
|
||||||
|
EMAIL_USE_SSL = False
|
||||||
|
|
||||||
|
|
||||||
CELERY_BROKER_URL = env.str("CELERY_BROKER_URL", default="memory://localhost:8000//")
|
CELERY_BROKER_URL = env.str("CELERY_BROKER_URL", default="memory://localhost:8000//")
|
||||||
CELERY_TIME_ZONE = TIME_ZONE
|
CELERY_TIME_ZONE = TIME_ZONE
|
||||||
CELERY_ALWAYS_EAGER = DEBUG
|
CELERY_ALWAYS_EAGER = DEBUG
|
||||||
|
|||||||
@@ -57,3 +57,11 @@ REDSYS_TPV_DOMAIN = env.str("REDSYS_TPV_DOMAIN", "")
|
|||||||
ITEMS_PER_PAGE = env.int("ITEMS_PER_PAGE", 20)
|
ITEMS_PER_PAGE = env.int("ITEMS_PER_PAGE", 20)
|
||||||
SHOP_COUNTRY = env.str("SHOP_COUNTRY", "ESPAÑA")
|
SHOP_COUNTRY = env.str("SHOP_COUNTRY", "ESPAÑA")
|
||||||
NPM_BIN_PATH = which("npm")
|
NPM_BIN_PATH = which("npm")
|
||||||
|
|
||||||
|
EMAIL_BACKEND = env.str(
|
||||||
|
"EMAIL_BACKEND", "django.core.mail.backends.console.EmailBackend"
|
||||||
|
)
|
||||||
|
EMAIL_HOST = env.str("EMAIL_HOST", "")
|
||||||
|
EMAIL_HOST_USER = env.str("EMAIL_HOST_USER", "")
|
||||||
|
EMAIL_HOST_PASSWORD = env.str("EMAIL_HOST_PASSWORD", "")
|
||||||
|
EMAIL_PORT = env.int("EMAIL_PORT", 587)
|
||||||
|
|||||||
+580
-357
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,8 @@
|
|||||||
# Generated by Django 5.1.4 on 2025-01-16 17:00
|
# Generated by Django 5.1.4 on 2025-01-16 17:00
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -14,6 +14,7 @@ from django.utils.text import gettext_lazy as _
|
|||||||
from shop.exceptions import RedsysPaymentException, RedsysValidationException
|
from shop.exceptions import RedsysPaymentException, RedsysValidationException
|
||||||
from shop.models import (
|
from shop.models import (
|
||||||
Cart,
|
Cart,
|
||||||
|
CartItem,
|
||||||
Order,
|
Order,
|
||||||
OrderLine,
|
OrderLine,
|
||||||
Payment,
|
Payment,
|
||||||
@@ -21,7 +22,6 @@ from shop.models import (
|
|||||||
ProductBatch,
|
ProductBatch,
|
||||||
ProductPrice,
|
ProductPrice,
|
||||||
ShippingMethod,
|
ShippingMethod,
|
||||||
CartItem,
|
|
||||||
)
|
)
|
||||||
from shop.settings import ERROR_CODES
|
from shop.settings import ERROR_CODES
|
||||||
from shop.signals import clear_cart
|
from shop.signals import clear_cart
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ from django.shortcuts import get_object_or_404
|
|||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
|
||||||
from shop.models import Order
|
from shop.models import Order
|
||||||
from shop.utils import validate_payment_for_order, add_payment_to_order
|
from shop.utils import add_payment_to_order, validate_payment_for_order
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth.forms import SetPasswordMixin, BaseUserCreationForm
|
from django.contrib.auth.forms import BaseUserCreationForm, SetPasswordMixin
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.forms import EmailField
|
from django.forms import EmailField
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
from django import forms
|
||||||
|
from django.contrib.auth.forms import PasswordResetForm as BasePasswordResetForm
|
||||||
|
from django.contrib.auth.forms import SetPasswordForm as BaseSetPasswordForm
|
||||||
|
from django.contrib.auth.tokens import default_token_generator
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
|
|
||||||
|
class PasswordResetForm(BasePasswordResetForm):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def validate_token(token):
|
||||||
|
is_valid = default_token_generator.check_token(token)
|
||||||
|
|
||||||
|
if not is_valid:
|
||||||
|
raise ValidationError(_("El token no es válido o ha expirado"))
|
||||||
|
|
||||||
|
|
||||||
|
class SetPasswordForm(BaseSetPasswordForm):
|
||||||
|
token = forms.CharField(
|
||||||
|
required=True,
|
||||||
|
widget=forms.HiddenInput(),
|
||||||
|
validators=[],
|
||||||
|
)
|
||||||
|
|
||||||
|
def validate_token(self):
|
||||||
|
is_valid = default_token_generator.check_token(self.user, self.data.get('token'))
|
||||||
|
|
||||||
|
if not is_valid:
|
||||||
|
raise ValidationError(_("El token no es válido o ha expirado"))
|
||||||
|
|
||||||
|
def is_valid(self):
|
||||||
|
try:
|
||||||
|
self.validate_token()
|
||||||
|
except ValidationError as e:
|
||||||
|
self.add_error(self.token, str(e))
|
||||||
|
return False
|
||||||
|
return super().is_valid()
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{% load i18n %}{% autoescape off %}
|
||||||
|
{% blocktranslate %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktranslate %}
|
||||||
|
|
||||||
|
{% translate "Please go to the following page and choose a new password:" %}
|
||||||
|
{% block reset_link %}
|
||||||
|
{{ protocol }}://{{ domain }}{% url 'web:reset_password_confirm' uidb64=uid token=token %}
|
||||||
|
{% endblock %}
|
||||||
|
{% translate 'Your username, in case you’ve forgotten:' %} {{ user.get_username }}
|
||||||
|
|
||||||
|
{% translate "Thanks for using our site!" %}
|
||||||
|
|
||||||
|
{% blocktranslate %}The {{ site_name }} team{% endblocktranslate %}
|
||||||
|
|
||||||
|
{% endautoescape %}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Hola madafaka
|
||||||
@@ -5,7 +5,8 @@
|
|||||||
<section class="bg-gray-50 dark:bg-gray-900">
|
<section class="bg-gray-50 dark:bg-gray-900">
|
||||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||||
|
|
||||||
<a href="{% url 'web:index' %}" class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
|
<a href="{% url 'web:index' %}"
|
||||||
|
class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
|
||||||
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</a>
|
</a>
|
||||||
@@ -28,23 +29,37 @@
|
|||||||
{{ field }}
|
{{ field }}
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="my-2 flex items-center">
|
<div class="my-2 flex items-center">
|
||||||
|
{{ field }}
|
||||||
<label for="{{ field.id_for_label }}"
|
<label for="{{ field.id_for_label }}"
|
||||||
class="inline-block text-sm font-medium text-gray-900 dark:text-white mr-2">
|
class="inline-block text-sm font-medium text-gray-900 dark:text-white ml-2">
|
||||||
{{ field.label }}
|
{{ field.label }}
|
||||||
</label>
|
</label>
|
||||||
{{ field }}
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<p class="text-sm font-light text-gray-500 my-4 dark:text-gray-400">
|
||||||
|
{% translate '¿Aún no tienes cuenta?' %}
|
||||||
|
<a href="{% url 'web:register' %}"
|
||||||
|
class="font-medium text-primary-600 hover:underline dark:text-primary-500">{% translate 'Regístrate aquí' %}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800">
|
class="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800">
|
||||||
{% translate 'Iniciar sesión' %}
|
{% translate 'Iniciar sesión' %}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<div class="flex justify-center">
|
||||||
<p class="text-sm font-light text-gray-500 mt-4 dark:text-gray-400">
|
<p class="text-sm font-light text-gray-500 mt-4 dark:text-gray-400">
|
||||||
{% translate '¿Aún no tienes cuenta?' %}
|
<a href="{% url 'web:reset_password' %}"
|
||||||
<a href="{% url 'web:register' %}" class="font-medium text-primary-600 hover:underline dark:text-primary-500">{% translate 'Regístrate aquí' %}</a>
|
class="font-medium text-primary-600 hover:underline dark:text-primary-500">{% translate '¿Has olvidado tu contraseña?' %}</a>
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,42 +1,46 @@
|
|||||||
{% extends 'base/base.html' %}
|
{% extends 'theme/base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
<section class="bg-gray-50 dark:bg-gray-900">
|
<section class="bg-gray-50 dark:bg-gray-900">
|
||||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||||
<a href="#" class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
|
|
||||||
<img class="w-8 h-8 mr-2" src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/logo.svg" alt="logo">
|
<a href="{% url 'web:index' %}" class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
|
||||||
|
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</a>
|
</a>
|
||||||
<div class="w-full p-6 bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md dark:bg-gray-800 dark:border-gray-700 sm:p-8">
|
|
||||||
<h2 class="mb-1 text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
|
<div
|
||||||
Change Password
|
class="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700">
|
||||||
</h2>
|
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||||
<form class="mt-4 space-y-4 lg:mt-5 md:space-y-5" action="#">
|
<h1 class="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
|
||||||
<div>
|
{% translate 'Restablecer contraseña' %}
|
||||||
<label for="email" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your email</label>
|
</h1>
|
||||||
<input type="email" name="email" id="email" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-blue-500" placeholder="name@company.com" required="">
|
<form action="{% url 'web:reset_password' %}" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% for field in form %}
|
||||||
|
|
||||||
|
<div class="my-2 flex items-center">
|
||||||
|
<label for="{{ field.id_for_label }}"
|
||||||
|
class="inline-block text-sm font-medium text-gray-900 dark:text-white mr-2">
|
||||||
|
{{ field.label }}
|
||||||
|
</label>
|
||||||
|
{{ field }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">New Password</label>
|
{% endfor %}
|
||||||
<input type="password" name="password" id="password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-blue-500" required="">
|
<button
|
||||||
</div>
|
class="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800">
|
||||||
<div>
|
{% translate 'Restablecer contraseña' %}
|
||||||
<label for="confirm-password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Confirm password</label>
|
</button>
|
||||||
<input type="confirm-password" name="confirm-password" id="confirm-password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-blue-500" required="">
|
<p class="text-sm font-light text-gray-500 mt-4 dark:text-gray-400">
|
||||||
</div>
|
{% translate '¿Aún no tienes cuenta?' %}
|
||||||
<div class="flex items-start">
|
<a href="{% url 'web:register' %}" class="font-medium text-primary-600 hover:underline dark:text-primary-500">{% translate 'Regístrate aquí' %}</a>
|
||||||
<div class="flex items-center h-5">
|
</p>
|
||||||
<input id="newsletter" aria-describedby="newsletter" type="checkbox" class="w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-primary-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-primary-600 dark:ring-offset-gray-800" required="">
|
|
||||||
</div>
|
|
||||||
<div class="ml-3 text-sm">
|
|
||||||
<label for="newsletter" class="font-light text-gray-500 dark:text-gray-300">I accept the <a class="font-medium text-primary-600 hover:underline dark:text-primary-500" href="#">Terms and Conditions</a></label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800">Reset passwod</button>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{% extends 'theme/base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<section class="bg-gray-50 dark:bg-gray-900">
|
||||||
|
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||||
|
|
||||||
|
<a href="{% url 'web:index' %}" class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
|
||||||
|
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
||||||
|
{{ title }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700">
|
||||||
|
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||||
|
<h1 class="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
|
||||||
|
{% translate 'Restablecer contraseña' %}
|
||||||
|
</h1>
|
||||||
|
{% if valid_token %}
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% for field in form %}
|
||||||
|
|
||||||
|
<div class="my-2 flex items-center">
|
||||||
|
<label for="{{ field.id_for_label }}"
|
||||||
|
class="inline-block text-sm font-medium text-gray-900 dark:text-white mr-2">
|
||||||
|
{{ field.label }}
|
||||||
|
</label>
|
||||||
|
{{ field }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
<button
|
||||||
|
class="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800">
|
||||||
|
{% translate 'Restablecer contraseña' %}
|
||||||
|
</button>
|
||||||
|
<p class="text-sm font-light text-gray-500 mt-4 dark:text-gray-400">
|
||||||
|
{% translate '¿Aún no tienes cuenta?' %}
|
||||||
|
<a href="{% url 'web:register' %}" class="font-medium text-primary-600 hover:underline dark:text-primary-500">{% translate 'Regístrate aquí' %}</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<span>El enlace no es válido o ha expirado</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
{% extends 'theme/base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<section class="bg-gray-50 dark:bg-gray-900">
|
||||||
|
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||||
|
|
||||||
|
<a href="{% url 'web:index' %}"
|
||||||
|
class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
|
||||||
|
<img class="w-8 h-8 mr-2" src="{{ logo }}" alt="logo">
|
||||||
|
{{ title }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700">
|
||||||
|
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||||
|
<h1 class="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
|
||||||
|
{% translate 'Se te ha enviado un correo electrónico para restablecer tu contraseña' %}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p class="text-sm font-light text-gray-500 mt-4 dark:text-gray-400">
|
||||||
|
{% translate '¿Aún no tienes cuenta?' %}
|
||||||
|
<a href="{% url 'web:register' %}"
|
||||||
|
class="font-medium text-primary-600 hover:underline dark:text-primary-500">{% translate 'Regístrate aquí' %}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from web.models import WebSettings
|
from web.models import WebSettings
|
||||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
||||||
|
|
||||||
|
|
||||||
class TestManifest(TestCase):
|
class TestManifest(TestCase):
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ from django.urls import reverse
|
|||||||
from shop.models import (
|
from shop.models import (
|
||||||
Cart,
|
Cart,
|
||||||
CartItem,
|
CartItem,
|
||||||
Order,
|
|
||||||
CustomerAddress,
|
CustomerAddress,
|
||||||
|
Order,
|
||||||
ShippingMethod,
|
ShippingMethod,
|
||||||
ShopSettings,
|
ShopSettings,
|
||||||
)
|
)
|
||||||
|
|||||||
+20
-2
@@ -10,7 +10,15 @@ from web.views.components import (
|
|||||||
list_wishlisted_products,
|
list_wishlisted_products,
|
||||||
wishlist_button,
|
wishlist_button,
|
||||||
)
|
)
|
||||||
from web.views.users import login, logout, my_account, register, reset_password
|
from web.views.users import (
|
||||||
|
login,
|
||||||
|
logout,
|
||||||
|
my_account,
|
||||||
|
register,
|
||||||
|
reset_password,
|
||||||
|
reset_password_confirm,
|
||||||
|
reset_password_email_sent,
|
||||||
|
)
|
||||||
from web.views.web import (
|
from web.views.web import (
|
||||||
add_cart_item,
|
add_cart_item,
|
||||||
add_to_wishlist,
|
add_to_wishlist,
|
||||||
@@ -40,7 +48,17 @@ i18n_resolvers = i18n_patterns(
|
|||||||
path(_("login/"), login, name="login"),
|
path(_("login/"), login, name="login"),
|
||||||
path(_("logout/"), logout, name="logout"),
|
path(_("logout/"), logout, name="logout"),
|
||||||
path(_("register/"), register, name="register"),
|
path(_("register/"), register, name="register"),
|
||||||
path(_("reset-password/"), reset_password, name="reset-password"),
|
path(_("reset-password/"), reset_password, name="reset_password"),
|
||||||
|
path(
|
||||||
|
_("reset/<uidb64>/<token>/"),
|
||||||
|
reset_password_confirm,
|
||||||
|
name="reset_password_confirm",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
_("reset-password/email-sent/"),
|
||||||
|
reset_password_email_sent,
|
||||||
|
name="reset_password_email_sent",
|
||||||
|
),
|
||||||
path(_("my-account/"), my_account, name="my_account"),
|
path(_("my-account/"), my_account, name="my_account"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+112
-5
@@ -1,16 +1,19 @@
|
|||||||
from django.contrib.auth import login as login_user, authenticate
|
from django.conf import settings
|
||||||
from django.contrib.auth import logout as logout_user
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.contrib.auth import login as login_user
|
||||||
|
from django.contrib.auth import logout as logout_user
|
||||||
|
from django.contrib.auth.tokens import default_token_generator
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
from django.shortcuts import redirect, render, reverse
|
from django.shortcuts import redirect, render, reverse
|
||||||
|
from django.utils.http import url_has_allowed_host_and_scheme, urlsafe_base64_decode
|
||||||
from django.utils.text import gettext_lazy as _
|
from django.utils.text import gettext_lazy as _
|
||||||
from django.views.generic import TemplateView, View
|
from django.views.generic import TemplateView, View
|
||||||
|
|
||||||
from shop.models import CustomerAddress
|
from shop.models import CustomerAddress
|
||||||
from users.forms import LoginForm, RegisterForm
|
from users.forms import LoginForm, PasswordResetForm, RegisterForm, SetPasswordForm
|
||||||
from web.models import WebSettings
|
from web.models import WebSettings
|
||||||
|
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
@@ -123,7 +126,108 @@ class LogoutView(View, RedirectionMixin):
|
|||||||
|
|
||||||
|
|
||||||
class ResetPasswordView(TemplateView):
|
class ResetPasswordView(TemplateView):
|
||||||
template_name = "web/reset-password.html"
|
template_name = "users/reset_password.html"
|
||||||
|
form_class = PasswordResetForm
|
||||||
|
redirect_to = "web:reset_password_email_sent"
|
||||||
|
email_reset_password_template_name = "mails/reset_password.txt"
|
||||||
|
html_reset_password_template_name = "mails/reset_password.html"
|
||||||
|
subject_template_name = "mails/subject_reset_password.txt"
|
||||||
|
|
||||||
|
def get_email_options(self):
|
||||||
|
return {
|
||||||
|
"extra_email_context": {},
|
||||||
|
"email_template_name": self.email_reset_password_template_name,
|
||||||
|
"html_email_template_name": self.html_reset_password_template_name,
|
||||||
|
"subject_template_name": self.subject_template_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_base_context(self):
|
||||||
|
settings = WebSettings.load()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"title": settings.web_title,
|
||||||
|
"description": _("Restablecer contraseña"),
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = self.get_base_context()
|
||||||
|
context.update({"form": self.form_class()})
|
||||||
|
return context
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
form = self.form_class(request.POST)
|
||||||
|
|
||||||
|
if form.is_valid():
|
||||||
|
opts = {
|
||||||
|
"use_https": request.is_secure(),
|
||||||
|
"from_email": getattr(settings, "DEFAULT_FROM_EMAIL"),
|
||||||
|
"request": request,
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.update(self.get_email_options())
|
||||||
|
form.save(**opts)
|
||||||
|
return redirect(self.redirect_to)
|
||||||
|
|
||||||
|
context = self.get_base_context()
|
||||||
|
context.update({"form": form})
|
||||||
|
|
||||||
|
return render(request, self.template_name, context)
|
||||||
|
|
||||||
|
|
||||||
|
class ResetPasswordEmailSent(TemplateView):
|
||||||
|
template_name = "users/reset_password_email_sent.html"
|
||||||
|
|
||||||
|
|
||||||
|
class ResetPasswordConfirmView(TemplateView):
|
||||||
|
template_name = "users/reset_password_confirm.html"
|
||||||
|
form_class = SetPasswordForm
|
||||||
|
redirect_to = "web:login"
|
||||||
|
token_generator = default_token_generator
|
||||||
|
|
||||||
|
def get_user(self):
|
||||||
|
try:
|
||||||
|
uidb64 = self.kwargs.get("uidb64")
|
||||||
|
uid = urlsafe_base64_decode(uidb64).decode()
|
||||||
|
user = User.objects.get(pk=uid)
|
||||||
|
except (
|
||||||
|
TypeError,
|
||||||
|
ValueError,
|
||||||
|
OverflowError,
|
||||||
|
User.DoesNotExist,
|
||||||
|
ValidationError,
|
||||||
|
):
|
||||||
|
user = None
|
||||||
|
return user
|
||||||
|
|
||||||
|
def generate_new_token_for_user(self, user):
|
||||||
|
return self.token_generator.make_token(user)
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
user = self.get_user()
|
||||||
|
valid_token = self.check_token(user)
|
||||||
|
new_token = self.generate_new_token_for_user(user)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"title": WebSettings.load().web_title,
|
||||||
|
"description": _("Establecer nueva contraseña"),
|
||||||
|
"form": self.form_class(user, {'token': new_token}),
|
||||||
|
"valid_token": valid_token,
|
||||||
|
"new_token": new_token,
|
||||||
|
}
|
||||||
|
|
||||||
|
def check_token(self, user):
|
||||||
|
token = self.kwargs.get("token")
|
||||||
|
valid_token = self.token_generator.check_token(user, token)
|
||||||
|
return valid_token
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
user = self.get_user()
|
||||||
|
form = self.form_class(user, request.POST)
|
||||||
|
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
return redirect(self.redirect_to)
|
||||||
|
return render(request, self.template_name, {})
|
||||||
|
|
||||||
|
|
||||||
class MyAccountView(TemplateView):
|
class MyAccountView(TemplateView):
|
||||||
@@ -143,4 +247,7 @@ logout = LogoutView.as_view()
|
|||||||
register = RegisterView.as_view()
|
register = RegisterView.as_view()
|
||||||
reset_password = ResetPasswordView.as_view()
|
reset_password = ResetPasswordView.as_view()
|
||||||
|
|
||||||
|
reset_password_confirm = ResetPasswordConfirmView.as_view()
|
||||||
|
reset_password_email_sent = ResetPasswordEmailSent.as_view()
|
||||||
|
|
||||||
my_account = MyAccountView.as_view()
|
my_account = MyAccountView.as_view()
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ from shop.models import (
|
|||||||
from shop.redsys import RedsysClient
|
from shop.redsys import RedsysClient
|
||||||
from shop.utils import create_order_from_cart
|
from shop.utils import create_order_from_cart
|
||||||
from web.forms import CreateOrderForm
|
from web.forms import CreateOrderForm
|
||||||
from web.mixins import PaginatedQuerysetMixin, FilteredQuerysetMixin
|
from web.mixins import FilteredQuerysetMixin, PaginatedQuerysetMixin
|
||||||
from web.models import WebSettings
|
from web.models import WebSettings
|
||||||
from web.settings import ANONYMOUS_CART_ID_COOKIE_NAME
|
from web.settings import ANONYMOUS_CART_ID_COOKIE_NAME
|
||||||
from web.utils import get_or_create_cart
|
from web.utils import get_or_create_cart
|
||||||
|
|||||||
Reference in New Issue
Block a user