From 249521aa4a80e33484f5bf69bf8bf031686dd641 Mon Sep 17 00:00:00 2001 From: Pablo Moreno Date: Sat, 18 Jan 2025 13:55:33 +0100 Subject: [PATCH] feat: added user info form --- locale/es/LC_MESSAGES/django.po | 109 ++++++++++++++--------- nginx/nginx.conf | 1 + users/forms/info.py | 24 +++++ web/templates/components/users/info.html | 28 ++++++ web/templates/users/login.html | 2 +- web/templates/users/user_details.html | 9 +- web/urls.py | 16 +++- web/views/components.py | 38 ++++++++ web/views/users.py | 8 +- web/views/web.py | 4 +- 10 files changed, 186 insertions(+), 53 deletions(-) create mode 100644 users/forms/info.py create mode 100644 web/templates/components/users/info.html diff --git a/locale/es/LC_MESSAGES/django.po b/locale/es/LC_MESSAGES/django.po index 866d674..7da0a9d 100644 --- a/locale/es/LC_MESSAGES/django.po +++ b/locale/es/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-01-17 21:17+0100\n" -"PO-Revision-Date: 2025-01-17 21:23+0100\n" +"POT-Creation-Date: 2025-01-18 13:27+0100\n" +"PO-Revision-Date: 2025-01-18 13:28+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: es\n" @@ -688,11 +688,19 @@ msgstr "No se ha recibido ningún valor para Ds_MerchantParameters" msgid "No se ha realizado el pago. Motivo: {reason}" msgstr "No se ha realizado el pago. Motivo: {reason}" -#: .\users\forms\login.py:13 .\users\forms\register.py:14 -#: .\users\forms\reset_password.py:16 +#: .\users\forms\info.py:13 .\users\forms\login.py:13 +#: .\users\forms\register.py:14 .\users\forms\reset_password.py:16 msgid "pablo@shoppy.com" msgstr "pablo@shoppy.com" +#: .\users\forms\info.py:14 .\users\forms\register.py:15 +msgid "Pablo" +msgstr "Pablo" + +#: .\users\forms\info.py:15 .\users\forms\register.py:16 +msgid "Moreno" +msgstr "Moreno" + #: .\users\forms\login.py:26 msgid "Contraseña" msgstr "Contraseña" @@ -701,14 +709,6 @@ msgstr "Contraseña" msgid "Mantener sesión iniciada" msgstr "Mantener sesión iniciada" -#: .\users\forms\register.py:15 -msgid "Pablo" -msgstr "Pablo" - -#: .\users\forms\register.py:16 -msgid "Moreno" -msgstr "Moreno" - #: .\users\forms\reset_password.py:42 msgid "El token no es válido o ha expirado" msgstr "El token no es válido o ha expirado" @@ -810,7 +810,6 @@ msgid "Volver a inicio" msgstr "Volver a inicio" #: .\web\templates\components\cart\cart.html:80 -#: .\web\templates\users\user_details.html:67 #: .\web\templates\web\order.html:74 msgid "Dirección de envío" msgstr "Dirección de envío" @@ -824,7 +823,7 @@ msgstr "E-Mail" #: .\web\templates\components\cart\cart.html:111 #: .\web\templates\components\cart\cart.html:199 #: .\web\templates\components\cart\cart.html:204 -#: .\web\templates\users\user_details.html:40 +#: .\web\templates\users\user_details.html:39 msgid "Nombre completo" msgstr "Nombre completo" @@ -832,7 +831,7 @@ msgstr "Nombre completo" #: .\web\templates\components\cart\cart.html:122 #: .\web\templates\components\cart\cart.html:210 #: .\web\templates\components\cart\cart.html:216 -#: .\web\templates\users\user_details.html:46 +#: .\web\templates\users\user_details.html:45 msgid "Dirección" msgstr "Dirección" @@ -840,7 +839,7 @@ msgstr "Dirección" #: .\web\templates\components\cart\cart.html:136 #: .\web\templates\components\cart\cart.html:224 #: .\web\templates\components\cart\cart.html:230 -#: .\web\templates\users\user_details.html:72 +#: .\web\templates\users\user_details.html:61 msgid "Localidad" msgstr "Localidad" @@ -848,7 +847,7 @@ msgstr "Localidad" #: .\web\templates\components\cart\cart.html:150 #: .\web\templates\components\cart\cart.html:238 #: .\web\templates\components\cart\cart.html:244 -#: .\web\templates\users\user_details.html:52 +#: .\web\templates\users\user_details.html:51 msgid "Código postal" msgstr "Código postal" @@ -856,7 +855,7 @@ msgstr "Código postal" #: .\web\templates\components\cart\cart.html:165 #: .\web\templates\components\cart\cart.html:253 #: .\web\templates\components\cart\cart.html:259 -#: .\web\templates\users\user_details.html:76 +#: .\web\templates\users\user_details.html:65 msgid "Provincia" msgstr "Provincia" @@ -868,7 +867,6 @@ msgid "País" msgstr "País" #: .\web\templates\components\cart\cart.html:190 -#: .\web\templates\users\user_details.html:65 #: .\web\templates\web\order.html:89 msgid "Dirección de facturación" msgstr "Dirección de facturación" @@ -930,17 +928,17 @@ msgid "Ver carrito" msgstr "Ver carrito" #: .\web\templates\components\generic\navbar.html:22 -#: .\web\templates\components\generic\navbar.html:88 +#: .\web\templates\components\generic\navbar.html:90 msgid "Inicio" msgstr "Inicio" -#: .\web\templates\components\generic\navbar.html:53 +#: .\web\templates\components\generic\navbar.html:54 #: .\web\templates\components\users\user_dropdown.html:6 #: .\web\templates\users\user_details.html:10 msgid "Mi cuenta" msgstr "Mi cuenta" -#: .\web\templates\components\generic\navbar.html:76 +#: .\web\templates\components\generic\navbar.html:78 msgid "Abrir menú" msgstr "Abrir menú" @@ -953,10 +951,15 @@ msgid "Cerrar" msgstr "Cerrar" #: .\web\templates\components\products\list_filters.html:14 -#: .\web\templates\components\products\list_filters.html:23 +#: .\web\templates\components\products\list_filters.html:24 msgid "Buscar" msgstr "Buscar" +#: .\web\templates\components\users\info.html:24 +#| msgid "Editar datos" +msgid "Actualizar datos" +msgstr "Actualizar datos" + #: .\web\templates\components\users\user_dropdown.html:12 #: .\web\templates\web\orders.html:10 msgid "Mis pedidos" @@ -1056,19 +1059,19 @@ msgstr "Restablecer contraseña" msgid "Se te ha enviado un correo electrónico para restablecer tu contraseña" msgstr "Se te ha enviado un correo electrónico para restablecer tu contraseña" -#: .\web\templates\users\user_details.html:24 +#: .\web\templates\users\user_details.html:23 msgid "Mis direcciones" msgstr "Mis direcciones" -#: .\web\templates\users\user_details.html:32 +#: .\web\templates\users\user_details.html:31 msgid "No hay ninguna dirección" msgstr "No hay ninguna dirección" -#: .\web\templates\users\user_details.html:56 +#: .\web\templates\users\user_details.html:55 msgid "Teléfono" msgstr "Teléfono" -#: .\web\templates\users\user_details.html:90 +#: .\web\templates\users\user_details.html:79 msgid "Editar datos" msgstr "Editar datos" @@ -1128,55 +1131,59 @@ msgstr "Devuelto" msgid "Ver pedido" msgstr "Ver pedido" -#: .\web\urls.py:41 +#: .\web\urls.py:42 msgid "wishlist" msgstr "lista-deseados" -#: .\web\urls.py:42 +#: .\web\urls.py:42 .\web\urls.py:46 .\web\urls.py:65 .\web\urls.py:87 +msgid "/login/" +msgstr "/iniciar-sesion/" + +#: .\web\urls.py:43 msgid "categories//" msgstr "categorias//" -#: .\web\urls.py:43 +#: .\web\urls.py:44 msgid "products///" msgstr "productos///" -#: .\web\urls.py:44 +#: .\web\urls.py:45 msgid "cart/" msgstr "carrito/" -#: .\web\urls.py:45 +#: .\web\urls.py:46 msgid "orders/" msgstr "pedidos/" -#: .\web\urls.py:46 +#: .\web\urls.py:47 msgid "order//" msgstr "pedidos//" -#: .\web\urls.py:48 +#: .\web\urls.py:49 msgid "login/" msgstr "iniciar-sesion/" -#: .\web\urls.py:49 +#: .\web\urls.py:50 msgid "logout/" msgstr "cerrar-sesion/" -#: .\web\urls.py:50 +#: .\web\urls.py:51 msgid "register/" msgstr "crear-cuenta/" -#: .\web\urls.py:51 +#: .\web\urls.py:52 msgid "reset-password/" msgstr "restablecer-contraseña/" -#: .\web\urls.py:53 +#: .\web\urls.py:54 msgid "reset-password///" msgstr "restablecer-contrasena///" -#: .\web\urls.py:58 +#: .\web\urls.py:59 msgid "reset-password/email-sent/" msgstr "restablecer-contrasena/email-enviado/" -#: .\web\urls.py:62 +#: .\web\urls.py:64 msgid "my-account/" msgstr "mi-cuenta/" @@ -1201,6 +1208,26 @@ msgstr "Establecer nueva contraseña" msgid "{settings.web_title} - {category.name}" msgstr "{settings.web_title} - {category.name}" -#: .\web\views\web.py:82 +#: .\web\views\web.py:80 +#, python-brace-format +msgid "{web_settings.web_title} - Carrito" +msgstr "{web_settings.web_title} - Carrito" + +#: .\web\views\web.py:83 msgid "resumen del carrito" msgstr "resumen del carrito" + +#: .\web\views\web.py:169 .\web\views\web.py:170 +#, python-brace-format +msgid "{settings.web_title} - Comprar" +msgstr "{settings.web_title} - Comprar" + +#: .\web\views\web.py:190 +#, python-brace-format +msgid "{settings.web_title} - Lista de deseados" +msgstr "{settings.web_title} - Lista de deseados" + +#: .\web\views\web.py:209 +#, python-brace-format +msgid "{settings.web_title} - Mis pedidos" +msgstr "{settings.web_title} - Mis pedidos" diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 023ba9e..6c751de 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -34,6 +34,7 @@ server { add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + add_header Accept-Encoding "gzip, compress, br" # gzip gzip on; diff --git a/users/forms/info.py b/users/forms/info.py new file mode 100644 index 0000000..b932e74 --- /dev/null +++ b/users/forms/info.py @@ -0,0 +1,24 @@ +from django import forms +from django.contrib.auth import get_user_model +from django.utils.text import gettext_lazy as _ + +from web.mixins import StylingMixin + +User = get_user_model() + + +class UserInfoForm(StylingMixin, forms.ModelForm): + styled_fields = ("email", "first_name", "last_name") + placeholder_for_field = { + "email": _("pablo@shoppy.com"), + "first_name": _("Pablo"), + "last_name": _("Moreno"), + } + + class Meta: + model = User + fields = ( + "email", + "first_name", + "last_name", + ) diff --git a/web/templates/components/users/info.html b/web/templates/components/users/info.html new file mode 100644 index 0000000..39f9cb5 --- /dev/null +++ b/web/templates/components/users/info.html @@ -0,0 +1,28 @@ +{% load i18n %} +{% load static %} +
+ {% csrf_token %} + {% for field in form %} +
+ + + {{ field }} +
+ {% endfor %} + + {% for k, error in form.errors.items %} + {{ error }} + {% endfor %} + + + + +
diff --git a/web/templates/users/login.html b/web/templates/users/login.html index 848e9ae..0599506 100644 --- a/web/templates/users/login.html +++ b/web/templates/users/login.html @@ -17,7 +17,7 @@

