Compare commits

...

9 Commits

32 changed files with 540 additions and 59 deletions
Split View
  1. +1
    -1
      JugarAlPadel/K8S/Makefile
  2. +3
    -0
      JugarAlPadel/K8S/env-prod-configmap.yaml
  3. +11
    -1
      JugarAlPadel/K8S/jugaralpadel-deployment.yaml
  4. +57
    -0
      JugarAlPadel/POLITICA.md
  5. +62
    -0
      JugarAlPadel/README.md
  6. +2
    -0
      JugarAlPadel/gestion_reservas/eventos/urls.py
  7. +21
    -4
      JugarAlPadel/gestion_reservas/eventos/views.py
  8. +5
    -0
      JugarAlPadel/gestion_reservas/gestion_reservas/context_processors.py
  9. +21
    -7
      JugarAlPadel/gestion_reservas/gestion_reservas/settings.py
  10. +5
    -1
      JugarAlPadel/gestion_reservas/gestion_reservas/urls.py
  11. +25
    -7
      JugarAlPadel/gestion_reservas/gestion_reservas/views.py
  12. +2
    -1
      JugarAlPadel/gestion_reservas/reymotausers/admin.py
  13. +3
    -0
      JugarAlPadel/gestion_reservas/reymotausers/apps.py
  14. +0
    -1
      JugarAlPadel/gestion_reservas/reymotausers/forms.py
  15. +11
    -0
      JugarAlPadel/gestion_reservas/reymotausers/management/commands/desactiva_usuarios.py
  16. +14
    -0
      JugarAlPadel/gestion_reservas/reymotausers/management/commands/enviar_correos_reactivacion.py
  17. +11
    -0
      JugarAlPadel/gestion_reservas/reymotausers/management/commands/reactiva_usuarios.py
  18. +16
    -1
      JugarAlPadel/gestion_reservas/reymotausers/models.py
  19. +11
    -0
      JugarAlPadel/gestion_reservas/reymotausers/signals.py
  20. +2
    -1
      JugarAlPadel/gestion_reservas/reymotausers/urls.py
  21. +31
    -0
      JugarAlPadel/gestion_reservas/reymotausers/utils.py
  22. +34
    -2
      JugarAlPadel/gestion_reservas/reymotausers/views.py
  23. +2
    -1
      JugarAlPadel/gestion_reservas/templates/_branding.html
  24. +4
    -1
      JugarAlPadel/gestion_reservas/templates/_footer.html
  25. +21
    -0
      JugarAlPadel/gestion_reservas/templates/acerca_de.html
  26. +24
    -0
      JugarAlPadel/gestion_reservas/templates/base.html
  27. +19
    -17
      JugarAlPadel/gestion_reservas/templates/eventos/detalle_evento.html
  28. +23
    -0
      JugarAlPadel/gestion_reservas/templates/eventos/estadisticas_usuarios.html
  29. +15
    -13
      JugarAlPadel/gestion_reservas/templates/eventos/lista_eventos.html
  30. +57
    -0
      JugarAlPadel/gestion_reservas/templates/politica_privacidad.html
  31. +19
    -0
      JugarAlPadel/gestion_reservas/templates/registration/reactivar_cuenta.html
  32. +8
    -0
      JugarAlPadel/gestion_reservas/templates/registration/signup.html

+ 1
- 1
JugarAlPadel/K8S/Makefile View File

@ -1,7 +1,7 @@
export ARQUITECTURA := $(shell lscpu |grep itectur | tr -d ' '| cut -f2 -d':')
export REGISTRY=registry.reymota.es
export IMG_VERSION = 0.70.22
export IMG_VERSION = 0.70.60
export IMG_NGINX_VERSION = 2.3
# limpia todo


+ 3
- 0
JugarAlPadel/K8S/env-prod-configmap.yaml View File

@ -1,6 +1,9 @@
apiVersion: v1
data:
DEBUG: "False"
TESTING: "True"
APP_VERSION: 12.0.0
DATABASE: postgres
kind: ConfigMap
metadata:
labels:


+ 11
- 1
JugarAlPadel/K8S/jugaralpadel-deployment.yaml View File

@ -39,13 +39,23 @@ spec:
name: jugaralpadel
image: $REGISTRY/jugaralpadel-$ARQUITECTURA:$IMG_VERSION
env:
- name: VERSION
- name: IMG_VERSION
value: "$IMG_VERSION"
- name: APP_VERSION
valueFrom:
configMapKeyRef:
key: APP_VERSION
name: env-prod
- name: DEBUG
valueFrom:
configMapKeyRef:
key: DEBUG
name: env-prod
- name: TESTING
valueFrom:
configMapKeyRef:
key: TESTING
name: env-prod
ports:
- containerPort: 8000
protocol: TCP


+ 57
- 0
JugarAlPadel/POLITICA.md View File

