Browse Source

Funcionalidad para política de privacidad

politica
Celestino Rey 8 months ago
parent
commit
ef8a0b37d0
21 changed files with 312 additions and 13 deletions
  1. +1
    -1
      JugarAlPadel/K8S/Makefile
  2. +62
    -0
      JugarAlPadel/README.md
  3. +5
    -0
      JugarAlPadel/gestion_reservas/gestion_reservas/context_processors.py
  4. +13
    -4
      JugarAlPadel/gestion_reservas/gestion_reservas/settings.py
  5. +3
    -1
      JugarAlPadel/gestion_reservas/gestion_reservas/urls.py
  6. +5
    -0
      JugarAlPadel/gestion_reservas/gestion_reservas/views.py
  7. +2
    -1
      JugarAlPadel/gestion_reservas/reymotausers/admin.py
  8. +3
    -0
      JugarAlPadel/gestion_reservas/reymotausers/apps.py
  9. +0
    -1
      JugarAlPadel/gestion_reservas/reymotausers/forms.py
  10. +11
    -0
      JugarAlPadel/gestion_reservas/reymotausers/management/commands/desactiva_usuarios.py
  11. +14
    -0
      JugarAlPadel/gestion_reservas/reymotausers/management/commands/enviar_correos_reactivacion.py
  12. +11
    -0
      JugarAlPadel/gestion_reservas/reymotausers/management/commands/reactiva_usuarios.py
  13. +16
    -1
      JugarAlPadel/gestion_reservas/reymotausers/models.py
  14. +11
    -0
      JugarAlPadel/gestion_reservas/reymotausers/signals.py
  15. +2
    -1
      JugarAlPadel/gestion_reservas/reymotausers/urls.py
  16. +31
    -0
      JugarAlPadel/gestion_reservas/reymotausers/utils.py
  17. +34
    -2
      JugarAlPadel/gestion_reservas/reymotausers/views.py
  18. +4
    -1
      JugarAlPadel/gestion_reservas/templates/_footer.html
  19. +57
    -0
      JugarAlPadel/gestion_reservas/templates/politica_privacidad.html
  20. +19
    -0
      JugarAlPadel/gestion_reservas/templates/registration/reactivar_cuenta.html
  21. +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.42
export IMG_NGINX_VERSION = 2.3
# limpia todo


+ 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

+ 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}

+ 13
- 4
JugarAlPadel/gestion_reservas/gestion_reservas/settings.py View File

@ -14,6 +14,7 @@ from pathlib import Path
import os
import logging
APP_VERSION = "11.0.2"
# Build paths inside the project like this: BASE_DIR / 'subdir'.
@ -73,6 +74,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 +158,23 @@ 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'
# 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.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'


+ 3
- 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,6 +37,8 @@ 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'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


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

@ -6,6 +6,7 @@ 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 datetime import date
from django.http import HttpResponseForbidden
from rest_framework.decorators import api_view
@ -64,6 +65,10 @@ 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()})
#
# 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."""


+ 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-->

+ 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>[Nombre de la Organización]</strong>, con dirección en <strong>[Dirección]</strong> y correo electrónico <strong>[Email de contacto]</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>[Email de contacto]</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>[Email de contacto]</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