{% translate 'Inicia sesión en tu cuenta' %}

-
+ {% csrf_token %} {% for field in form %} {% if field.id_for_label != 'id_remember_me' %} diff --git a/web/templates/users/user_details.html b/web/templates/users/user_details.html index a09c471..5c026d2 100644 --- a/web/templates/users/user_details.html +++ b/web/templates/users/user_details.html @@ -9,12 +9,11 @@ > {% translate 'Mi cuenta' %} +
-
-
-

- {{ user.first_name }} {{ user.last_name }}

-
diff --git a/web/urls.py b/web/urls.py index c5de0ff..8c210e1 100644 --- a/web/urls.py +++ b/web/urls.py @@ -9,6 +9,7 @@ from web.views.components import ( list_products, list_wishlisted_products, wishlist_button, + user_info_component, ) from web.views.users import ( login, @@ -38,11 +39,11 @@ app_name = "web" i18n_resolvers = i18n_patterns( path("", index, name="index"), - path(_("wishlist"), login_required(wishlist, login_url="/login/"), name="wishlist"), + path(_("wishlist"), login_required(wishlist, login_url=_("/login/")), name="wishlist"), path(_("categories//"), category_view, name="category_view"), path(_("products///"), product_detail, name="product_detail"), path(_("cart/"), cart_detail, name="cart_detail"), - path(_("orders/"), login_required(orders, login_url="/login/"), name="orders"), + path(_("orders/"), login_required(orders, login_url=_("/login/")), name="orders"), path(_("order//"), order_detail, name="order"), # users path(_("login/"), login, name="login"), @@ -59,7 +60,11 @@ i18n_resolvers = i18n_patterns( reset_password_email_sent, name="reset_password_email_sent", ), - path(_("my-account/"), my_account, name="my_account"), + path( + _("my-account/"), + login_required(my_account, login_url=_("/login/")), + name="my_account", + ), ) urlpatterns = [ @@ -77,6 +82,11 @@ urlpatterns = [ wishlist_button, name="wishlist_button", ), + path( + "web/components/user-info/", + login_required(user_info_component, login_url=_("/login/")), + name="user_info_component", + ), # api path("web/add-cart-item/", add_cart_item, name="add_cart_item"), path("web/delete-cart-item//", delete_cart_item, name="delete_cart_item"), diff --git a/web/views/components.py b/web/views/components.py index 2f95763..6c024c5 100644 --- a/web/views/components.py +++ b/web/views/components.py @@ -1,5 +1,6 @@ from decimal import Decimal +from django.http import HttpResponse from django.shortcuts import get_object_or_404, render from django.views.generic import TemplateView @@ -12,7 +13,9 @@ from shop.models import ( ShippingMethod, WishlistedProduct, ) +from users.forms.info import UserInfoForm from web.mixins import FilteredQuerysetMixin, PaginatedQuerysetMixin +from web.models import WebSettings from web.settings import ANONYMOUS_CART_ID_COOKIE_NAME from web.utils import get_or_create_cart @@ -142,6 +145,41 @@ class WishlistButton(TemplateView): } +class UserInfoComponentView(TemplateView): + template_name = "components/users/info.html" + form_class = UserInfoForm + + def get_context_data(self, **kwargs): + web_settings = WebSettings.load() + user = self.request.user + form = self.form_class( + initial={ + "email": user.email, + "first_name": user.first_name, + "last_name": user.last_name, + } + ) + + return { + "form": form, + } + + def post(self, request, *args, **kwargs): + user = self.request.user + form = self.form_class(request.POST) + + if form.is_valid(): + user.email = form.cleaned_data.get("email") + user.first_name = form.cleaned_data.get("first_name") + user.last_name = form.cleaned_data.get("last_name") + user.save() + return HttpResponse(status=200) + + return render(request, self.template_name, {"form": form}) + + list_products = ListProducts.as_view() list_wishlisted_products = ListWishlistedProducts.as_view() wishlist_button = WishlistButton.as_view() + +user_info_component = UserInfoComponentView.as_view() diff --git a/web/views/users.py b/web/views/users.py index 1739927..bb01de1 100644 --- a/web/views/users.py +++ b/web/views/users.py @@ -1,3 +1,5 @@ +import urllib + from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.auth import login as login_user @@ -6,7 +8,7 @@ from django.contrib.auth.tokens import default_token_generator from django.core.exceptions import ValidationError from django.db import IntegrityError from django.shortcuts import redirect, render, reverse -from django.utils.http import url_has_allowed_host_and_scheme, urlsafe_base64_decode +from django.utils.http import url_has_allowed_host_and_scheme, urlsafe_base64_decode, urlencode from django.utils.text import gettext_lazy as _ from django.views.generic import TemplateView, View @@ -29,6 +31,10 @@ class LoginView(View, RedirectionMixin): redirect_to = "web:index" login_form_class = LoginForm + def get_redirection(self): + query_param_string = urlencode(self.request.GET) + return f'{reverse(self.redirect_to)}?{query_param_string.join("")}' + def get_login_form(self, request): return self.login_form_class(data=request.POST) diff --git a/web/views/web.py b/web/views/web.py index 775cc9e..d500980 100644 --- a/web/views/web.py +++ b/web/views/web.py @@ -187,7 +187,7 @@ class WishlistView(TemplateView): def get_context_data(self, **kwargs): settings = WebSettings.load() return { - "title": settings.web_title, + "title": _(f"{settings.web_title} - Lista de deseados"), "description": settings.web_description, } @@ -206,7 +206,7 @@ class OrdersView(TemplateView, FilteredQuerysetMixin, PaginatedQuerysetMixin): page = self.get_paginated_queryset(qs) return { - "title": settings.web_title, + "title": _(f"{settings.web_title} - Mis pedidos"), "page": page, "has_next_page": page.has_next(), "has_previous_page": page.has_previous(),