@ -0,0 +1,57 @@
# Notas de la versión
Los cambios presentes en esta rama eran, principalmente, para incluir una página con la política de privacidad.
Además, incluía alguna otra mejora, como las estadísticas de usuario y un Acerca de.
Estas dos últimas no descarto pasarlas a la rama main.
Finalmente, después de preparar todo para el lanzamiento, Mónica decidió no incluirlo ya que no merecía la pena.
## Correo para probar los cambios sobre política de privacidad.
### ¿Qué tengo que hacer?
- Desactivar usuarios
- Enviar correo de reactivación
### ¿Qué tienen que probar?
- Que no tienen acceso a la web.
- Que reciben un correo con las instrucciones
- Que leen la política de privacidad y envían comentarios o que está correcto.
- Que una vez seguidas vuelven a tener acceso
-
### Testers:
melsilgar@hotmail.com
sergiofer0307@gmail.com
monvega67@gmail.com
padelycervezas1974@gmail.com
Hola,
Gracias por participar en la prueba de las nuevas funcionalidades de la aplicación de reservas de pozos.
Vamos a trabajar sobre un entorno de desarrollo cuya direccion es http://jalp.reymota.es
Hay dos cambios importantes:
1. La direccion de correo del administrador ahora es admin@jugaralpadel.es con lo que tienes que asegurarte de que esta direccion no aparece en el buzón de no deseados de tu correo.
2. Hemos introducido una página con la política de privacidad. Cuando un usuario nuevo se registre, tendrá que aceptar la política para poder darse de alta. Para los que ya estamos, necesitamos ‘forzar’ la desconexión de vuestra cuenta y volver a activarla. Para ello, vais a recibir un correo de la direccion de arriba (punto 1) con las instrucciones. Básicamente, tenéis que seguir el enlace y aceptar la política.
¿Qué tenéis que probar?
1. Durante el día de hoy, lunes 21 de abril de 2025, tendréis acceso a la web http://jalp.reymota.es. Vuestras credenciales son las mismas que la página oficial. Simplemente verificad que podéis entrar y ver los pozos que hay. ¡Ojo! Son datos antiguos, no son los reales.
2. Mañana día 22 de abril de 2025 tenéis que comprobar que NO tenéis acceso a la página http://jalp.reymota.es
3. En la tarde del día 22, deberíais recibir el correo desde la direccion admin@jugaralpadel.es con instrucciones de cómo aceptar la política de privacidad.
4. Comprobad que pincháis en el enlace y este os lleva a una página donde tenéis que marcar que aceptáis la política de privacidad. Leedla y enviadnos comentarios o que os parece bien.
5. Verificad que, una vez seguido el enlace y aceptado la política, volvéis a tener acceso a la página http://jalp.reymota.es.
Esto es para probar que todo funciona bien. Cuando esté terminada la prueba, lo haremos desde la página oficial y volveréis a recibir el correo con las instrucciones y tal, pero esta vez desde la direccion https://jugaralpade.es. El correo ya va a ser siempre admin@jugaralpadel.es
Para cualquier duda, ya sabéis donde estoy.

+ 62
- 0
JugarAlPadel/README.md View File

