fastapi-djauth 1.4.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. fastapi_djauth-1.4.1/.gitignore +10 -0
  2. fastapi_djauth-1.4.1/CHANGELOG.md +78 -0
  3. fastapi_djauth-1.4.1/CONTRIBUTING.md +62 -0
  4. fastapi_djauth-1.4.1/LICENSE +20 -0
  5. fastapi_djauth-1.4.1/PKG-INFO +133 -0
  6. fastapi_djauth-1.4.1/README.md +85 -0
  7. fastapi_djauth-1.4.1/SECURITY.md +23 -0
  8. fastapi_djauth-1.4.1/djauth/__init__.py +82 -0
  9. fastapi_djauth-1.4.1/djauth/__main__.py +98 -0
  10. fastapi_djauth-1.4.1/djauth/api.py +890 -0
  11. fastapi_djauth-1.4.1/djauth/backends.py +130 -0
  12. fastapi_djauth-1.4.1/djauth/core.py +1280 -0
  13. fastapi_djauth-1.4.1/djauth/database.py +148 -0
  14. fastapi_djauth-1.4.1/djauth/decorators.py +119 -0
  15. fastapi_djauth-1.4.1/djauth/errors.py +107 -0
  16. fastapi_djauth-1.4.1/djauth/fields.py +157 -0
  17. fastapi_djauth-1.4.1/djauth/hashers.py +54 -0
  18. fastapi_djauth-1.4.1/djauth/models.py +200 -0
  19. fastapi_djauth-1.4.1/djauth/plantilla/.dockerignore.tpl +8 -0
  20. fastapi_djauth-1.4.1/djauth/plantilla/.env.example.tpl +15 -0
  21. fastapi_djauth-1.4.1/djauth/plantilla/.github/workflows/ci.yml.tpl +22 -0
  22. fastapi_djauth-1.4.1/djauth/plantilla/.gitignore.tpl +12 -0
  23. fastapi_djauth-1.4.1/djauth/plantilla/Dockerfile.tpl +26 -0
  24. fastapi_djauth-1.4.1/djauth/plantilla/README.md.tpl +83 -0
  25. fastapi_djauth-1.4.1/djauth/plantilla/alembic.ini.tpl +39 -0
  26. fastapi_djauth-1.4.1/djauth/plantilla/migrations/env.py.tpl +52 -0
  27. fastapi_djauth-1.4.1/djauth/plantilla/migrations/script.py.mako.tpl +24 -0
  28. fastapi_djauth-1.4.1/djauth/plantilla/migrations/versions/0001_productos.py.tpl +35 -0
  29. fastapi_djauth-1.4.1/djauth/plantilla/pyproject.toml.tpl +46 -0
  30. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/__init__.py.tpl +3 -0
  31. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/api/__init__.py.tpl +0 -0
  32. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/api/deps.py.tpl +12 -0
  33. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/api/router.py.tpl +8 -0
  34. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/api/v1/__init__.py.tpl +0 -0
  35. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/api/v1/productos.py.tpl +74 -0
  36. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/core/__init__.py.tpl +0 -0
  37. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/core/config.py.tpl +41 -0
  38. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/core/security.py.tpl +50 -0
  39. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/db.py.tpl +41 -0
  40. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/main.py.tpl +52 -0
  41. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/models/__init__.py.tpl +5 -0
  42. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/models/producto.py.tpl +24 -0
  43. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/schemas/__init__.py.tpl +0 -0
  44. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/schemas/producto.py.tpl +36 -0
  45. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/services/__init__.py.tpl +0 -0
  46. fastapi_djauth-1.4.1/djauth/plantilla/src/__paquete__/services/productos.py.tpl +46 -0
  47. fastapi_djauth-1.4.1/djauth/plantilla/tests/__init__.py.tpl +0 -0
  48. fastapi_djauth-1.4.1/djauth/plantilla/tests/conftest.py.tpl +35 -0
  49. fastapi_djauth-1.4.1/djauth/plantilla/tests/test_app.py.tpl +42 -0
  50. fastapi_djauth-1.4.1/djauth/py.typed +0 -0
  51. fastapi_djauth-1.4.1/djauth/routers.py +404 -0
  52. fastapi_djauth-1.4.1/djauth/settings.py +127 -0
  53. fastapi_djauth-1.4.1/djauth/startproject.py +271 -0
  54. fastapi_djauth-1.4.1/djauth/static/account.html +51 -0
  55. fastapi_djauth-1.4.1/djauth/static/account.js +34 -0
  56. fastapi_djauth-1.4.1/djauth/static/admin.html +167 -0
  57. fastapi_djauth-1.4.1/djauth/static/admin.js +346 -0
  58. fastapi_djauth-1.4.1/djauth/static/common.js +99 -0
  59. fastapi_djauth-1.4.1/djauth/static/djauth.css +99 -0
  60. fastapi_djauth-1.4.1/djauth/static/login.html +26 -0
  61. fastapi_djauth-1.4.1/djauth/static/login.js +38 -0
  62. fastapi_djauth-1.4.1/djauth/static/reset.html +27 -0
  63. fastapi_djauth-1.4.1/djauth/static/reset.js +30 -0
  64. fastapi_djauth-1.4.1/djauth/validators.py +139 -0
  65. fastapi_djauth-1.4.1/docs/01-instalacion.md +51 -0
  66. fastapi_djauth-1.4.1/docs/02-configuracion.md +107 -0
  67. fastapi_djauth-1.4.1/docs/03-proteger-rutas.md +131 -0
  68. fastapi_djauth-1.4.1/docs/04-sesion-y-bearer.md +54 -0
  69. fastapi_djauth-1.4.1/docs/05-usuarios-grupos-permisos.md +82 -0
  70. fastapi_djauth-1.4.1/docs/06-backends.md +83 -0
  71. fastapi_djauth-1.4.1/docs/07-extender-usuario.md +74 -0
  72. fastapi_djauth-1.4.1/docs/08-administracion.md +32 -0
  73. fastapi_djauth-1.4.1/docs/09-errores.md +78 -0
  74. fastapi_djauth-1.4.1/docs/10-seguridad.md +40 -0
  75. fastapi_djauth-1.4.1/docs/11-comandos.md +30 -0
  76. fastapi_djauth-1.4.1/docs/12-api.md +59 -0
  77. fastapi_djauth-1.4.1/docs/13-desde-django.md +63 -0
  78. fastapi_djauth-1.4.1/docs/14-historial-de-cambios.md +115 -0
  79. fastapi_djauth-1.4.1/docs/15-bases-de-datos.md +266 -0
  80. fastapi_djauth-1.4.1/docs/16-nuevo-proyecto.md +99 -0
  81. fastapi_djauth-1.4.1/docs/17-varias-bases-y-routers.md +194 -0
  82. fastapi_djauth-1.4.1/docs/README.md +23 -0
  83. fastapi_djauth-1.4.1/examples/app.py +41 -0
  84. fastapi_djauth-1.4.1/llms.txt +59 -0
  85. fastapi_djauth-1.4.1/pyproject.toml +82 -0
  86. fastapi_djauth-1.4.1/tests/test_backends_fields_errors.py +283 -0
  87. fastapi_djauth-1.4.1/tests/test_database.py +94 -0
  88. fastapi_djauth-1.4.1/tests/test_decorators.py +141 -0
  89. fastapi_djauth-1.4.1/tests/test_djauth.py +443 -0
  90. fastapi_djauth-1.4.1/tests/test_engines.py +122 -0
  91. fastapi_djauth-1.4.1/tests/test_routers.py +262 -0
  92. fastapi_djauth-1.4.1/tests/test_startproject.py +101 -0
  93. fastapi_djauth-1.4.1/tests/test_user_history.py +213 -0
  94. fastapi_djauth-1.4.1/tests/test_username_field.py +89 -0
