feat: agrega rol 'publico' con UserProfile y permisos diferenciados

- Crea modelo UserProfile (OneToOne con User) con user_type: publico/user/administrator
- Señal post_save que crea UserProfile automáticamente al crear User
- UserSerializer.get_role() lee desde profile.user_type
- Nuevos permisos: IsNotPublico, IsPublico y actualiza IsAdministrator
- IsNotPublico restringe acceso a vistas de gestión (productos, clientes, ventas)
- CatalogSaleView.create permite publico; otras acciones requieren IsNotPublico
- UserProfile inline en admin de Usuarios
- Data migration para backfill de usuarios existentes
This commit is contained in:
2026-06-22 12:27:23 -05:00
parent 27b68a9ac2
commit 5b373bd15f
12 changed files with 177 additions and 15 deletions

View File

@@ -0,0 +1,25 @@
# Generated by Django 5.0.6 on 2026-06-22 17:26
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='UserProfile',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('user_type', models.CharField(choices=[('publico', 'Público'), ('user', 'Usuario'), ('administrator', 'Administrador')], default='user', max_length=20)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@@ -0,0 +1,24 @@
from django.db import migrations
def backfill_user_profiles(apps, schema_editor):
User = apps.get_model("auth", "User")
UserProfile = apps.get_model("users", "UserProfile")
for user in User.objects.all():
UserProfile.objects.get_or_create(
user=user,
defaults={
"user_type": "administrator" if user.is_staff else "user",
},
)
class Migration(migrations.Migration):
dependencies = [
('users', '0001_initial'),
]
operations = [
migrations.RunPython(backfill_user_profiles, migrations.RunPython.noop),
]