@ -65,3 +65,65 @@ Contiene una mejora en la lista de eventos, que ya no es lista sino cajas con fo
![0.27](https://gogs.reymota.es/attachments/2ea8f931-8623-441f-81d7-bca5657dd98b)
## Generación de la tabla
Con la modificación para generar una tabla con el perfil de usuario, hay que ejecutar migraciones lo primero
Desde dentro del contenedor:
./manage.py makemigrations
./manage.py migrate
A partir de ahora, cada vez que se cree un usuario nuevo, se genera una entrada en la tabla de PerfilUsuario.
Para crear las entradas en dicha tabla para los usuarios ya activos, hay que entrar en la shell de python y ejecutar unos comandos:
python manage.py shell
from reymota.models import UsuarioPersonalizado, PerfilUsuario
usuarios_sin_perfil = UsuarioPersonalizado.objects.filter(perfilusuario__isnull=True)
for usuario in usuarios_sin_perfil:
PerfilUsuario.objects.create(usuario=usuario)
print(f"Perfil creado para {usuario.nombre}")
## Política de privacidad
Pasos para solicitar la aceptación de la política de privacidad.
1. Desactivar usuarios (menos los que son administradores -staff-)
2. Enviar correo con enlace para aceptar la política
### Desactivar usuarios
Entrar en el contenedor
kubectl -n jugaralpadel exec -it deployment.apps/jugaralpadel -- bash
y desde la shell:
./manage.py desactiva_usuarios
Una vez hecho esto, hay que generar el correo, pero antes hay que asegurarse que DEBUG=False, para que la SITE_URL apunte correctamente
# Configuración de correo con Gmail
if DEBUG is True:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
SITE_URL = "http://jugaralpadel.rancher.reymota.lab"
else:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
SITE_URL = "http://jugaralpadel.es"
y luego:
./manage.py enviar_correos_reactivacion
### Reactivar usuarios
Si queremos reactivar todos los usuarios:
./manage.py reactiva_usuarios

+ 2
- 0
JugarAlPadel/gestion_reservas/eventos/urls.py View File

@ -36,4 +36,6 @@ urlpatterns = [
path('api/noticias/', api_lista_noticias, name='api_lista_noticias'),
path('api/noticias/<int:noticia_id>/', api_detalle_noticia, name='api_detalle_noticia'),
path("estadisticas/usuarios/", views.estadisticas_por_usuario, name="estadisticas_por_usuario"),
]

+ 21
- 4
JugarAlPadel/gestion_reservas/eventos/views.py View File

@ -21,6 +21,11 @@ from .serializers import EventoSerializer, ReservaSerializer, ListaEsperaSeriali
from .models import Evento, Reserva, ListaEspera, Noticia
from .forms import ListaEsperaForm, EventoForm, MensajeCorreoForm
from django.contrib.auth import get_user_model
from django.db.models import Count
User = get_user_model()
logger = logging.getLogger(__name__)
@ -87,8 +92,6 @@ def publicar_evento(request, evento_id):
@login_required
def lista_eventos(request):
# anno_actual = timezone.now().year
# Solo mostrar los eventos publicados a los usuarios normales
if request.user.is_staff:
eventos = Evento.objects.all().order_by('-fecha', '-hora')
@ -106,6 +109,10 @@ def lista_eventos(request):
else:
en_espera = False
# comprobar si el evento es pasado ya
evento_es_pasado = evento.fecha < timezone.now().date()
eventos_con_reserva.append({
'evento': evento,
'inscrito': inscrito,
@ -118,7 +125,8 @@ def lista_eventos(request):
'en_espera': en_espera,
'usuario': request.user,
'publicado': evento.publicado,
'url_imagen': evento.url_imagen
'url_imagen': evento.url_imagen,
'evento_es_pasado': evento_es_pasado
})
return render(request, 'eventos/lista_eventos.html', {'eventos_con_reserva': eventos_con_reserva})
@ -140,6 +148,8 @@ def detalle_evento(request, evento_id):
evento = get_object_or_404(Evento, pk=evento_id)
evento_es_pasado = evento.fecha < timezone.now().date()
reservas = Reserva.objects.filter(evento=evento_id)
inscrito = Reserva.objects.filter(evento=evento, usuario=request.user).exists() if request.user.is_authenticated else False
@ -164,7 +174,8 @@ def detalle_evento(request, evento_id):
'en_espera': en_espera,
'usuario': request.user,
'publicado': evento.publicado,
'url_imagen': evento.url_imagen
'url_imagen': evento.url_imagen,
'evento_es_pasado': evento_es_pasado
}
)
@ -357,3 +368,9 @@ def enviar_correo_inscritos(request, evento_id):
return render(request, 'eventos/enviar_correo_inscritos.html', {'form': form, 'evento': evento})
@user_passes_test(es_admin)
def estadisticas_por_usuario(request):
usuarios = User.objects.annotate(num_eventos=Count("reserva__evento")).order_by("-num_eventos")
return render(request, "eventos/estadisticas_usuarios.html", {"usuarios": usuarios})

+ 5
- 0
JugarAlPadel/gestion_reservas/gestion_reservas/context_processors.py View File

@ -1,7 +1,12 @@
from django.conf import settings
from datetime import date
def app_version(request):
return {
'APP_VERSION': settings.APP_VERSION
}
def base_context(request):
return {'year': date.today().year}

+ 21
- 7
JugarAlPadel/gestion_reservas/gestion_reservas/settings.py View File