@@ -0,0 +1,10 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ dist/
4
+ build/
5
+ *.egg-info/
6
+ .venv/
7
+ *.sqlite3
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ uv.lock
@@ -0,0 +1,78 @@
1
+ # Cambios
2
+
3
+ El formato sigue [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/) y el proyecto usa [versionado semántico](https://semver.org/lang/es/).
4
+
5
+ ## [1.4.1] - 2026-11-11
6
+
7
+ ### Cambiado
8
+ - Los ejemplos de la documentación, la plantilla de `startproject`, las pruebas y el texto de ayuda del campo *Motivo del cambio* en la administración usan datos genéricos (empresa, sedes y producto de ejemplo).
9
+
10
+ ## [1.4.0] - 2026-11-11
11
+
12
+ Primera versión publicada en PyPI.
13
+
14
+ ### Corregido
15
+ - **MySQL, Oracle y SQL Server:** agregar columnas propias (`user_mixin`) a una tabla existente fallaba porque los nombres iban entre comillas dobles y se usaba `ADD COLUMN` en todos los motores. Ahora se usan las comillas y la sintaxis de cada motor.
16
+ - Un controlador asíncrono (`asyncpg`, `aiomysql`…) se rechaza al arrancar con un error claro, en lugar de fallar después. Ya no se elige `asyncpg` automáticamente.
17
+ - **Oracle** no funcionaba: las claves primarias no se generaban (ahora usan `IDENTITY`) y los textos vacíos fallaban, porque Oracle guarda `''` como NULL. Ahora esos textos admiten NULL solo en Oracle y se leen como `''`, igual que hace Django.
18
+ - Las claves primarias usan `IDENTITY` en PostgreSQL, Oracle y SQL Server para las tablas nuevas. Las tablas existentes no cambian.
19
+
20
+ ### Cambiado
21
+ - Versión mínima de SQLAlchemy: 2.0.24, la primera que escapa `#` en las contraseñas al mostrar la URL de conexión.
22
+ - El paquete declara sus tipos (`py.typed`) y pasa `mypy`.
23
+ - Nuevos extras `mssql` (`pymssql`, sin dependencias del sistema) y `oracle` en las pistas de instalación.
24
+
25
+ ### Añadido
26
+ - **Varias bases de datos y routers**, como `DATABASES` y `DATABASE_ROUTERS` de Django: `databases={...}` con alias, `database_routers=[...]` con `db_for_read`, `db_for_write`, `allow_relation` y `allow_migrate`, y `model._meta` con las mismas `app_label` de Django (los routers de Django funcionan tal cual). Sirve también para los modelos de la aplicación (`kit.databases`, `Databases`, `RoutingSession`). Ver [la guía](docs/17-varias-bases-y-routers.md).
27
+ - Seguros de las varias bases: alias `READ_ONLY` que nunca reciben escrituras; contraseñas, sesiones y tokens validados siempre en la base de escritura; lectura y escritura en la misma base dentro de una sesión de escritura; claves foráneas entre bases y alias desconocidos rechazados al arrancar; `allow_relation` comprobado antes de guardar.
28
+ - Guía de [bases de datos](docs/15-bases-de-datos.md): conexión y particularidades de cada motor.
29
+ - CI con Python 3.11 a 3.14 en Linux, Windows y macOS, versiones mínimas de las dependencias, PostgreSQL, MySQL, Oracle y SQL Server reales, `mypy`, `bandit` y `pip-audit`.
30
+ - `djauth startproject`: crea un proyecto FastAPI nuevo con arquitectura por capas, djauth integrado, Alembic, Docker, pruebas y CI; con las versiones probadas o las últimas. Ver [Nuevo proyecto](docs/16-nuevo-proyecto.md).
31
+ - Publicación automática en TestPyPI y PyPI con *Trusted Publishing* y atestaciones firmadas.
32
+ - `CONTRIBUTING.md`, plantillas de issues y de pull requests, Dependabot y `llms.txt`.
33
+
34
+ ## [1.3.0] - 2026-11-11
35
+
36
+ ### Añadido
37
+ - **Historial de cambios del usuario** (tabla `auth_user_history`): cada alta, modificación (valor anterior y nuevo por campo), cambio de contraseña (sin valores) y eliminación, con quién lo hizo, cuándo, desde qué IP y el motivo. Se guarda en la misma transacción que el cambio y se conserva al eliminar el usuario. Solo cambios del usuario: inicios de sesión y demás acciones siguen en el registro general.
38
+ - Rutas `GET /auth/api/user-history` y `GET /auth/api/users/{id}/history`, método `kit.user_history()` y permiso `auth.view_userchange`.
39
+ - Motivo del cambio: `?reason=` en la API, `reason=` en `create_user`, `update_user`, `delete_user` y `set_password`, y un campo en el formulario de la administración.
40
+ - Pestaña *Cambios de usuarios* en la administración.
41
+ - Campos sensibles: `info={"sensitive": True}` en columnas propias y `ExtraField(..., sensitive=True)` registran que cambiaron, sin los valores.
42
+ - Opción `user_history` para desactivarlo.
43
+
44
+ ### Cambiado
45
+ - Los mensajes de error de la conexión a la base sugieren los nombres cortos de motor (`postgresql`, `mysql`…).
46
+
47
+ ## [1.2.0] - 2026-11-10
48
+
49
+ ### Añadido
50
+ - Decoradores `@login_required`, `@permission_required`, `@staff_member_required`, `@superuser_required` y `@user_passes_test`, además de las dependencias `current_user`, `require_perm`, etc.
51
+
52
+ ### Cambiado
53
+ - Los ejemplos usan los nombres cortos de motor (`"ENGINE": "postgresql"`) y ya no dan a entender que hace falta Django. Los nombres de Django se siguen aceptando.
54
+
55
+ ## [1.1.0] - 2026-11-10
56
+
57
+ ### Añadido
58
+ - **Backends de autenticación** (`authentication_backends`), el equivalente de `AUTHENTICATION_BACKENDS` de Django: `ModelBackend`, `AllowAllUsersModelBackend` y `BaseBackend` para escribir los suyos (LDAP, otros sistemas, otras credenciales). Permisos sumados de todos los backends.
59
+ - **Extender el usuario con columnas reales** (`user_mixin`), como `AbstractUser`: aparecen en la API y en la administración, se leen como `user.campo`, y las columnas nuevas se agregan solas a la tabla.
60
+ - **Errores descriptivos**: todas las respuestas llevan `detail`, `code`, `hint` y `errors` por campo; los errores de formato se traducen al español (`422`).
61
+ - **`DATABASES` de Django** (`database={"ENGINE": …, "NAME": …}`): conexión sin escribir la URL, con contraseñas escapadas y elección automática del controlador instalado. Conexiones verificadas antes de usarse.
62
+ - **`username_field`**, el equivalente de `USERNAME_FIELD`: iniciar sesión con el usuario o con el correo (único, sin distinguir mayúsculas, garantizado por la base).
63
+ - Documentación por temas en `docs/`.
64
+
65
+ ### Seguridad
66
+ - Un WebSocket autenticado con cookie debe abrirse desde el mismo origen (evita el secuestro de WebSocket entre sitios, CSWSH).
67
+ - Un administrador que no es superusuario ya no puede modificar ni cambiar la contraseña de usuarios con permisos que él no tiene.
68
+ - El inicio de sesión rechaza peticiones con `Origin` de otro sitio aunque aún no haya cookie.
69
+ - La cookie de sesión se marca `Secure` automáticamente cuando la petición llega por HTTPS.
70
+
71
+ ## [1.0.0] - 2026-11-10
72
+
73
+ ### Añadido
74
+ - Usuarios, grupos (roles) y permisos con el modelo de `django.contrib.auth`.
75
+ - Autenticación por sesión (cookie) o token Bearer opaco y revocable.
76
+ - Administración web, inicio de sesión, "Mi cuenta" y restablecimiento de contraseña.
77
+ - Contraseñas PBKDF2-SHA256 compatibles con Django.
78
+ - Comandos `createsuperuser`, `changepassword` y `listusers`.
@@ -0,0 +1,62 @@
1
+ # Contribuir a fastapi-djauth
2
+
3
+ Gracias por querer mejorar el paquete. Esta guía explica cómo preparar el entorno, qué se comprueba en cada cambio y cómo se publica una versión.
4
+
5
+ ## Preparar el entorno
6
+
7
+ Requiere Python 3.11 o superior. Con [uv](https://docs.astral.sh/uv/) (recomendado):
8
+
9
+ ```bash
10
+ git clone https://github.com/carlosvisbal/fastapi-djauth.git && cd fastapi-djauth
11
+ uv venv && uv pip install -e ".[test]"
12
+ ```
13
+
14
+ O con `pip`: `python -m venv .venv && . .venv/bin/activate && pip install -e ".[test]"`.
15
+
16
+ ## Comprobaciones
17
+
18
+ Son las mismas que ejecuta la CI en cada pull request:
19
+
20
+ ```bash
21
+ pytest # pruebas
22
+ uvx ruff check djauth tests examples # errores y estilo
23
+ uvx ruff format --check djauth tests examples # formato
24
+ uvx mypy # tipos
25
+ uvx bandit -q -r djauth # análisis de seguridad del código
26
+ ```
27
+
28
+ ### Contra PostgreSQL y MySQL reales
29
+
30
+ Las pruebas usan SQLite. `tests/test_engines.py` repite el flujo principal contra motores reales cuando se le indican:
31
+
32
+ ```bash
33
+ docker run -d --name pg -e POSTGRES_USER=djauth -e POSTGRES_PASSWORD=djauth -e POSTGRES_DB=djauth -p 5432:5432 postgres:17-alpine
34
+ docker run -d --name my -e MYSQL_ROOT_PASSWORD=root -e MYSQL_USER=djauth -e MYSQL_PASSWORD=djauth -e MYSQL_DATABASE=djauth -p 3306:3306 mysql:8.4
35
+ uv pip install -e ".[test,postgres,mysql]"
36
+
37
+ DJAUTH_TEST_DATABASE_URLS="postgresql+psycopg://djauth:djauth@127.0.0.1:5432/djauth mysql+pymysql://djauth:djauth@127.0.0.1:3306/djauth" \
38
+ pytest tests/test_engines.py -v
39
+ ```
40
+
41
+ ## Qué se espera de un cambio
42
+
43
+ - **Pruebas:** toda función nueva o error corregido lleva su prueba.
44
+ - **Documentación:** si cambia algo visible, actualice `docs/`, el README y `CHANGELOG.md` (sección "Sin publicar").
45
+ - **Idioma:** la documentación, los mensajes y los comentarios están en español.
46
+ - **Seguridad:** no se aceptan cambios que debiliten las protecciones por defecto (contraseñas, sesiones, CSRF, escalada de privilegios). Si su cambio toca autenticación, sesiones, permisos o datos personales, explique en el pull request su impacto en la seguridad.
47
+ - **Compatibilidad:** se sigue [versionado semántico](https://semver.org/lang/es/). Un cambio que rompa la API pública espera a la siguiente versión mayor.
48
+
49
+ Las fallas de seguridad **no** se informan en un issue: vea [SECURITY.md](SECURITY.md).
50
+
51
+ ## Publicar una versión (mantenedores)
52
+
53
+ 1. Actualice `__version__` en `djauth/__init__.py`. Es la única fuente de la versión.
54
+ 2. Pase las notas de "Sin publicar" en `CHANGELOG.md` a la versión nueva, con la fecha.
55
+ 3. Haga commit en `main` y espere a que la CI quede en verde.
56
+ 4. Cree la Release en GitHub con la etiqueta `vX.Y.Z`:
57
+
58
+ ```bash
59
+ gh release create vX.Y.Z --title "vX.Y.Z" --notes "Ver CHANGELOG.md"
60
+ ```
61
+
62
+ El flujo `publish.yml` comprueba que la etiqueta coincida con la versión y construye el paquete. Luego lo publica en TestPyPI y después en PyPI, este último con aprobación manual en el entorno `pypi`. Al final adjunta los archivos a la Release. No hacen falta contraseñas ni tokens (*Trusted Publishing*).
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CARLOS DANIEL VISBAL ATENCIA
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
@@ -0,0 +1,133 @@
1
+ Metadata-Version: 2.5
2
+ Name: fastapi-djauth
3
+ Version: 1.4.1
4
+ Summary: Usuarios, roles, permisos y administración para FastAPI: sesión o token Bearer, seguro por defecto.
5
+ Project-URL: Homepage, https://github.com/carlosvisbal/fastapi-djauth
6
+ Project-URL: Documentation, https://github.com/carlosvisbal/fastapi-djauth/tree/main/docs
7
+ Project-URL: Changelog, https://github.com/carlosvisbal/fastapi-djauth/blob/main/CHANGELOG.md
8
+ Project-URL: Issues, https://github.com/carlosvisbal/fastapi-djauth/issues
9
+ Project-URL: Source, https://github.com/carlosvisbal/fastapi-djauth
10
+ Project-URL: Security, https://github.com/carlosvisbal/fastapi-djauth/security/policy
11
+ Author: Carlos Daniel Visbal Atencia
12
+ Maintainer: Carlos Daniel Visbal Atencia
13
+ License-Expression: MIT
14
+ License-File: LICENSE
15
+ Keywords: admin,audit,auth,authentication,authorization,bearer,django,fastapi,permissions,rbac,roles,session,users
16
+ Classifier: Development Status :: 4 - Beta
17
+ Classifier: Environment :: Web Environment
18
+ Classifier: Framework :: FastAPI
19
+ Classifier: Framework :: Pydantic :: 2
20
+ Classifier: Intended Audience :: Developers
21
+ Classifier: Natural Language :: Spanish
22
+ Classifier: Operating System :: OS Independent
23
+ Classifier: Programming Language :: Python :: 3
24
+ Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Programming Language :: Python :: 3.13
27
+ Classifier: Programming Language :: Python :: 3.14
28
+ Classifier: Topic :: Internet :: WWW/HTTP :: Session
29
+ Classifier: Topic :: Security
30
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
31
+ Classifier: Typing :: Typed
32
+ Requires-Python: >=3.11
33
+ Requires-Dist: fastapi>=0.110
34
+ Requires-Dist: pydantic<3.0,>=2.5
35
+ Requires-Dist: sqlalchemy<3.0,>=2.0.24
36
+ Provides-Extra: mssql
37
+ Requires-Dist: pymssql>=2.3; extra == 'mssql'
38
+ Provides-Extra: mysql
39
+ Requires-Dist: pymysql[rsa]>=1.1; extra == 'mysql'
40
+ Provides-Extra: oracle
41
+ Requires-Dist: oracledb>=2.0; extra == 'oracle'
42
+ Provides-Extra: postgres
43
+ Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
44
+ Provides-Extra: test
45
+ Requires-Dist: httpx>=0.27; extra == 'test'
46
+ Requires-Dist: pytest>=8; extra == 'test'
47
+ Description-Content-Type: text/markdown
48
+
49
+ # fastapi-djauth
50
+
51
+ [![PyPI](https://img.shields.io/pypi/v/fastapi-djauth)](https://pypi.org/project/fastapi-djauth/)
52
+ [![Python](https://img.shields.io/pypi/pyversions/fastapi-djauth)](https://pypi.org/project/fastapi-djauth/)
53
+ [![CI](https://github.com/carlosvisbal/fastapi-djauth/actions/workflows/ci.yml/badge.svg)](https://github.com/carlosvisbal/fastapi-djauth/actions/workflows/ci.yml)
54
+ [![Tipado](https://img.shields.io/badge/tipado-mypy-blue)](https://github.com/carlosvisbal/fastapi-djauth/blob/main/pyproject.toml)
55
+ [![Licencia: MIT](https://img.shields.io/badge/licencia-MIT-green)](https://github.com/carlosvisbal/fastapi-djauth/blob/main/LICENSE)
56
+
57
+ **Usuarios, roles, permisos y administración para FastAPI.** Sesión por cookie o token Bearer, una vista de administración lista, y la seguridad resuelta.
58
+
59
+ ```python
60
+ from fastapi import Depends, FastAPI
61
+ from djauth import AuthKit, AuthSettings, AuthUser, require_perm
62
+
63
+ kit = AuthKit(AuthSettings(
64
+ database={"ENGINE": "postgresql", "NAME": "miapp", "USER": "app", "PASSWORD": "…", "HOST": "localhost"},
65
+ permissions={"ventas": {"aprobar_pedido": "Puede aprobar pedidos"}},
66
+ )).init()
67
+
68
+ app = FastAPI()
69
+
70
+ @app.post("/pedidos/{id}/aprobar")
71
+ def aprobar(id: int, user: AuthUser = Depends(require_perm("ventas.aprobar_pedido"))):
72
+ return {"aprobado_por": user.username}
73
+
74
+ kit.install(app) # API en /auth/api y páginas: /auth/login, /auth/admin, /auth/account
75
+ ```
76
+
77
+ ## Qué trae
78
+
79
+ - **Usuarios, grupos (roles) y permisos** `app.codename`, con `user.has_perm()`, decoradores (`@login_required`, `@permission_required`) o dependencias.
80
+ - **Configurable sin código extra:** conexión a la base por diccionario, inicio de sesión con usuario o con correo, backends de autenticación propios (LDAP, otros sistemas) y columnas propias en el usuario.
81
+ - **Sesión o Bearer:** cookie `HttpOnly` para navegadores, tokens opacos y revocables para APIs; uno, otro o los dos.
82
+ - **Administración web:** usuarios, grupos, permisos y registro de acciones; inicio de sesión, "Mi cuenta" y restablecimiento de contraseña.
83
+ - **Historial de cambios del usuario:** cada alta, modificación (valor anterior y nuevo por campo), cambio de contraseña y baja, con quién, cuándo, desde qué IP y por qué. Nunca guarda contraseñas.
84
+ - **Seguro por defecto:** contraseñas PBKDF2-SHA256, bloqueo por fuerza bruta, CSRF, protección de WebSocket, sin escalada de privilegios entre administradores, cabeceras de seguridad.
85
+ - **Errores descriptivos:** cada error trae mensaje, código fijo, campo afectado y cómo resolverlo.
86
+ - **Cualquier base:** SQLite, PostgreSQL, MySQL/MariaDB, Oracle o SQL Server (SQLAlchemy 2), probadas contra servidores reales en cada cambio.
87
+ - **Varias bases y routers:** `databases` y `database_routers`, como `DATABASES` y `DATABASE_ROUTERS` de Django: réplicas de lectura o una base por área, también para sus propios modelos.
88
+ - **Plantilla de proyecto:** `djauth startproject` crea una aplicación nueva lista para producción.
89
+
90
+ ## Proyecto nuevo en un minuto
91
+
92
+ ```bash
93
+ pip install fastapi-djauth
94
+ djauth startproject inventario --db postgresql
95
+ ```
96
+
97
+ Crea una aplicación FastAPI completa con arquitectura por capas, usuarios y permisos, Alembic, Docker, pruebas y CI. Usted elige las versiones probadas o las últimas de cada librería. Ver [Proyecto nuevo](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/16-nuevo-proyecto.md).
98
+
99
+ ## Instalación
100
+
101
+ ```bash
102
+ pip install fastapi-djauth # PyPI
103
+ pip install "fastapi-djauth[postgres]" # con el controlador de PostgreSQL
104
+ pip install "git+https://github.com/carlosvisbal/fastapi-djauth.git" # última versión de GitHub
105
+ ```
106
+
107
+ Requiere Python 3.11+.
108
+
109
+ ## Documentación
110
+
111
+ | | |
112
+ |---|---|
113
+ | **Empezar** | [Proyecto nuevo](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/16-nuevo-proyecto.md) · [Instalación y primer uso](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/01-instalacion.md) · [Configuración](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/02-configuracion.md) · [Bases de datos](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/15-bases-de-datos.md) · [Desde Django](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/13-desde-django.md) |
114
+ | **Usar** | [Proteger rutas](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/03-proteger-rutas.md) · [Sesión o Bearer](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/04-sesion-y-bearer.md) · [Usuarios, grupos y permisos](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/05-usuarios-grupos-permisos.md) |
115
+ | **Personalizar** | [Varias bases y routers](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/17-varias-bases-y-routers.md) · [Backends de autenticación](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/06-backends.md) · [Extender el usuario](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/07-extender-usuario.md) |
116
+ | **Operar** | [Administración web](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/08-administracion.md) · [Historial de cambios](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/14-historial-de-cambios.md) · [Comandos](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/11-comandos.md) · [Seguridad](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/10-seguridad.md) |
117
+ | **Referencia** | [API REST](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/12-api.md) · [Errores](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/09-errores.md) · [Cambios](https://github.com/carlosvisbal/fastapi-djauth/blob/main/CHANGELOG.md) |
118
+
119
+ ¿Viene de Django? Los conceptos y la configuración le resultarán familiares, y puede importar sus usuarios con su contraseña: vea [Desde Django](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/13-desde-django.md). El paquete **no** necesita Django instalado.
120
+
121
+ Hay un ejemplo completo en [examples/app.py](https://github.com/carlosvisbal/fastapi-djauth/blob/main/examples/app.py).
122
+
123
+ ## Seguridad
124
+
125
+ Lea [docs/10-seguridad.md](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/10-seguridad.md) antes de poner el servicio en producción. Para informar una vulnerabilidad, use el aviso privado de GitHub ([SECURITY.md](https://github.com/carlosvisbal/fastapi-djauth/blob/main/SECURITY.md)), no un issue público.
126
+
127
+ ## Contribuir
128
+
129
+ Las contribuciones son bienvenidas. Vea [CONTRIBUTING.md](https://github.com/carlosvisbal/fastapi-djauth/blob/main/CONTRIBUTING.md): cómo preparar el entorno, las pruebas (también contra PostgreSQL y MySQL reales) y el proceso de publicación.
130
+
131
+ ## Licencia
132
+
133
+ [MIT](https://github.com/carlosvisbal/fastapi-djauth/blob/main/LICENSE) © Carlos Daniel Visbal Atencia
@@ -0,0 +1,85 @@
1
+ # fastapi-djauth
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/fastapi-djauth)](https://pypi.org/project/fastapi-djauth/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/fastapi-djauth)](https://pypi.org/project/fastapi-djauth/)
5
+ [![CI](https://github.com/carlosvisbal/fastapi-djauth/actions/workflows/ci.yml/badge.svg)](https://github.com/carlosvisbal/fastapi-djauth/actions/workflows/ci.yml)
6
+ [![Tipado](https://img.shields.io/badge/tipado-mypy-blue)](https://github.com/carlosvisbal/fastapi-djauth/blob/main/pyproject.toml)
7
+ [![Licencia: MIT](https://img.shields.io/badge/licencia-MIT-green)](https://github.com/carlosvisbal/fastapi-djauth/blob/main/LICENSE)
8
+
9
+ **Usuarios, roles, permisos y administración para FastAPI.** Sesión por cookie o token Bearer, una vista de administración lista, y la seguridad resuelta.
10
+
11
+ ```python
12
+ from fastapi import Depends, FastAPI
13
+ from djauth import AuthKit, AuthSettings, AuthUser, require_perm
14
+
15
+ kit = AuthKit(AuthSettings(
16
+ database={"ENGINE": "postgresql", "NAME": "miapp", "USER": "app", "PASSWORD": "…", "HOST": "localhost"},
17
+ permissions={"ventas": {"aprobar_pedido": "Puede aprobar pedidos"}},
18
+ )).init()
19
+
20
+ app = FastAPI()
21
+
22
+ @app.post("/pedidos/{id}/aprobar")
23
+ def aprobar(id: int, user: AuthUser = Depends(require_perm("ventas.aprobar_pedido"))):
24
+ return {"aprobado_por": user.username}
25
+
26
+ kit.install(app) # API en /auth/api y páginas: /auth/login, /auth/admin, /auth/account
27
+ ```
28
+
29
+ ## Qué trae
30
+
31
+ - **Usuarios, grupos (roles) y permisos** `app.codename`, con `user.has_perm()`, decoradores (`@login_required`, `@permission_required`) o dependencias.
32
+ - **Configurable sin código extra:** conexión a la base por diccionario, inicio de sesión con usuario o con correo, backends de autenticación propios (LDAP, otros sistemas) y columnas propias en el usuario.
33
+ - **Sesión o Bearer:** cookie `HttpOnly` para navegadores, tokens opacos y revocables para APIs; uno, otro o los dos.
34
+ - **Administración web:** usuarios, grupos, permisos y registro de acciones; inicio de sesión, "Mi cuenta" y restablecimiento de contraseña.
35
+ - **Historial de cambios del usuario:** cada alta, modificación (valor anterior y nuevo por campo), cambio de contraseña y baja, con quién, cuándo, desde qué IP y por qué. Nunca guarda contraseñas.
36
+ - **Seguro por defecto:** contraseñas PBKDF2-SHA256, bloqueo por fuerza bruta, CSRF, protección de WebSocket, sin escalada de privilegios entre administradores, cabeceras de seguridad.
37
+ - **Errores descriptivos:** cada error trae mensaje, código fijo, campo afectado y cómo resolverlo.
38
+ - **Cualquier base:** SQLite, PostgreSQL, MySQL/MariaDB, Oracle o SQL Server (SQLAlchemy 2), probadas contra servidores reales en cada cambio.
39
+ - **Varias bases y routers:** `databases` y `database_routers`, como `DATABASES` y `DATABASE_ROUTERS` de Django: réplicas de lectura o una base por área, también para sus propios modelos.
40
+ - **Plantilla de proyecto:** `djauth startproject` crea una aplicación nueva lista para producción.
41
+
42
+ ## Proyecto nuevo en un minuto
43
+
44
+ ```bash
45
+ pip install fastapi-djauth
46
+ djauth startproject inventario --db postgresql
47
+ ```
48
+
49
+ Crea una aplicación FastAPI completa con arquitectura por capas, usuarios y permisos, Alembic, Docker, pruebas y CI. Usted elige las versiones probadas o las últimas de cada librería. Ver [Proyecto nuevo](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/16-nuevo-proyecto.md).
50
+
51
+ ## Instalación
52
+
53
+ ```bash
54
+ pip install fastapi-djauth # PyPI
55
+ pip install "fastapi-djauth[postgres]" # con el controlador de PostgreSQL
56
+ pip install "git+https://github.com/carlosvisbal/fastapi-djauth.git" # última versión de GitHub
57
+ ```
58
+
59
+ Requiere Python 3.11+.
60
+
61
+ ## Documentación
62
+
63
+ | | |
64
+ |---|---|
65
+ | **Empezar** | [Proyecto nuevo](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/16-nuevo-proyecto.md) · [Instalación y primer uso](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/01-instalacion.md) · [Configuración](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/02-configuracion.md) · [Bases de datos](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/15-bases-de-datos.md) · [Desde Django](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/13-desde-django.md) |
66
+ | **Usar** | [Proteger rutas](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/03-proteger-rutas.md) · [Sesión o Bearer](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/04-sesion-y-bearer.md) · [Usuarios, grupos y permisos](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/05-usuarios-grupos-permisos.md) |
67
+ | **Personalizar** | [Varias bases y routers](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/17-varias-bases-y-routers.md) · [Backends de autenticación](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/06-backends.md) · [Extender el usuario](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/07-extender-usuario.md) |
68
+ | **Operar** | [Administración web](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/08-administracion.md) · [Historial de cambios](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/14-historial-de-cambios.md) · [Comandos](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/11-comandos.md) · [Seguridad](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/10-seguridad.md) |
69
+ | **Referencia** | [API REST](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/12-api.md) · [Errores](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/09-errores.md) · [Cambios](https://github.com/carlosvisbal/fastapi-djauth/blob/main/CHANGELOG.md) |
70
+
71
+ ¿Viene de Django? Los conceptos y la configuración le resultarán familiares, y puede importar sus usuarios con su contraseña: vea [Desde Django](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/13-desde-django.md). El paquete **no** necesita Django instalado.
72
+
73
+ Hay un ejemplo completo en [examples/app.py](https://github.com/carlosvisbal/fastapi-djauth/blob/main/examples/app.py).
74
+
75
+ ## Seguridad
76
+
77
+ Lea [docs/10-seguridad.md](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/10-seguridad.md) antes de poner el servicio en producción. Para informar una vulnerabilidad, use el aviso privado de GitHub ([SECURITY.md](https://github.com/carlosvisbal/fastapi-djauth/blob/main/SECURITY.md)), no un issue público.
78
+
79
+ ## Contribuir
80
+
81
+ Las contribuciones son bienvenidas. Vea [CONTRIBUTING.md](https://github.com/carlosvisbal/fastapi-djauth/blob/main/CONTRIBUTING.md): cómo preparar el entorno, las pruebas (también contra PostgreSQL y MySQL reales) y el proceso de publicación.
82
+
83
+ ## Licencia
84
+
85
+ [MIT](https://github.com/carlosvisbal/fastapi-djauth/blob/main/LICENSE) © Carlos Daniel Visbal Atencia
@@ -0,0 +1,23 @@
1
+ # Política de seguridad
2
+
3
+ ## Versiones con soporte
4
+
5
+ | Versión | Soporte |
6
+ |---|---|
7
+ | 1.3.x | Sí |
8
+ | < 1.3 | No: actualice a la última versión (1.1.0 corrigió el secuestro de WebSocket entre sitios) |
9
+
10
+ ## Informar una vulnerabilidad
11
+
12
+ **No abra un issue público.** Use el aviso privado de GitHub: pestaña **Security → Report a vulnerability** en https://github.com/carlosvisbal/fastapi-djauth/security/advisories/new
13
+
14
+ Incluya, si puede: versión afectada, pasos para reproducirlo y el impacto. Recibirá respuesta en un plazo de 7 días. Una vez corregido, se publica una versión nueva y un aviso con el crédito a quien lo informó (si lo desea).
15
+
16
+ Lo que protege el módulo y sus límites: [docs/10-seguridad.md](docs/10-seguridad.md).
17
+
18
+ ## Cómo se protege la cadena de publicación
19
+
20
+ - Los paquetes se publican desde GitHub Actions con *Trusted Publishing*: no existen contraseñas ni tokens de PyPI que robar.
21
+ - Cada versión en PyPI lleva una atestación firmada (PEP 740) que prueba de qué repositorio y flujo salió.
22
+ - Las acciones de GitHub están fijadas por commit, y Dependabot propone sus actualizaciones.
23
+ - En cada cambio se ejecutan pruebas, análisis de tipos (`mypy`), análisis de seguridad del código (`bandit`) y la búsqueda de vulnerabilidades conocidas en las dependencias (`pip-audit`).
@@ -0,0 +1,82 @@
1
+ """djauth: usuarios, grupos (roles), permisos y administración al estilo de Django, para FastAPI.
2
+
3
+ from djauth import AuthKit, AuthSettings, current_user, require_perm
4
+
5
+ kit = AuthKit(AuthSettings(database_url="sqlite:///auth.sqlite3")).init()
6
+ kit.install(app, protect=True)
7
+ """
8
+
9
+ from djauth.api import (
10
+ AuthMiddleware,
11
+ Rule,
12
+ current_user,
13
+ identify,
14
+ optional_user,
15
+ require_perm,
16
+ require_staff,
17
+ require_superuser,
18
+ rule,
19
+ ws_user,
20
+ )
21
+ from djauth.backends import AllowAllUsersModelBackend, AuthRequest, BaseBackend, ModelBackend
22
+ from djauth.core import SERVICE_USER, AuthKit, AuthUser
23
+ from djauth.database import DatabaseConfigError, url_from_django
24
+ from djauth.decorators import login_required, permission_required, staff_member_required, superuser_required, user_passes_test
25
+ from djauth.errors import (
26
+ AuthError,
27
+ InvalidCredentialsError,
28
+ NotAuthenticatedError,
29
+ NotFoundError,
30
+ PermissionDeniedError,
31
+ TooManyAttemptsError,
32
+ ValidationError,
33
+ )
34
+ from djauth.hashers import check_password, make_password
35
+ from djauth.routers import BaseRouter, Databases, ModelMeta, RoutingSession, model_meta
36
+ from djauth.settings import AuthSettings, ExtraField
37
+
38
+ __version__ = "1.4.1"
39
+
40
+ __all__ = [
41
+ "SERVICE_USER",
42
+ "AllowAllUsersModelBackend",
43
+ "AuthError",
44
+ "AuthKit",
45
+ "AuthMiddleware",
46
+ "AuthRequest",
47
+ "AuthSettings",
48
+ "AuthUser",
49
+ "BaseBackend",
50
+ "BaseRouter",
51
+ "DatabaseConfigError",
52
+ "Databases",
53
+ "ExtraField",
54
+ "InvalidCredentialsError",
55
+ "ModelBackend",
56
+ "ModelMeta",
57
+ "NotAuthenticatedError",
58
+ "NotFoundError",
59
+ "PermissionDeniedError",
60
+ "RoutingSession",
61
+ "Rule",
62
+ "TooManyAttemptsError",
63
+ "ValidationError",
64
+ "__version__",
65
+ "check_password",
66
+ "current_user",
67
+ "identify",
68
+ "login_required",
69
+ "make_password",
70
+ "model_meta",
71
+ "optional_user",
72
+ "permission_required",
73
+ "require_perm",
74
+ "require_staff",
75
+ "require_superuser",
76
+ "rule",
77
+ "staff_member_required",
78
+ "superuser_required",
79
+ "url_from_django",
80
+ "user_passes_test",
81
+ "ws_user",
82
+ ]
@@ -0,0 +1,98 @@
1
+ """Comandos de administración (como `manage.py`):
2
+
3
+ python -m djauth --db sqlite:///auth.sqlite3 createsuperuser --username admin --email a@b.co
4
+ python -m djauth --db … changepassword admin
5
+ python -m djauth --db … listusers
6
+ djauth startproject inventario --db postgresql # proyecto FastAPI nuevo con djauth integrado
7
+
8
+ La contraseña se pide por teclado; para scripts, use la variable DJAUTH_PASSWORD.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import getpass
15
+ import os
16
+ import sys
17
+
18
+ from djauth.core import AuthKit
19
+ from djauth.errors import AuthError, ValidationError
20
+ from djauth.settings import AuthSettings
21
+
22
+
23
+ def _ask_password() -> str:
24
+ if env := os.environ.get("DJAUTH_PASSWORD"):
25
+ return env
26
+ while True:
27
+ first = getpass.getpass("Contraseña: ")
28
+ if first == getpass.getpass("Contraseña (otra vez): "):
29
+ return first
30
+ print("Las contraseñas no coinciden.", file=sys.stderr)
31
+
32
+
33
+ def main(argv: list[str] | None = None) -> int:
34
+ parser = argparse.ArgumentParser(prog="python -m djauth", description="Administración de usuarios de djauth")
35
+ parser.add_argument(
36
+ "--db", default=os.environ.get("DJAUTH_DATABASE_URL", "sqlite:///auth.sqlite3"), help="URL de la base de datos"
37
+ )
38
+ parser.add_argument("--prefix", default="auth_", help="Prefijo de las tablas")
39
+ sub = parser.add_subparsers(dest="command", required=True)
40
+ create = sub.add_parser("createsuperuser", help="Crear un superusuario")
41
+ create.add_argument("--username", required=True)
42
+ create.add_argument("--email", default="")
43
+ change = sub.add_parser("changepassword", help="Cambiar la contraseña de un usuario")
44
+ change.add_argument("username")
45
+ sub.add_parser("listusers", help="Listar usuarios")
46
+ start = sub.add_parser("startproject", help="Crear un proyecto FastAPI nuevo con djauth integrado")
47
+ start.add_argument("name", help="Nombre del paquete: minúsculas, números y _ (p. ej. inventario)")
48
+ start.add_argument("directory", nargs="?", help="Carpeta donde crearlo (por defecto ./<name>; debe estar vacía)")
49
+ start.add_argument("--db", dest="db_engine", choices=("sqlite", "postgresql", "mysql"), default="sqlite")
50
+ start.add_argument(
51
+ "--versiones",
52
+ dest="versions",
53
+ choices=("probadas", "ultimas"),
54
+ default="probadas",
55
+ help="probadas: versiones exactas verificadas con este djauth · ultimas: lo más reciente compatible",
56
+ )
57
+ start.add_argument("--titulo", dest="title", help='Nombre visible de la aplicación (p. ej. "Inventario general")')
58
+ start.add_argument("--sin-lock", dest="no_lock", action="store_true", help="No ejecutar `uv lock` al terminar")
59
+ args = parser.parse_args(argv)
60
+
61
+ if args.command == "startproject":
62
+ from djauth.startproject import main as startproject
63
+
64
+ return startproject(args)
65
+
66
+ kit = AuthKit(AuthSettings(database_url=args.db, table_prefix=args.prefix)).init()
67
+ try:
68
+ if args.command == "createsuperuser":
69
+ created = kit.create_superuser(
70
+ args.username, _ask_password(), email=args.email, reason="Creado con djauth createsuperuser."
71
+ )
72
+ print(f"Superusuario {created['username']} creado.")
73
+ elif args.command == "changepassword":
74
+ user = kit.get_by_username(args.username)
75
+ if user is None:
76
+ print(f"No existe el usuario {args.username}.", file=sys.stderr)
77
+ return 1
78
+ kit.set_password(user.id, _ask_password(), reason="Cambiada con djauth changepassword.")
79
+ print(f"Contraseña de {user.username} cambiada; sus sesiones abiertas se cerraron.")
80
+ elif args.command == "listusers":
81
+ items, total = kit.list_users(limit=1000)
82
+ for u in items:
83
+ flags = "".join(f for f, on in (("S", u["is_superuser"]), ("A", u["is_staff"]), ("-", not u["is_active"])) if on)
84
+ print(f"{u['id']:>5} {u['username']:<30} {flags:<3} {', '.join(u['groups'])}")
85
+ print(f"{total} usuarios")
86
+ except ValidationError as exc:
87
+ for field, messages in exc.errors.items():
88
+ for m in messages:
89
+ print(f"{field}: {m}", file=sys.stderr)
90
+ return 1
91
+ except AuthError as exc:
92
+ print(str(exc), file=sys.stderr)
93
+ return 1
94
+ return 0
95
+
96
+
97
+ if __name__ == "__main__":
98
+ raise SystemExit(main())