@ -14,7 +14,9 @@ from pathlib import Path
import os
import logging
APP_VERSION = "11.0.2"
APP_NAME = "Jugaralpadel.es"
APP_VERSION = os.environ.get("APP_VERSION", "0.0.0-dev") # Valor por defecto si no está definido
IMG_VERSION = os.environ.get("IMG_VERSION", "0.0.0-dev") # Valor por defecto si no está definido
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
@ -28,9 +30,10 @@ SECRET_KEY = 'hey'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.environ["DEBUG"] == 'True'
TESTING = os.environ["TESTING"] == 'True'
ALLOWED_HOSTS = [".ocp-cluster.reymota.lab", "jugaralpadel.rancher.reymota.lab", "jugaralpadel.es"]
CSRF_TRUSTED_ORIGINS = ["https://*.ocp-cluster.reymota.lab", "http://jugaralpadel.rancher.reymota.lab", "https://jugaralpadel.rancher.reymota.lab", "https://jugaralpadel.es"]
ALLOWED_HOSTS = [".ocp-cluster.reymota.lab", "jugaralpadel.rancher.reymota.lab", "jugaralpadel.es", ".reymota.es"]
CSRF_TRUSTED_ORIGINS = ["https://*.ocp-cluster.reymota.lab", "http://jugaralpadel.rancher.reymota.lab", "https://jugaralpadel.rancher.reymota.lab", "https://jugaralpadel.es", "http://*.reymota.es"]
# Application definition
@ -73,6 +76,7 @@ TEMPLATES = [
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'gestion_reservas.context_processors.app_version',
'gestion_reservas.context_processors.base_context',
],
'libraries': {
'filtros_de_entorno': 'gestion_reservas.templatetags.filtros_de_entorno',
@ -156,16 +160,26 @@ MEDIA_URL = '/media/'
# Configuración de correo con Gmail
if DEBUG is True:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
SITE_URL = "http://jugaralpadel.rancher.reymota.lab"
else:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
SITE_URL = "http://jugaralpadel.es"
EMAIL_HOST = 'smtp.gmail.com'
if TESTING is True:
SITE_URL = "http://jalp.reymota.es"
# EMAIL_HOST = 'smtp.gmail.com'
# EMAIL_HOST_USER = 'jugaralpadelentreamigos@gmail.com'
# EMAIL_HOST_PASSWORD = 'btjnlcliimxcnmhi' # Es mejor usar una contraseña de aplicación de Google
# DEFAULT_FROM_EMAIL = 'jugaralpadelentreamigos@gmail.com'
EMAIL_HOST = 'smtp.ionos.es'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'jugaralpadelentreamigos@gmail.com'
EMAIL_HOST_PASSWORD = 'btjnlcliimxcnmhi' # Es mejor usar una contraseña de aplicación de Google
DEFAULT_FROM_EMAIL = 'jugaralpadelentreamigos@gmail.com'
EMAIL_HOST_USER = 'admin@jugaralpadel.es'
EMAIL_HOST_PASSWORD = 'qunkik-mefGen-9wawku' # Es mejor usar una contraseña de aplicación de Google
DEFAULT_FROM_EMAIL = 'admin@jugaralpadel.es'
# Dirección del administrador
# ADMIN_EMAIL = 'king.bernard.b@gmail.com'


+ 5
- 1
JugarAlPadel/gestion_reservas/gestion_reservas/urls.py View File

@ -21,7 +21,7 @@ from django.conf import settings
from django.views.generic.base import TemplateView # new
from . import views
from .views import api_lista_ayuda
from .views import api_lista_ayuda, politica_privacidad
urlpatterns = [
@ -37,7 +37,11 @@ urlpatterns = [
path('entorno/', views.ver_variables_entorno, name='ver_variables_entorno'),
path('ayuda/', views.ayuda, name='ayuda'),
path('politica-privacidad/', views.politica_privacidad, name='politica_privacidad'),
path('api/ayuda/', api_lista_ayuda, name='api_lista_ayuda'),
path("acerca-de/", views.acerca_de, name="acerca_de"),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

+ 25
- 7
JugarAlPadel/gestion_reservas/gestion_reservas/views.py View File

@ -1,21 +1,26 @@
from rest_framework.response import Response
from django.utils import timezone
from rest_framework import status
# Imports
from datetime import date
import os
from django.conf import settings
from django.contrib.auth.decorators import user_passes_test
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseForbidden
from django.shortcuts import render, get_object_or_404
from django.utils import timezone
from eventos.models import Noticia, Evento
from .models import Ayuda
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from eventos.models import Noticia, Evento
from .serializers import AyudaSerializer
from .models import Ayuda
import markdown # Importa la biblioteca de markdown
import os
@user_passes_test(lambda u: u.is_staff)
def ver_variables_entorno(request):
@ -64,6 +69,19 @@ def ayuda(request):
return render(request, 'ayuda.html', {'elementos': elementos_ayuda, 'apartados': apartados})
def politica_privacidad(request):
return render(request, 'politica_privacidad.html', {'fecha_actual': date.today()})
def acerca_de(request):
context = {
"app_name": settings.APP_NAME,
"app_version": settings.APP_VERSION,
"img_version": settings.IMG_VERSION
}
return render(request, "acerca_de.html", context)
#
# API
#


+ 2
- 1
JugarAlPadel/gestion_reservas/reymotausers/admin.py View File

@ -1,6 +1,7 @@
from django.contrib import admin
from django.core.mail import send_mail
from django.contrib import messages
from django.conf import settings
from django.contrib.auth.admin import UserAdmin
@ -16,7 +17,7 @@ def enviar_email_prueba(modeladmin, request, queryset):
send_mail(
'Correo de Prueba',
'Este es un correo de prueba desde el panel de administración.',
'jugaralpadelentreamigos@gmail.com', # Remitente
settings.DEFAULT_FROM_EMAIL,
[user.email], # Destinatario
fail_silently=False,
)


+ 3
- 0
JugarAlPadel/gestion_reservas/reymotausers/apps.py View File

@ -4,3 +4,6 @@ from django.apps import AppConfig
class ReymotausersConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'reymotausers'
def ready(self):
import reymotausers.signals

+ 0
- 1
JugarAlPadel/gestion_reservas/reymotausers/forms.py View File

@ -5,7 +5,6 @@ from .models import ReyMotaUser
class ReyMotaUserCreationForm(UserCreationForm):
class Meta:
model = ReyMotaUser
fields = ("email", "nombre", "foto")


+ 11
- 0
JugarAlPadel/gestion_reservas/reymotausers/management/commands/desactiva_usuarios.py View File

@ -0,0 +1,11 @@
from django.core.management.base import BaseCommand
from reymotausers.models import ReyMotaUser
class Command(BaseCommand):
help = "Desactivar usuarios antiguos antes de la política de privacidad"
def handle(self, *args, **kwargs):
usuarios_actualizados = ReyMotaUser.objects.filter(is_active=True, is_staff=False).update(is_active=False)
self.stdout.write(self.style.SUCCESS(f"Usuarios desactivados: {usuarios_actualizados}"))

+ 14
- 0
JugarAlPadel/gestion_reservas/reymotausers/management/commands/enviar_correos_reactivacion.py View File

@ -0,0 +1,14 @@
from django.core.management.base import BaseCommand
from reymotausers.models import ReyMotaUser
from reymotausers.utils import enviar_correo_reactivacion
class Command(BaseCommand):
help = "Enviar correos a usuarios desactivados para aceptar la política de privacidad"
def handle(self, *args, **kwargs):
usuarios = ReyMotaUser.objects.filter(is_active=False)
for usuario in usuarios:
enviar_correo_reactivacion(usuario)
self.stdout.write(self.style.SUCCESS(f"Correos enviados a {usuarios.count()} usuarios."))

+ 11
- 0
JugarAlPadel/gestion_reservas/reymotausers/management/commands/reactiva_usuarios.py View File

@ -0,0 +1,11 @@
from django.core.management.base import BaseCommand
from reymotausers.models import ReyMotaUser
class Command(BaseCommand):
help = "Reactivar usuarios"
def handle(self, *args, **kwargs):
usuarios_actualizados = ReyMotaUser.objects.filter(is_active=False, is_staff=False).update(is_active=True)
self.stdout.write(self.style.SUCCESS(f"Usuarios reactivados: {usuarios_actualizados}"))

+ 16
- 1
JugarAlPadel/gestion_reservas/reymotausers/models.py View File

@ -1,9 +1,11 @@
from django.db import models
# Create your models here.
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from .managers import ReyMotaUserManager
from django.conf import settings
import uuid
# Create your models here.
@ -22,3 +24,16 @@ class ReyMotaUser(AbstractBaseUser, PermissionsMixin):
def __str__(self):
return self.email
class PerfilUsuario(models.Model):
usuario = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="perfilusuario")
acepto_politica = models.BooleanField(default=True)
token_activacion = models.UUIDField(default=uuid.uuid4, unique=True, null=True, blank=True)
def generar_nuevo_token(self):
self.token_activacion = uuid.uuid4()
self.save()
def __str__(self):
return f"Perfil de {self.usuario}"

+ 11
- 0
JugarAlPadel/gestion_reservas/reymotausers/signals.py View File

@ -0,0 +1,11 @@
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
from .models import PerfilUsuario, ReyMotaUser
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def crear_perfil(sender, instance, created, **kwargs):
if created:
PerfilUsuario.objects.create(usuario=instance)

+ 2
- 1
JugarAlPadel/gestion_reservas/reymotausers/urls.py View File

@ -1,9 +1,10 @@
from django.urls import path
from . import views
from .views import api_lista_usuarios, api_detalle_usuario
from .views import api_lista_usuarios, api_detalle_usuario, reactivar_cuenta
urlpatterns = [
path('api/usuarios/', api_lista_usuarios, name='api_lista_usuarios'),
path('api/usuarios/<int:usuario_id>/', api_detalle_usuario, name='api_detalle_usuario'),
path("reactivar/<uuid:token>/", reactivar_cuenta, name="reactivar_cuenta"),
]

+ 31
- 0
JugarAlPadel/gestion_reservas/reymotausers/utils.py View File

@ -0,0 +1,31 @@
from django.core.mail import send_mail
from django.conf import settings
from django.urls import reverse
def enviar_correo_reactivacion(usuario):
perfil = usuario.perfilusuario
perfil.generar_nuevo_token() # Generar un nuevo token
enlace = f"{settings.SITE_URL}{reverse('reactivar_cuenta', args=[perfil.token_activacion])}"
asunto = "Reactivación de tu cuenta - Política de Privacidad"
mensaje = f"""
Hola {usuario.nombre},
Para cumplir con la nueva normativa de privacidad, hemos desactivado temporalmente tu cuenta.
Por favor, acepta la política de privacidad en el siguiente enlace para volver a activarla:
{enlace}
Saludos,
El equipo de soporte
"""
send_mail(
asunto,
mensaje,
settings.DEFAULT_FROM_EMAIL,
[usuario.email]
)

+ 34
- 2
JugarAlPadel/gestion_reservas/reymotausers/views.py View File

@ -1,15 +1,47 @@
from django.shortcuts import render
from django.shortcuts import render, redirect, get_object_or_404
from rest_framework.response import Response
from rest_framework.decorators import api_view
from .serializers import ReyMotaUserSerializer
from .models import ReyMotaUser
from .models import ReyMotaUser, PerfilUsuario
from django.contrib import messages
# Create your views here.
def reactivar_cuenta(request, token):
# Buscar el perfil sin generar error 404
perfil = PerfilUsuario.objects.filter(token_activacion=token).first()
if not perfil:
messages.error(request, "❌ Este enlace ya ha sido utilizado o es invalido.")
return redirect("login")
usuario = perfil.usuario
if request.method == "POST":
if perfil.acepto_politica:
messages.error(request, "❌ Este enlace ya ha sido utilizado.")
return redirect("login")
# Marcar que el usuario ha aceptado la política
perfil.acepto_politica = True
perfil.token_activacion = None # Eliminar el token para que no se pueda reutilizar
perfil.save()
usuario.is_active = True
usuario.save()
messages.success(request, "Tu cuenta ha sido reactivada correctamente.")
return redirect("login")
return render(request, "registration/reactivar_cuenta.html", {"usuario": usuario})
@api_view(['GET'])
def api_lista_usuarios(request):
"""Devuelve la lista de todos los usuarios."""


+ 2
- 1
JugarAlPadel/gestion_reservas/templates/_branding.html View File

@ -3,6 +3,7 @@
{% load filtros_de_entorno %}
<div class="app-branding">
<a class="app-logo" href="{% url 'principal' %}"><img class="logo-icon me-2" src="{% static 'images/palapadel.svg' %}" alt="logo"><span class="logo-text">JUGAR AL PADEL</span><span style="color: blue; font-size: 14px;"> v {{ "VERSION"|muestra_version }}</span></a>
<a class="app-logo" href="{% url 'principal' %}"><img class="logo-icon me-2" src="{% static 'images/palapadel.svg' %}" alt="logo"><span class="logo-text">JUGAR AL PADEL</span></a>
<span style="color: blue; font-size: 14px;">Versión: {{ APP_VERSION }}</span></a>
</div><!--//app-branding-->

+ 4
- 1
JugarAlPadel/gestion_reservas/templates/_footer.html View File

@ -7,4 +7,7 @@
<div class="container text-center py-3">
<small class="copyright">(c) <a class="app-link" href="mailto:creylopez@yahoo.es" target="_blank">Celestino Rey</a></small>
</div>
<!--</footer>//app-auth-footer-->
<div class="container text-center py-3">
<small class="copyright"> <a class="app-link" href="{% url 'politica_privacidad' %}" target="_blank">Política de privacidad</a></small>
</div>
<!--</footer>//app-auth-footer-->

+ 21
- 0
JugarAlPadel/gestion_reservas/templates/acerca_de.html View File

@ -0,0 +1,21 @@
{% extends "base.html" %}
{% block content %}
<div class="container-xl">
<h1 class="app-page-title">Acerca de...</h1>
<div class="row g-4">
<div class="col-12 col-md-6">
<div class="app-card app-card-basic d-flex flex-column align-items-start shadow-sm">
<div class="app-card-body px-4">
<ul class="list-unstyled">
<li><strong>Nombre de la aplicación:</strong> {{ app_name }}</li>
<li><strong>Versión:</strong> {{ app_version }}</li>
<li><strong>Versión de la imagen:</strong> {{ img_version }}</li>
</ul>
</div><!--//app-card-body-->
</div><!--//app-card-->
</div><!--//col-->
</div><!--//row-->
</div>
{% endblock %}

+ 24
- 0
JugarAlPadel/gestion_reservas/templates/base.html View File

@ -122,6 +122,17 @@
<span class="nav-link-text">Crear un nuevo evento</span>
</a><!--//nav-link-->
</li><!--//nav-item-->
<li class="nav-item"></li>
<a class="nav-link" href="{% url 'eventos:estadisticas_por_usuario' %}">
<span class="nav-icon">
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-bar-chart-line" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M11 2a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v12h.5a.5.5 0 0 1 0 1H.5a.5.5 0 0 1 0-1H1v-3a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v3h1V7a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v7h1V2zm1 12h2V2h-2v12zm-3 0V7H7v7h2zm-5 0v-3H2v3h2z"/>
</svg>
</span>
<span class="nav-link-text">Estadísticas por usuario</span>
</a><!--//nav-link-->
</li><!--//nav-item-->
{% endif %}
@ -138,6 +149,19 @@
</a><!--//nav-link-->
</li><!--//nav-item-->
<li class="nav-item">
<!--//Bootstrap Icons: https://icons.getbootstrap.com/ -->
<a class="nav-link" href="{% url 'acerca_de' %}">
<span class="nav-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-exclamation-square" viewBox="0 0 16 16">
<path d="M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/>
<path d="M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0M7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0z"/>
</svg>
</span>
<span class="nav-link-text">Acerca de...</span>
</a><!--//nav-link-->
</li><!--//nav-item-->
</ul><!--//app-menu-->
</nav><!--//app-nav-->
</div><!--//sidepanel-inner-->


+ 19
- 17
JugarAlPadel/gestion_reservas/templates/eventos/detalle_evento.html View File

@ -43,26 +43,28 @@
</div><!--//row-->
<div class="col-auto">
{% if evento.evento.publicado or user.is_staff %} <!-- Solo mostrar eventos publicados a usuarios -->
{% if not evento.inscrito %}
{% if evento.plazas_restantes > 0 %}
<a class="btn btn-primary" href="{% url 'eventos:reservar_evento' evento.id %}">Reservar</a>
{% else %}
{% if not evento.en_espera %}
<a class="btn btn-warning" href="{% url 'eventos:apuntar_lista_espera' evento.evento.id %}">Apuntarse a la lista de espera</a>
{% if not evento.evento_es_pasado %}
{% if evento.evento.publicado or user.is_staff %} <!-- Solo mostrar eventos publicados a usuarios -->
{% if not evento.inscrito %}
{% if evento.plazas_restantes > 0 %}
<a class="btn btn-primary" href="{% url 'eventos:reservar_evento' evento.id %}">Reservar</a>
{% else %}
{% if not evento.en_espera %}
<a class="btn btn-warning" href="{% url 'eventos:apuntar_lista_espera' evento.evento.id %}">Apuntarse a la lista de espera</a>
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% if user.is_staff and not evento.evento.publicado %}
<a class="btn btn-danger" href="{% url 'eventos:publicar_evento' evento.id %}">Publicar</a>
{% endif %}
{% if user.is_staff and not evento.evento.publicado %}
<a class="btn btn-danger" href="{% url 'eventos:publicar_evento' evento.id %}">Publicar</a>
{% endif %}
{% if user.is_staff and evento.evento.publicado %}
<a href="{% url 'eventos:enviar_correo_inscritos' evento.id %}" class="btn btn-danger">
📧 Enviar correo a inscritos
</a>
{% if user.is_staff and evento.evento.publicado %}
<a href="{% url 'eventos:enviar_correo_inscritos' evento.id %}" class="btn btn-danger">
📧 Enviar correo a inscritos
</a>
{% endif %}
{% endif %}
</div>


+ 23
- 0
JugarAlPadel/gestion_reservas/templates/eventos/estadisticas_usuarios.html View File

@ -0,0 +1,23 @@
{% extends "base.html" %}
{% block content %}
<h2>Estadísticas de Inscripciones por Usuario</h2>
<table class="table table-bordered">
<thead>
<tr>
<th>Usuario</th>
<th>Eventos inscritos</th>
</tr>
</thead>
<tbody>
{% for usuario in usuarios %}
<tr>
<td>{{ usuario.get_full_name|default:usuario.nombre }}</td>
<td>{{ usuario.num_eventos }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

+ 15
- 13
JugarAlPadel/gestion_reservas/templates/eventos/lista_eventos.html View File

@ -62,19 +62,21 @@
</div>
<div class="d-grid gap-2 d-md-block">
{% if not evento.inscrito %}
{% if evento.plazas_restantes > 0 %}
<a class="btn btn-primary" href="{% url 'eventos:reservar_evento' evento.id %}">Reservar</a>
{% else %}
{% if not evento.en_espera %}
<button class="btn btn-warning" href="{% url 'eventos:apuntar_lista_espera' evento.evento.id %}">Lista de espera</button>
{% else %}
<a class="fs-4"><p>Ya estás en la lista de espera.</p></a>
{% endif %}
{% endif %}
{% else %}
<a class="fs-4"><p>Estás dentro.</p></a>
{% endif %}
{% if not evento.evento_es_pasado %}
{% if not evento.inscrito %}
{% if evento.plazas_restantes > 0 %}
<a class="btn btn-primary" href="{% url 'eventos:reservar_evento' evento.id %}">Reservar</a>
{% else %}
{% if not evento.en_espera %}
<button class="btn btn-warning" href="{% url 'eventos:apuntar_lista_espera' evento.evento.id %}">Lista de espera</button>
{% else %}
<a class="fs-4"><p>Ya estás en la lista de espera.</p></a>
{% endif %}
{% endif %}
{% else %}
<a class="fs-4"><p>Estás dentro.</p></a>
{% endif %}
{% endif %}
{% if user.is_staff and not evento.evento.publicado %}
<a class="btn btn-danger" href="{% url 'eventos:publicar_evento' evento.id %}">Publicar</a>


+ 57
- 0
JugarAlPadel/gestion_reservas/templates/politica_privacidad.html View File

@ -0,0 +1,57 @@
{% extends "base.html" %}
{% block content %}
<div class="container mt-4">
<h2>Política de Privacidad</h2>
<p>Última actualización: {{ fecha_actual }}</p>
<h3>1. Responsable del tratamiento</h3>
<p>El responsable del tratamiento de los datos personales es <strong>Raúl Fernández Suárez</strong>, con dirección en <strong>Calle Ravena, 7 - 28032 Madrid</strong> y correo electrónico <strong>admin@jugaralpadel.es</strong>.</p>
<h3>2. Datos que recopilamos</h3>
<p>Recopilamos los siguientes datos personales cuando te registras en nuestra plataforma y reservas eventos:</p>
<ul>
<li>Nombre y apellidos</li>
<li>Correo electrónico</li>
<li>Información sobre las reservas realizadas</li>
</ul>
<h3>3. Finalidad del tratamiento</h3>
<p>Utilizamos tus datos personales para:</p>
<ul>
<li>Gestionar las reservas en eventos</li>
<li>Enviarte confirmaciones y actualizaciones sobre los eventos</li>
<li>Enviar información relevante sobre la plataforma (solo si has dado tu consentimiento)</li>
</ul>
<h3>4. Base legal del tratamiento</h3>
<p>El tratamiento de tus datos se basa en:</p>
<ul>
<li>Tu consentimiento, que puedes retirar en cualquier momento</li>
<li>La necesidad de procesar datos para la ejecución de un contrato (gestión de eventos y reservas)</li>
<li>Obligaciones legales aplicables</li>
</ul>
<h3>5. ¿Cuánto tiempo guardamos los datos?</h3>
<p>Conservamos tus datos mientras tengas una cuenta en nuestra plataforma o hasta que solicites su eliminación.</p>
<h3>6. Derechos del usuario</h3>
<p>De acuerdo con el RGPD, tienes derecho a:</p>
<ul>
<li>Acceder a tus datos personales</li>
<li>Rectificar datos inexactos</li>
<li>Solicitar la eliminación de tus datos</li>
<li>Oponerte al tratamiento de datos para ciertos fines</li>
<li>Solicitar la portabilidad de tus datos</li>
</ul>
<p>Para ejercer estos derechos, contacta con nosotros en <strong>admin@jugaralpadel.es</strong>.</p>
<h3>7. Seguridad de los datos</h3>
<p>Aplicamos medidas de seguridad para proteger los datos contra accesos no autorizados, pérdidas o alteraciones.</p>
<h3>8. Contacto</h3>
<p>Si tienes preguntas sobre esta política, puedes contactarnos en <strong>admin@jugaralpadel.es</strong>.</p>
</div>
{% endblock %}

+ 19
- 0
JugarAlPadel/gestion_reservas/templates/registration/reactivar_cuenta.html View File

@ -0,0 +1,19 @@
{% extends "base.html" %}
{% block content %}
<div class="container">
<h2>Reactivar cuenta</h2>
<p>Hola, {{ usuario.nombre }}. Para continuar usando nuestra plataforma, debes aceptar la política de privacidad.</p>
<form method="post">
{% csrf_token %}
<label>
<input type="checkbox" name="aceptar_politica" required>
Acepto la <a href="{% url 'politica_privacidad' %}" target="_blank">Política de Privacidad</a>
</label>
<br><br>
<button type="submit" class="btn btn-success">Aceptar y Reactivar</button>
</form>
</div>
{% endblock %}

+ 8
- 0
JugarAlPadel/gestion_reservas/templates/registration/signup.html View File

@ -26,6 +26,14 @@
</p>
{% endfor %}
<div class="item border-bottom py-3"></div>
<div>
{{ form.aceptar_politica }}
<label for="{{ form.aceptar_politica.id_for_label }}">
Acepto la <a href="{% url 'politica_privacidad' %}" target="_blank">Política de Privacidad</a>
</label>
</div>
<div class="text-center">
<button type="submit" class="btn app-btn-primary w-100 theme-btn mx-auto">Sign Up</button>
</div>


Loading…
Cancel
Save