milpa-core 0.3.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.
- milpa_core-0.3.1/.dockerignore +17 -0
- milpa_core-0.3.1/.env.example +118 -0
- milpa_core-0.3.1/.github/workflows/ci.yml +65 -0
- milpa_core-0.3.1/.github/workflows/release.yml +54 -0
- milpa_core-0.3.1/.gitignore +45 -0
- milpa_core-0.3.1/CHANGELOG.md +146 -0
- milpa_core-0.3.1/CODE_OF_CONDUCT.md +58 -0
- milpa_core-0.3.1/CONTRIBUTING.md +148 -0
- milpa_core-0.3.1/LICENSE +21 -0
- milpa_core-0.3.1/PKG-INFO +246 -0
- milpa_core-0.3.1/README.md +192 -0
- milpa_core-0.3.1/Tests/Core/Auth/test_Auth.py +136 -0
- milpa_core-0.3.1/Tests/Core/Auth/test_Authorization.py +165 -0
- milpa_core-0.3.1/Tests/Core/Auth/test_Hash.py +23 -0
- milpa_core-0.3.1/Tests/Core/Auth/test_PassportGuard.py +77 -0
- milpa_core-0.3.1/Tests/Core/Auth/test_Policy.py +54 -0
- milpa_core-0.3.1/Tests/Core/Auth/test_SessionGuard.py +80 -0
- milpa_core-0.3.1/Tests/Core/CeleryApp/test_Dispatch.py +28 -0
- milpa_core-0.3.1/Tests/Core/CeleryApp/test_Retry.py +41 -0
- milpa_core-0.3.1/Tests/Core/Config/test_BrokerSettings.py +30 -0
- milpa_core-0.3.1/Tests/Core/Config/test_CookieSettings.py +30 -0
- milpa_core-0.3.1/Tests/Core/Console/test_CliErrorBoundary.py +20 -0
- milpa_core-0.3.1/Tests/Core/Console/test_Console.py +138 -0
- milpa_core-0.3.1/Tests/Core/Console/test_DiscoveryLoud.py +43 -0
- milpa_core-0.3.1/Tests/Core/Console/test_FormatCommandList.py +50 -0
- milpa_core-0.3.1/Tests/Core/Console/test_JornalLauncher.py +39 -0
- milpa_core-0.3.1/Tests/Core/Console/test_LauncherCommands.py +62 -0
- milpa_core-0.3.1/Tests/Core/Console/test_MakeWritesToAppDir.py +158 -0
- milpa_core-0.3.1/Tests/Core/Console/test_NewCommands.py +77 -0
- milpa_core-0.3.1/Tests/Core/Console/test_ScheduleRunCommand.py +85 -0
- milpa_core-0.3.1/Tests/Core/Cron/test_Schedule.py +66 -0
- milpa_core-0.3.1/Tests/Core/Database/test_Factory.py +90 -0
- milpa_core-0.3.1/Tests/Core/Database/test_Filtering.py +82 -0
- milpa_core-0.3.1/Tests/Core/Database/test_Migrations.py +84 -0
- milpa_core-0.3.1/Tests/Core/Database/test_Repository.py +179 -0
- milpa_core-0.3.1/Tests/Core/Database/test_Seeder.py +46 -0
- milpa_core-0.3.1/Tests/Core/Database/test_Session.py +39 -0
- milpa_core-0.3.1/Tests/Core/Database/test_Transactional.py +98 -0
- milpa_core-0.3.1/Tests/Core/Events/test_EventDispatch.py +93 -0
- milpa_core-0.3.1/Tests/Core/Events/test_Observer.py +34 -0
- milpa_core-0.3.1/Tests/Core/Http/test_Csrf.py +74 -0
- milpa_core-0.3.1/Tests/Core/Http/test_ExceptionHandler.py +123 -0
- milpa_core-0.3.1/Tests/Core/Http/test_Middleware.py +47 -0
- milpa_core-0.3.1/Tests/Core/Http/test_RateLimit.py +56 -0
- milpa_core-0.3.1/Tests/Core/Http/test_Routing.py +117 -0
- milpa_core-0.3.1/Tests/Core/Http/test_SecurityHeaders.py +86 -0
- milpa_core-0.3.1/Tests/Core/Jobs/test_Jobs.py +61 -0
- milpa_core-0.3.1/Tests/Core/Mail/test_Mail.py +65 -0
- milpa_core-0.3.1/Tests/Core/Mail/test_MailDriver.py +39 -0
- milpa_core-0.3.1/Tests/Core/Mail/test_Mailable.py +55 -0
- milpa_core-0.3.1/Tests/Core/Mail/test_Mailer.py +174 -0
- milpa_core-0.3.1/Tests/Core/Mail/test_MailerDispatch.py +50 -0
- milpa_core-0.3.1/Tests/Core/Mail/test_Tasks.py +120 -0
- milpa_core-0.3.1/Tests/Core/Mediator/test_Mediator.py +54 -0
- milpa_core-0.3.1/Tests/Core/Pipeline/test_Pipeline.py +43 -0
- milpa_core-0.3.1/Tests/Core/Translate/test_AcceptLanguage.py +20 -0
- milpa_core-0.3.1/Tests/Core/Translate/test_I18n.py +164 -0
- milpa_core-0.3.1/Tests/Core/View/test_Negotiation.py +51 -0
- milpa_core-0.3.1/Tests/Core/View/test_TemplateEngine.py +109 -0
- milpa_core-0.3.1/Tests/Core/test_Clock.py +20 -0
- milpa_core-0.3.1/Tests/Core/test_Cron.py +57 -0
- milpa_core-0.3.1/Tests/Core/test_FrameworkIsGeneric.py +36 -0
- milpa_core-0.3.1/Tests/Core/test_ModelDiscovery.py +20 -0
- milpa_core-0.3.1/Tests/Modules/Demo/test_DemoBuildingBlocks.py +126 -0
- milpa_core-0.3.1/Tests/Modules/Demo/test_DemoFlows.py +100 -0
- milpa_core-0.3.1/Tests/conftest.py +18 -0
- milpa_core-0.3.1/docker-compose.yml +42 -0
- milpa_core-0.3.1/documentation/01-introduccion.md +83 -0
- milpa_core-0.3.1/documentation/02-instalacion.md +93 -0
- milpa_core-0.3.1/documentation/03-configuracion.md +127 -0
- milpa_core-0.3.1/documentation/04-estructura-directorios.md +85 -0
- milpa_core-0.3.1/documentation/05-ciclo-de-vida.md +100 -0
- milpa_core-0.3.1/documentation/06-monolito-modular.md +103 -0
- milpa_core-0.3.1/documentation/07-rutas-y-controladores.md +188 -0
- milpa_core-0.3.1/documentation/08-consola-jornal.md +110 -0
- milpa_core-0.3.1/documentation/09-vistas.md +92 -0
- milpa_core-0.3.1/documentation/10-correo.md +173 -0
- milpa_core-0.3.1/documentation/11-colas-y-tareas.md +154 -0
- milpa_core-0.3.1/documentation/12-programacion-cron.md +147 -0
- milpa_core-0.3.1/documentation/13-localizacion-i18n.md +118 -0
- milpa_core-0.3.1/documentation/14-logging.md +53 -0
- milpa_core-0.3.1/documentation/15-autenticacion.md +174 -0
- milpa_core-0.3.1/documentation/16-base-de-datos.md +133 -0
- milpa_core-0.3.1/documentation/17-modelos.md +109 -0
- milpa_core-0.3.1/documentation/18-repositorios-y-transacciones.md +192 -0
- milpa_core-0.3.1/documentation/19-eventos-y-observers.md +250 -0
- milpa_core-0.3.1/documentation/20-mediator.md +265 -0
- milpa_core-0.3.1/documentation/21-pipeline.md +221 -0
- milpa_core-0.3.1/documentation/22-jobs.md +174 -0
- milpa_core-0.3.1/documentation/23-versionado-api.md +194 -0
- milpa_core-0.3.1/documentation/24-rate-limiting.md +181 -0
- milpa_core-0.3.1/documentation/25-filtrado-y-paginacion.md +294 -0
- milpa_core-0.3.1/documentation/26-negociacion-de-contenido.md +174 -0
- milpa_core-0.3.1/documentation/27-serializadores.md +207 -0
- milpa_core-0.3.1/documentation/28-errores-y-rfc9457.md +339 -0
- milpa_core-0.3.1/documentation/README.md +67 -0
- milpa_core-0.3.1/jornal +18 -0
- milpa_core-0.3.1/logs/.gitkeep +0 -0
- milpa_core-0.3.1/migrations/env.py +50 -0
- milpa_core-0.3.1/migrations/script.py.mako +27 -0
- milpa_core-0.3.1/migrations/versions/.gitkeep +0 -0
- milpa_core-0.3.1/migrations/versions/a7c1d9e2f4b8_add_archived_to_notes.py +29 -0
- milpa_core-0.3.1/migrations/versions/c35b0c89ce97_demo_users_and_notes.py +55 -0
- milpa_core-0.3.1/mkdocs.yml +93 -0
- milpa_core-0.3.1/pyproject.toml +173 -0
- milpa_core-0.3.1/src/milpa/Core/Auth/Auth.py +113 -0
- milpa_core-0.3.1/src/milpa/Core/Auth/Authorization.py +147 -0
- milpa_core-0.3.1/src/milpa/Core/Auth/Contracts.py +62 -0
- milpa_core-0.3.1/src/milpa/Core/Auth/Guards.py +98 -0
- milpa_core-0.3.1/src/milpa/Core/Auth/Hash.py +38 -0
- milpa_core-0.3.1/src/milpa/Core/Auth/Passport.py +95 -0
- milpa_core-0.3.1/src/milpa/Core/Auth/Providers.py +69 -0
- milpa_core-0.3.1/src/milpa/Core/Auth/Tokens.py +36 -0
- milpa_core-0.3.1/src/milpa/Core/Auth/__init__.py +52 -0
- milpa_core-0.3.1/src/milpa/Core/CeleryApp/CeleryApp.py +57 -0
- milpa_core-0.3.1/src/milpa/Core/CeleryApp/Dispatch.py +47 -0
- milpa_core-0.3.1/src/milpa/Core/CeleryApp/Retry.py +67 -0
- milpa_core-0.3.1/src/milpa/Core/CeleryApp/__init__.py +11 -0
- milpa_core-0.3.1/src/milpa/Core/Clock/Clock.py +40 -0
- milpa_core-0.3.1/src/milpa/Core/Clock/__init__.py +11 -0
- milpa_core-0.3.1/src/milpa/Core/Config/Settings.py +262 -0
- milpa_core-0.3.1/src/milpa/Core/Config/__init__.py +5 -0
- milpa_core-0.3.1/src/milpa/Core/Console/Cli.py +147 -0
- milpa_core-0.3.1/src/milpa/Core/Console/Commands/DbCommands.py +27 -0
- milpa_core-0.3.1/src/milpa/Core/Console/Commands/MakeCommands.py +418 -0
- milpa_core-0.3.1/src/milpa/Core/Console/Commands/MigrateCommands.py +72 -0
- milpa_core-0.3.1/src/milpa/Core/Console/Commands/QueueWorkCommand.py +44 -0
- milpa_core-0.3.1/src/milpa/Core/Console/Commands/RouteCommands.py +33 -0
- milpa_core-0.3.1/src/milpa/Core/Console/Commands/ScheduleRunCommand.py +49 -0
- milpa_core-0.3.1/src/milpa/Core/Console/Commands/ScheduleWorkCommand.py +33 -0
- milpa_core-0.3.1/src/milpa/Core/Console/Commands/SeedCommands.py +33 -0
- milpa_core-0.3.1/src/milpa/Core/Console/Commands/__init__.py +7 -0
- milpa_core-0.3.1/src/milpa/Core/Console/Console.py +171 -0
- milpa_core-0.3.1/src/milpa/Core/Console/Scaffold.py +93 -0
- milpa_core-0.3.1/src/milpa/Core/Console/__init__.py +29 -0
- milpa_core-0.3.1/src/milpa/Core/Cron/Cron.py +188 -0
- milpa_core-0.3.1/src/milpa/Core/Cron/Schedule.py +95 -0
- milpa_core-0.3.1/src/milpa/Core/Cron/__init__.py +48 -0
- milpa_core-0.3.1/src/milpa/Core/Database/Base.py +25 -0
- milpa_core-0.3.1/src/milpa/Core/Database/Factory.py +59 -0
- milpa_core-0.3.1/src/milpa/Core/Database/Faker.py +28 -0
- milpa_core-0.3.1/src/milpa/Core/Database/Filtering.py +101 -0
- milpa_core-0.3.1/src/milpa/Core/Database/Migrations.py +57 -0
- milpa_core-0.3.1/src/milpa/Core/Database/Repository.py +192 -0
- milpa_core-0.3.1/src/milpa/Core/Database/Seeder.py +32 -0
- milpa_core-0.3.1/src/milpa/Core/Database/Session.py +87 -0
- milpa_core-0.3.1/src/milpa/Core/Database/SoftDelete.py +25 -0
- milpa_core-0.3.1/src/milpa/Core/Database/Timestamp.py +27 -0
- milpa_core-0.3.1/src/milpa/Core/Database/Transactional.py +110 -0
- milpa_core-0.3.1/src/milpa/Core/Database/__init__.py +27 -0
- milpa_core-0.3.1/src/milpa/Core/Discovery.py +50 -0
- milpa_core-0.3.1/src/milpa/Core/Errors/Errors.py +137 -0
- milpa_core-0.3.1/src/milpa/Core/Errors/__init__.py +28 -0
- milpa_core-0.3.1/src/milpa/Core/Events/Dispatch.py +45 -0
- milpa_core-0.3.1/src/milpa/Core/Events/Observer.py +43 -0
- milpa_core-0.3.1/src/milpa/Core/Events/Tasks.py +54 -0
- milpa_core-0.3.1/src/milpa/Core/Events/__init__.py +19 -0
- milpa_core-0.3.1/src/milpa/Core/Http/Csrf.py +107 -0
- milpa_core-0.3.1/src/milpa/Core/Http/ExceptionHandler.py +123 -0
- milpa_core-0.3.1/src/milpa/Core/Http/Http.py +125 -0
- milpa_core-0.3.1/src/milpa/Core/Http/Middleware.py +91 -0
- milpa_core-0.3.1/src/milpa/Core/Http/ProblemDetails.py +49 -0
- milpa_core-0.3.1/src/milpa/Core/Http/RateLimit.py +96 -0
- milpa_core-0.3.1/src/milpa/Core/Http/Routing.py +165 -0
- milpa_core-0.3.1/src/milpa/Core/Http/SecurityHeaders.py +42 -0
- milpa_core-0.3.1/src/milpa/Core/Http/__init__.py +12 -0
- milpa_core-0.3.1/src/milpa/Core/Jobs/Jobs.py +87 -0
- milpa_core-0.3.1/src/milpa/Core/Jobs/__init__.py +10 -0
- milpa_core-0.3.1/src/milpa/Core/Logging/Logging.py +88 -0
- milpa_core-0.3.1/src/milpa/Core/Logging/__init__.py +10 -0
- milpa_core-0.3.1/src/milpa/Core/Mail/Mail.py +56 -0
- milpa_core-0.3.1/src/milpa/Core/Mail/Mailable.py +91 -0
- milpa_core-0.3.1/src/milpa/Core/Mail/Mailer.py +285 -0
- milpa_core-0.3.1/src/milpa/Core/Mail/Tasks.py +143 -0
- milpa_core-0.3.1/src/milpa/Core/Mail/__init__.py +20 -0
- milpa_core-0.3.1/src/milpa/Core/Mediator/Mediator.py +62 -0
- milpa_core-0.3.1/src/milpa/Core/Mediator/__init__.py +20 -0
- milpa_core-0.3.1/src/milpa/Core/Pipeline/Pipeline.py +60 -0
- milpa_core-0.3.1/src/milpa/Core/Pipeline/__init__.py +10 -0
- milpa_core-0.3.1/src/milpa/Core/Registry/Registry.py +213 -0
- milpa_core-0.3.1/src/milpa/Core/Registry/__init__.py +36 -0
- milpa_core-0.3.1/src/milpa/Core/Translate/I18n.py +171 -0
- milpa_core-0.3.1/src/milpa/Core/Translate/__init__.py +14 -0
- milpa_core-0.3.1/src/milpa/Core/View/TemplateEngine.py +149 -0
- milpa_core-0.3.1/src/milpa/Core/View/View.py +82 -0
- milpa_core-0.3.1/src/milpa/Core/View/__init__.py +10 -0
- milpa_core-0.3.1/src/milpa/Core/__init__.py +0 -0
- milpa_core-0.3.1/src/milpa/Dictionaries/__init__.py +11 -0
- milpa_core-0.3.1/src/milpa/Models/Note.py +20 -0
- milpa_core-0.3.1/src/milpa/Models/User.py +22 -0
- milpa_core-0.3.1/src/milpa/Models/__init__.py +22 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Commands.py +17 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Console/Commands/ArchiveNoteCommand.py +26 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Console/Commands/__init__.py +1 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Console/__init__.py +1 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Crons/DailyDigestCron.py +21 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Crons/__init__.py +3 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Events.py +36 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Factories/__init__.py +7 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Factories/factories.py +38 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Handlers/ArchiveNoteHandler.py +35 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Handlers/__init__.py +2 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Http/ApiController.py +157 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Http/ReportsController.py +46 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Http/WebController.py +233 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Http/__init__.py +1 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Jobs/ExportNotesJob.py +21 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Jobs/__init__.py +2 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Mail/DemoMailable.py +40 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Mail/NewUserAdminMailable.py +26 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Mail/NoteCreatedMailable.py +31 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Mail/ShareNoteMailable.py +27 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Mail/__init__.py +2 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Observers/NotifyAdminOnUserRegistered.py +27 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Observers/NotifyOwnerOnNoteCreated.py +20 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Observers/__init__.py +3 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Pipes/CleanContent.py +38 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Pipes/__init__.py +2 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Policies.py +29 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Repositories/NoteRepository.py +20 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Repositories/UserRepository.py +15 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Repositories/__init__.py +1 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Lang/demo/NoteCreated.en.yml +4 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Lang/demo/NoteCreated.es.yml +4 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Static/css/app.css +99 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Static/favicon.ico +0 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Static/logo.png +0 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Views/_notes_results.html.j2 +32 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Views/_users_results.html.j2 +32 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Views/admin_users.html.j2 +17 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Views/dashboard.html.j2 +30 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Views/emails/new_user_admin.html.j2 +10 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Views/emails/note_created.html.j2 +6 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Views/emails/share_note.html.j2 +7 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Views/forbidden.html.j2 +10 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Views/layout.html.j2 +59 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Views/login.html.j2 +53 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Views/notes.html.j2 +24 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Resources/Views/register.html.j2 +49 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Seeders/DemoSeeder.py +38 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Seeders/__init__.py +1 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Serializers.py +60 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Services/NoteService.py +53 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Services/UserService.py +25 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/Services/__init__.py +1 -0
- milpa_core-0.3.1/src/milpa/Modules/Demo/__init__.py +6 -0
- milpa_core-0.3.1/src/milpa/Modules/__init__.py +0 -0
- milpa_core-0.3.1/src/milpa/Resources/Files/Emails/sample.pdf +0 -0
- milpa_core-0.3.1/src/milpa/Resources/Images/Emails/logo.png +0 -0
- milpa_core-0.3.1/src/milpa/Resources/Lang/Emails/master.en.yml +14 -0
- milpa_core-0.3.1/src/milpa/Resources/Lang/Emails/master.es.yml +15 -0
- milpa_core-0.3.1/src/milpa/Resources/Lang/Emails/mastersigned.en.yml +35 -0
- milpa_core-0.3.1/src/milpa/Resources/Lang/Emails/mastersigned.es.yml +41 -0
- milpa_core-0.3.1/src/milpa/Resources/Lang/Emails/test.en.yml +13 -0
- milpa_core-0.3.1/src/milpa/Resources/Lang/Emails/test.es.yml +13 -0
- milpa_core-0.3.1/src/milpa/Resources/Static/welcome.css +19 -0
- milpa_core-0.3.1/src/milpa/Resources/Views/Emails/Trans/Footer/email_footer.html.j2 +31 -0
- milpa_core-0.3.1/src/milpa/Resources/Views/Emails/Trans/Styles/basic.html.j2 +133 -0
- milpa_core-0.3.1/src/milpa/Resources/Views/Emails/Trans/master.html.j2 +40 -0
- milpa_core-0.3.1/src/milpa/Resources/Views/Emails/Trans/mastersigned.html.j2 +35 -0
- milpa_core-0.3.1/src/milpa/Resources/Views/Emails/Trans/test.html.j2 +21 -0
- milpa_core-0.3.1/src/milpa/Resources/Views/Emails/Trans/testsigned.html.j2 +22 -0
- milpa_core-0.3.1/src/milpa/Resources/Views/index.html.j2 +16 -0
- milpa_core-0.3.1/src/milpa/__init__.py +8 -0
- milpa_core-0.3.1/src/milpa/_skeleton/.env.example.tmpl +47 -0
- milpa_core-0.3.1/src/milpa/_skeleton/.gitignore.tmpl +20 -0
- milpa_core-0.3.1/src/milpa/_skeleton/README.md.tmpl +40 -0
- milpa_core-0.3.1/src/milpa/_skeleton/app/Console/Commands/__init__.py.tmpl +0 -0
- milpa_core-0.3.1/src/milpa/_skeleton/app/Console/__init__.py.tmpl +0 -0
- milpa_core-0.3.1/src/milpa/_skeleton/app/Models/User.py.tmpl +22 -0
- milpa_core-0.3.1/src/milpa/_skeleton/app/Models/__init__.py.tmpl +15 -0
- milpa_core-0.3.1/src/milpa/_skeleton/app/Modules/Hello/Http/HelloController.py.tmpl +27 -0
- milpa_core-0.3.1/src/milpa/_skeleton/app/Modules/Hello/Http/__init__.py.tmpl +0 -0
- milpa_core-0.3.1/src/milpa/_skeleton/app/Modules/Hello/__init__.py.tmpl +0 -0
- milpa_core-0.3.1/src/milpa/_skeleton/app/Modules/__init__.py.tmpl +0 -0
- milpa_core-0.3.1/src/milpa/_skeleton/app/Resources/Views/welcome.html.j2.tmpl +27 -0
- milpa_core-0.3.1/src/milpa/_skeleton/app/__init__.py.tmpl +0 -0
- milpa_core-0.3.1/src/milpa/_skeleton/docker-compose.yml.tmpl +25 -0
- milpa_core-0.3.1/src/milpa/_skeleton/jornal.tmpl +17 -0
- milpa_core-0.3.1/src/milpa/_skeleton/logs/.gitkeep.tmpl +1 -0
- milpa_core-0.3.1/src/milpa/_skeleton/migrations/env.py.tmpl +50 -0
- milpa_core-0.3.1/src/milpa/_skeleton/migrations/script.py.mako.tmpl +27 -0
- milpa_core-0.3.1/src/milpa/_skeleton/migrations/versions/.gitkeep.tmpl +1 -0
- milpa_core-0.3.1/src/milpa/_skeleton/pyproject.toml.tmpl +25 -0
- milpa_core-0.3.1/uv.lock +1714 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Entorno y caches locales (la imagen instala sus propias dependencias).
|
|
2
|
+
.venv/
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.pyc
|
|
5
|
+
*.pyo
|
|
6
|
+
|
|
7
|
+
# Secretos y datos que NUNCA deben entrar a la imagen (se montan como volumen).
|
|
8
|
+
.env
|
|
9
|
+
secrets/
|
|
10
|
+
logs/
|
|
11
|
+
|
|
12
|
+
# Cosas del editor / control de versiones.
|
|
13
|
+
.idea/
|
|
14
|
+
.git/
|
|
15
|
+
.gitignore
|
|
16
|
+
.claude
|
|
17
|
+
README.md
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Copia este archivo a .env y ajusta. Estos valores asumen ejecución en DOCKER.
|
|
2
|
+
# Si corres en el HOST (uv run), usa localhost/127.0.0.1 en las URLs.
|
|
3
|
+
|
|
4
|
+
# --- Infraestructura ---
|
|
5
|
+
DATABASE_URL=mysql+pymysql://<user>:<password>@<host>:<port>/<database>
|
|
6
|
+
|
|
7
|
+
# --- Colas / broker-agnostic (ver docs/research/broker_agnostic_plan.md) ---
|
|
8
|
+
# BROKER_URL: vacío => redis local por default. Solo se usa para lo ENCOLADO (los
|
|
9
|
+
# flujos síncronos no lo tocan). Cambia el transporte sin tocar código:
|
|
10
|
+
# Redis: redis://localhost:6379/0
|
|
11
|
+
# RabbitMQ: amqp://guest:guest@localhost:5672// (docker compose ya lo levanta)
|
|
12
|
+
BROKER_URL=
|
|
13
|
+
# Result backend: OPCIONAL (crons fire-and-forget). Vacío => sin backend.
|
|
14
|
+
RESULT_BACKEND_URL=
|
|
15
|
+
# Store de locks para without_overlapping (redis). Vacío => redis local por default.
|
|
16
|
+
LOCK_URL=
|
|
17
|
+
# Reintentos de tasks ante fallos TRANSITORIOS (backoff exponencial con jitter). Son los
|
|
18
|
+
# DEFAULTS de retry_policy(); se pueden pisar A MANO en código por-task. Solo afectan a
|
|
19
|
+
# tasks que OPTAN por reintentar (autoretry_for), NUNCA a crons. 0 => sin reintentos.
|
|
20
|
+
TASK_MAX_RETRIES=3
|
|
21
|
+
TASK_RETRY_BACKOFF=2 # segundos base del 1er reintento (luego se duplica)
|
|
22
|
+
TASK_RETRY_BACKOFF_MAX=600 # tope del backoff entre reintentos (10 min)
|
|
23
|
+
#
|
|
24
|
+
# CLOUD (EDUCATIVO / EN CONSTRUCCIÓN — basado en docs, NO probado en docker, sin
|
|
25
|
+
# mantenimiento garantizado estos primeros meses; solo de referencia):
|
|
26
|
+
# AWS SQS: BROKER_URL=sqs://<AWS_KEY>:<AWS_SECRET>@ (dep: celery[sqs])
|
|
27
|
+
# Azure SB: BROKER_URL=azureservicebus://<SAS>@<namespace> (dep: azure-servicebus)
|
|
28
|
+
# GCP Pub/Sub: BROKER_URL=gcpubsub://projects/<PROJECT_ID> (dep: celery[gcpubsub])
|
|
29
|
+
# ActiveMQ NO es compatible con Celery (AMQP 1.0). Usa RabbitMQ como MQ.
|
|
30
|
+
# Si se omite, el default es la zona del HOST. IMPORTANTE fijarla explícita: un
|
|
31
|
+
# server suele estar en UTC y quien lo monta puede no ser quien programa.
|
|
32
|
+
TIMEZONE=America/Mexico_City
|
|
33
|
+
APP_ENV=local
|
|
34
|
+
# Nombre del proyecto (el default del framework es genérico "App"; pon el tuyo).
|
|
35
|
+
APP_NAME="My App"
|
|
36
|
+
# Locale de fallback de i18n (correos, API, etc.) cuando no se pasa uno explícito.
|
|
37
|
+
APP_FALLBACK_LOCALE=es
|
|
38
|
+
# Locale de Faker para factories/seeders (datos falsos). Cualquier locale de Faker:
|
|
39
|
+
# es_MX, es_ES, en_US, pt_BR, ... Default: es_MX.
|
|
40
|
+
FAKER_LOCALE=es_MX
|
|
41
|
+
# NUNCA en true contra la BD legacy (no debe crear/alterar tablas).
|
|
42
|
+
AUTO_CREATE_TABLES=false
|
|
43
|
+
# Puerto del servidor FastAPI (uvicorn --port).
|
|
44
|
+
APP_PORT=8000
|
|
45
|
+
|
|
46
|
+
# --- HTTP / middlewares (coma-separados; defaults SEGUROS si se omiten) ---
|
|
47
|
+
# CORS: vacío => NO se monta (same-origin). En dev pon el origin de tu front:
|
|
48
|
+
CORS_ALLOW_ORIGINS= # ej: http://localhost:3000,https://app.tudominio.com
|
|
49
|
+
CORS_ALLOW_METHODS=* # en prod restringe: GET,POST,PUT,DELETE
|
|
50
|
+
CORS_ALLOW_HEADERS=*
|
|
51
|
+
CORS_ALLOW_CREDENTIALS=false # true requiere orígenes explícitos (no "*")
|
|
52
|
+
# TrustedHost: "*" = off. En prod fija dominios (anti Host-header attack):
|
|
53
|
+
TRUSTED_HOSTS=* # ej: api.tudominio.com,*.tudominio.com
|
|
54
|
+
# GZip: off por default (mejor en nginx/proxy en prod).
|
|
55
|
+
GZIP_ENABLED=false
|
|
56
|
+
# Security headers (defensivos). El trío seguro (nosniff/X-Frame-Options/Referrer-Policy)
|
|
57
|
+
# va ON por default; todo es apagable. HSTS OFF por default: enciéndelo SOLO sirviendo
|
|
58
|
+
# HTTPS (en prod, tras TLS). CSP vacío = no se manda (es específico de cada app).
|
|
59
|
+
SECURITY_HEADERS_ENABLED=true
|
|
60
|
+
SECURITY_FRAME_OPTIONS=DENY # DENY | SAMEORIGIN | "" (no mandar)
|
|
61
|
+
SECURITY_REFERRER_POLICY=no-referrer
|
|
62
|
+
HSTS_ENABLED=false # true SOLO con HTTPS (en prod)
|
|
63
|
+
HSTS_MAX_AGE=31536000
|
|
64
|
+
HSTS_INCLUDE_SUBDOMAINS=true
|
|
65
|
+
CONTENT_SECURITY_POLICY= # ej: default-src 'self'
|
|
66
|
+
# Errores en formato RFC 9457 (application/problem+json). Base del campo `type`: vacío =>
|
|
67
|
+
# "about:blank". Si publicas docs de errores, apúntalo: https://tudominio.com/problems
|
|
68
|
+
PROBLEM_BASE_URL=
|
|
69
|
+
|
|
70
|
+
# --- Auth propia (login de milpa: JWT API + sesión cookie) ---
|
|
71
|
+
AUTH_GUARD=jwt # guard por default: jwt | session | passport
|
|
72
|
+
AUTH_USER_MODEL=milpa.Models.User.User
|
|
73
|
+
JWT_SECRET= # OBLIGATORIO para emitir/validar JWT propios (genera uno largo y aleatorio)
|
|
74
|
+
JWT_ALGORITHM=HS256
|
|
75
|
+
JWT_TTL_SECONDS=3600
|
|
76
|
+
# Prefijo de TODAS las cookies. Si SESSION_COOKIE/CSRF_COOKIE quedan vacíos, se derivan como
|
|
77
|
+
# <COOKIE_PREFIX>_session / <COOKIE_PREFIX>_csrf. Default: milpa.
|
|
78
|
+
COOKIE_PREFIX=milpa
|
|
79
|
+
# Sesión cookie (carril browser/HTMX). SESSION_SECRET vacío => no se monta la sesión.
|
|
80
|
+
# HttpOnly siempre; SESSION_SECURE=true en prod (HTTPS).
|
|
81
|
+
SESSION_SECRET= # genera uno largo y aleatorio para usar el guard 'session'
|
|
82
|
+
# SESSION_COOKIE= # vacío => <COOKIE_PREFIX>_session
|
|
83
|
+
SESSION_TTL_SECONDS=1209600 # 14 días
|
|
84
|
+
SESSION_SECURE=false # true en PROD (HTTPS)
|
|
85
|
+
SESSION_SAME_SITE=lax # lax | strict | none
|
|
86
|
+
# CSRF (double-submit): protege el carril cookie/sesión; exime bearer/JWT.
|
|
87
|
+
CSRF_ENABLED=true
|
|
88
|
+
# CSRF_COOKIE= # vacío => <COOKIE_PREFIX>_csrf
|
|
89
|
+
CSRF_HEADER=X-CSRF-Token
|
|
90
|
+
|
|
91
|
+
# --- Auth: validar tokens OAuth2 de Laravel Passport (tokens EXTERNOS, migración) ---
|
|
92
|
+
# Copia la llave pública del legacy (storage/oauth-public.key) a ./secrets/
|
|
93
|
+
# y apunta aquí a su ruta.
|
|
94
|
+
PASSPORT_PUBLIC_KEY_PATH=/secrets/oauth-public.key
|
|
95
|
+
# PASSPORT_EXPECTED_AUDIENCE=
|
|
96
|
+
|
|
97
|
+
# --- Logging (Loguru) ---
|
|
98
|
+
LOG_LEVEL=INFO
|
|
99
|
+
# LOG_JSON=true agrega logs/app.jsonl (JSON Lines) para Loki/Grafana.
|
|
100
|
+
LOG_JSON=false
|
|
101
|
+
|
|
102
|
+
# --- Correo ---
|
|
103
|
+
# MAIL_DRIVER: cómo se manda. smtp = SMTP real | log = lo escribe en el log (dev sin
|
|
104
|
+
# SMTP, cross-platform) | null = no-op (lo descarta).
|
|
105
|
+
MAIL_DRIVER=smtp
|
|
106
|
+
# En local apunta a Mailpit (puertos del docker-compose).
|
|
107
|
+
MAILPIT_SMTP_PORT=1025
|
|
108
|
+
MAILPIT_UI_PORT=8025
|
|
109
|
+
MAIL_HOST=<host> # ej. localhost (host) o mailpit (docker)
|
|
110
|
+
MAIL_PORT=1025
|
|
111
|
+
MAIL_USERNAME=
|
|
112
|
+
MAIL_PASSWORD=
|
|
113
|
+
MAIL_ENCRYPTION= # "" sin cifrado (Mailpit) | tls (STARTTLS) | ssl (SMTPS)
|
|
114
|
+
MAIL_FROM_ADDRESS=no-reply@example.com
|
|
115
|
+
MAIL_FROM_NAME="My App"
|
|
116
|
+
# Destinatarios de sistema (fallback si system_config no trae el name; CCO por APP_ENV si vacío).
|
|
117
|
+
ADMIN_SYSTEM_MAILS=
|
|
118
|
+
MAIL_CCO_RECIPIENT=
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
# Corre los MISMOS guardrails que en local (README §7) en cada push a main y en cada PR.
|
|
4
|
+
# Sin `docker build`: por diseño la app NO va en Docker (README §5; Docker solo infra).
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
pull_request:
|
|
9
|
+
|
|
10
|
+
# Cancela corridas viejas del mismo ref si llega un push nuevo.
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ci-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
quality:
|
|
17
|
+
name: Lint + Types + Imports + Tests
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
# Sin .env en CI: damos un sqlite dummy explícito (DATABASE_URL ya tiene default, pero
|
|
20
|
+
# lo dejamos claro). Basta para importar (el engine es perezoso) y los tests son sin BD.
|
|
21
|
+
env:
|
|
22
|
+
DATABASE_URL: "sqlite://"
|
|
23
|
+
steps:
|
|
24
|
+
- name: Checkout
|
|
25
|
+
uses: actions/checkout@v5
|
|
26
|
+
|
|
27
|
+
- name: Instalar uv (con Python 3.14 + caché)
|
|
28
|
+
uses: astral-sh/setup-uv@v8.1.0
|
|
29
|
+
with:
|
|
30
|
+
python-version: "3.14"
|
|
31
|
+
enable-cache: true
|
|
32
|
+
|
|
33
|
+
- name: Sincronizar dependencias (incluye grupo dev; reproducible con el lock)
|
|
34
|
+
run: uv sync --frozen
|
|
35
|
+
|
|
36
|
+
# Los 5 guardrails, en pasos separados para ver de un vistazo cuál falla.
|
|
37
|
+
- name: Ruff format (solo verifica)
|
|
38
|
+
run: uv run ruff format --check .
|
|
39
|
+
|
|
40
|
+
- name: Ruff lint
|
|
41
|
+
run: uv run ruff check .
|
|
42
|
+
|
|
43
|
+
- name: Mypy (estricto)
|
|
44
|
+
run: uv run mypy
|
|
45
|
+
|
|
46
|
+
- name: Fronteras entre módulos (import-linter)
|
|
47
|
+
run: uv run lint-imports
|
|
48
|
+
|
|
49
|
+
- name: Pytest (rápidos, sin BD)
|
|
50
|
+
run: uv run pytest
|
|
51
|
+
|
|
52
|
+
# --- Gates de empaquetado (Fase D): el wheel se construye e instala/usa en limpio ---
|
|
53
|
+
- name: Build sanity (uv build construye sdist + wheel)
|
|
54
|
+
run: uv build
|
|
55
|
+
|
|
56
|
+
- name: Smoke de instalación (wheel limpio + scaffolder milpa new)
|
|
57
|
+
run: |
|
|
58
|
+
uv venv /tmp/milpa-smoke
|
|
59
|
+
uv pip install --python /tmp/milpa-smoke/bin/python dist/*.whl
|
|
60
|
+
/tmp/milpa-smoke/bin/python -c "import milpa; print('milpa', milpa.__version__)"
|
|
61
|
+
( cd /tmp && /tmp/milpa-smoke/bin/milpa new smokeapp )
|
|
62
|
+
test -f /tmp/smokeapp/app/Modules/Hello/Http/HelloController.py
|
|
63
|
+
# El controller generado debe IMPORTAR (ejecuta @Controller/@Get): cubre que el
|
|
64
|
+
# skeleton no esté roto, no solo que el archivo exista.
|
|
65
|
+
( cd /tmp/smokeapp && /tmp/milpa-smoke/bin/python -c "import app.Modules.Hello.Http.HelloController; print('scaffolder OK')" )
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
name: Release (PyPI)
|
|
2
|
+
|
|
3
|
+
# Publica a PyPI cuando empujas un tag de versión (p. ej. `git tag v0.3.0a0 && git push --tags`).
|
|
4
|
+
# Usa Trusted Publishing (OIDC): NO hay tokens ni secretos — PyPI confía en este workflow.
|
|
5
|
+
# Requisito una sola vez: configurar el "pending publisher" en PyPI (ver docs/prerelease/07).
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
tags: ["v*"]
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
release:
|
|
12
|
+
name: Build + Publish (Trusted Publishing OIDC)
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
# 'environment' protege el publish: puedes exigir aprobación manual en Settings → Environments.
|
|
15
|
+
environment: pypi
|
|
16
|
+
permissions:
|
|
17
|
+
id-token: write # OBLIGATORIO para OIDC (Trusted Publishing, sin tokens)
|
|
18
|
+
contents: read # con un bloque permissions explícito, GitHub recorta el resto a 'none'
|
|
19
|
+
env:
|
|
20
|
+
DATABASE_URL: "sqlite://"
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout
|
|
23
|
+
uses: actions/checkout@v5
|
|
24
|
+
|
|
25
|
+
- name: Instalar uv (Python 3.14 + caché)
|
|
26
|
+
uses: astral-sh/setup-uv@v8.1.0
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.14"
|
|
29
|
+
enable-cache: true
|
|
30
|
+
|
|
31
|
+
- name: Sincronizar dependencias (reproducible con el lock)
|
|
32
|
+
run: uv sync --frozen
|
|
33
|
+
|
|
34
|
+
# --- Los 5 guardrails ANTES de publicar: no se publica algo roto ---
|
|
35
|
+
- name: Ruff format
|
|
36
|
+
run: uv run ruff format --check .
|
|
37
|
+
- name: Ruff lint
|
|
38
|
+
run: uv run ruff check .
|
|
39
|
+
- name: Mypy
|
|
40
|
+
run: uv run mypy
|
|
41
|
+
- name: Import-linter
|
|
42
|
+
run: uv run lint-imports
|
|
43
|
+
- name: Pytest
|
|
44
|
+
run: uv run pytest
|
|
45
|
+
|
|
46
|
+
- name: Construir sdist + wheel
|
|
47
|
+
run: uv build --no-sources
|
|
48
|
+
|
|
49
|
+
# uv detecta el OIDC de GitHub Actions y publica vía Trusted Publishing (sin tokens).
|
|
50
|
+
# (el default es --trusted-publishing automatic; no se pasa flag).
|
|
51
|
+
# Tip primer release: si falla el OIDC, cambia temporalmente a
|
|
52
|
+
# `uv publish --trusted-publishing always` para ver el error exacto.
|
|
53
|
+
- name: Publicar a PyPI
|
|
54
|
+
run: uv publish
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Entorno Python
|
|
2
|
+
.venv/
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.pyc
|
|
5
|
+
*.pyo
|
|
6
|
+
|
|
7
|
+
# Caches de herramientas (se regeneran solas; NO se versionan). graphify también las
|
|
8
|
+
# IGNORA al indexar porque respeta .gitignore — antes ensuciaban el grafo con nodos basura.
|
|
9
|
+
.import_linter_cache/
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
.pytest_cache/
|
|
12
|
+
.mypy_cache/
|
|
13
|
+
.claude/settings.local.json
|
|
14
|
+
|
|
15
|
+
# Secretos y configuración local (NUNCA al repo)
|
|
16
|
+
.env
|
|
17
|
+
# Ignora TODO el contenido de secrets/ (llaves, etc.) pero conserva la carpeta vacía.
|
|
18
|
+
secrets/*
|
|
19
|
+
!secrets/.gitkeep
|
|
20
|
+
|
|
21
|
+
# Logs (no versionamos contenido, sí la carpeta)
|
|
22
|
+
logs/*
|
|
23
|
+
!logs/.gitkeep
|
|
24
|
+
|
|
25
|
+
# BD sqlite local (p. ej. la del demo: DATABASE_URL=sqlite:///milpa.db)
|
|
26
|
+
*.db
|
|
27
|
+
*.sqlite3
|
|
28
|
+
|
|
29
|
+
# Runtime: PID del servidor web (lo escribe start.sh, lo lee stop.sh)
|
|
30
|
+
app.pid
|
|
31
|
+
|
|
32
|
+
# Handoff local entre sesiones (estado actual + pendientes); NO se versiona.
|
|
33
|
+
NEXT_SESSION.md
|
|
34
|
+
|
|
35
|
+
# Editor / SO
|
|
36
|
+
.idea/
|
|
37
|
+
.DS_Store
|
|
38
|
+
docs/
|
|
39
|
+
|
|
40
|
+
# Sitio generado por MkDocs (se construye en CI; no se versiona)
|
|
41
|
+
site/
|
|
42
|
+
|
|
43
|
+
# Artefactos de build/empaquetado (uv build)
|
|
44
|
+
/dist/
|
|
45
|
+
*.egg-info/
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Todos los cambios notables de **milpa** se documentan aquí.
|
|
4
|
+
|
|
5
|
+
El formato sigue [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/) y el proyecto usa
|
|
6
|
+
[Versionado Semántico](https://semver.org/lang/es/). En `0.x` la API puede cambiar entre minors.
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.3.1] - 2026-06-02
|
|
11
|
+
|
|
12
|
+
Primer release **publicado a PyPI**. Consolida el paquete instalable (extraído en `0.3.0a0`) con el
|
|
13
|
+
set completo de patrones estilo milpa, la API REST estilo DRF, el demo integral y el manual.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **Patrones estilo milpa** (OPT-IN, auto-descubribles): `Events`/`Observers` (1:N, transporte
|
|
18
|
+
adaptativo worker/síncrono), `Mediator` (command bus 1:1, transport-neutral HTTP+CLI) y `Pipeline`
|
|
19
|
+
(modelo cebolla). No impuestos: patrones que un arquitecto puede sugerir.
|
|
20
|
+
- **Background**: `@job` (on-demand, `.dispatch()`) separado a propósito de `@cron_task` (agendado).
|
|
21
|
+
- **API REST (estilo DRF)**: versionado (`@Controller(version="v1")`), rate limiting (`@rate_limit`),
|
|
22
|
+
filtering DSL (`FilterQueryModel`) + paginación por cursor, negociación de contenido (una ruta
|
|
23
|
+
sirve JSON o HTML según `Accept`) y serializers Pydantic v2 (`computed_field`).
|
|
24
|
+
- **Módulo `Demo`** integral (reemplaza a `Example`): users/notes ejercitando auth dual, RBAC+ABAC,
|
|
25
|
+
los tres patrones, correos por evento + mailables firmados, y UI HTMX + Alpine + Pico.css.
|
|
26
|
+
- **Manual** ampliado (mkdocs): eventos/observers, mediator, pipeline, jobs, versionado, rate
|
|
27
|
+
limiting, filtrado/paginación, negociación de contenido, serializadores y errores RFC 9457.
|
|
28
|
+
- **Skeleton del scaffolder**: `.env.example` con sección de correo (`MAIL_DRIVER=log` por default,
|
|
29
|
+
que imprime en la terminal de `jornal serve`; Mailpit para inbox web) y `docker-compose.yml`
|
|
30
|
+
(redis + mailpit) para la infra de dev.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- **`milpa new --demo` funciona out-of-the-box**: `faker` se incluye en el grupo dev del proyecto
|
|
35
|
+
generado y `Core/Database/Faker.py` da un error accionable si falta (las factories/seeders lo
|
|
36
|
+
necesitan; es dependencia de dev, no de producción).
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- Heredado de `0.3.0a0`: `DATABASE_URL` con default `sqlite`, `pymysql` movido al extra
|
|
41
|
+
`milpa-core[mysql]` (core agnóstico de dialecto), y el paquete importable `app` → `milpa`.
|
|
42
|
+
|
|
43
|
+
## [0.3.0a0] - 2026-06-01
|
|
44
|
+
|
|
45
|
+
Primera versión **INSTALABLE**: milpa se extrae como paquete (`pip install milpa-core`) con un
|
|
46
|
+
scaffolder de proyectos. Alpha — la API puede cambiar entre versiones.
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- **Paquete instalable** (`pip install milpa-core` / `uv add milpa-core`): src-layout (`src/milpa`),
|
|
51
|
+
`[build-system]` hatchling, comando de consola `milpa`, versión single-source en `__init__`.
|
|
52
|
+
- **`milpa new <app>`** — scaffolder que genera un proyecto listo para correr (estilo
|
|
53
|
+
`laravel new` / `django-admin startproject`) desde un skeleton embebido en el paquete.
|
|
54
|
+
- **Config-seam**: el Core resuelve módulos/modelos/recursos/migraciones del proyecto desde
|
|
55
|
+
`Settings`/`.env` (`MODULES_PACKAGE`, `MODELS_PACKAGE`, `USER_VIEWS_DIR`, …) en vez de rutas
|
|
56
|
+
hardcodeadas — un proyecto externo apunta milpa a su propio código. Nuevo `milpa.Core.Discovery`.
|
|
57
|
+
- Pipeline de release a PyPI (Trusted Publishing OIDC) + gates de empaquetado en CI
|
|
58
|
+
(`uv build` + smoke de instalación).
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
|
|
62
|
+
- **`DATABASE_URL`** ahora tiene default `sqlite:///./milpa.db` (zero-config: milpa arranca sin
|
|
63
|
+
configurar nada, como Django en dev). En QA/prod se pone el motor real en `.env`.
|
|
64
|
+
- **`pymysql`** sale del core → extra opcional `milpa-core[mysql]` (el core queda agnóstico de dialecto).
|
|
65
|
+
- El paquete importable se renombró `app` → `milpa`.
|
|
66
|
+
|
|
67
|
+
## [0.2.0] - 2026-05-30
|
|
68
|
+
|
|
69
|
+
DX de la consola: más comandos `jornal` (estilo `artisan`) y una lista coherente y legible.
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- **`jornal route list`** — lista las rutas HTTP montadas (método/path/nombre) en tabla rich,
|
|
74
|
+
construyendo la app real (≈ `php artisan route:list`).
|
|
75
|
+
- **`jornal db fresh`** — recrea la BD: baja todo, re-migra y siembra. Destructivo; pide
|
|
76
|
+
confirmación salvo `--force` (≈ `php artisan migrate:fresh --seed`).
|
|
77
|
+
- **`jornal make controller|model|module`** — scaffolding idempotente de stubs idiomáticos
|
|
78
|
+
(los controllers se auto-montan por el Registry; nunca sobrescribe un archivo existente)
|
|
79
|
+
(≈ `php artisan make:*`).
|
|
80
|
+
|
|
81
|
+
### Changed
|
|
82
|
+
|
|
83
|
+
- **`jornal list`** ahora incluye también los comandos raíz (p. ej. `serve`, `list`), no solo los
|
|
84
|
+
agrupados; y estrena título: **🌽 Labores de la milpa**.
|
|
85
|
+
- Descripciones (`help`) de **todos** los comandos normalizadas a un estilo coherente
|
|
86
|
+
`<imperativo>. (≈ php artisan X)`.
|
|
87
|
+
|
|
88
|
+
### Docs
|
|
89
|
+
|
|
90
|
+
- Guía de BD: cuándo sembrar un **catálogo fijo** en la propia migración con `op.bulk_insert`
|
|
91
|
+
(vs. seeder + factory para datos de ejemplo).
|
|
92
|
+
|
|
93
|
+
### Tests
|
|
94
|
+
|
|
95
|
+
- Cobertura (sin BD) de los comandos nuevos (registro de `route`/`db`/`make`, delegación de
|
|
96
|
+
`db fresh`, pureza de los stubs) y del `PassportGuard` (sin bearer → `None`, token válido →
|
|
97
|
+
user, token inválido → 401).
|
|
98
|
+
|
|
99
|
+
## [0.1.0] - 2026-05-30
|
|
100
|
+
|
|
101
|
+
Primera versión: el esqueleto del microframework + auth, demo y herramientas de datos.
|
|
102
|
+
|
|
103
|
+
### Added
|
|
104
|
+
|
|
105
|
+
#### Kernel / HTTP
|
|
106
|
+
- App factory FastAPI (`create_app`) con auto-discovery de routers por módulo.
|
|
107
|
+
- Routing **class-based** estilo Spring: `@Controller` + `@Get/@Post/@Put/@Patch/@Delete`
|
|
108
|
+
(convive con el estilo `APIRouter`).
|
|
109
|
+
- Errores en **RFC 9457** (`application/problem+json`): `DomainError` y subclases + handler global
|
|
110
|
+
(dominio, validación 422, `HTTPException`, catch-all 500).
|
|
111
|
+
- Middlewares: CORS / TrustedHost / GZip + **SecurityHeaders** (nosniff/X-Frame-Options/HSTS/CSP).
|
|
112
|
+
|
|
113
|
+
#### Auth (modelo Sanctum) + autorización
|
|
114
|
+
- **JWT** propio (HS256), guard `jwt`, `Auth.attempt`; **sesión cookie** firmada + **CSRF**
|
|
115
|
+
double-submit, guard `session`; **PassportGuard** (RS256 externo) para migrar Laravel.
|
|
116
|
+
- `Hash` (argon2id + verifica bcrypt `$2y$` de Laravel), `UserProvider` (SQLAlchemy, overridable),
|
|
117
|
+
`current_user`/`CurrentUser`, `guarded(name)`.
|
|
118
|
+
- **RBAC** (`@Roles`/`require_roles`) + **ABAC** (`Gate.define/authorize`, `@Can`).
|
|
119
|
+
- Nombres de cookie configurables con prefijo (`COOKIE_PREFIX`, default `milpa`).
|
|
120
|
+
|
|
121
|
+
#### Datos (estilo Spring/Laravel)
|
|
122
|
+
- `Repository[Model, Id]` tipado: `get/all/add/delete/find_or_fail/first_or_create` + `paginate()`
|
|
123
|
+
(offset/limit sin COUNT, `Page`). Sesión ambiente (`@transactional`/`session_scope`), soft-delete,
|
|
124
|
+
timestamps. Engine **agnóstico del motor**.
|
|
125
|
+
- **Migraciones** con Alembic (`jornal migrate make/run/status/rollback`).
|
|
126
|
+
- **Seeders** (`jornal db seed`) y **Factories** `Factory[Model]` con **Faker** (locale configurable
|
|
127
|
+
vía `FAKER_LOCALE`).
|
|
128
|
+
|
|
129
|
+
#### Tareas / consola / correo / i18n
|
|
130
|
+
- Celery (broker-agnóstico) + crons `@cron_task` con **retry/backoff** (`retry_policy`).
|
|
131
|
+
- Consola `jornal` (Typer) con auto-discovery y salida en tabla **rich**.
|
|
132
|
+
- Mail (`Mailable`/`Mailer`, drivers smtp/log/null, Jinja2, i18n) y Logging (loguru, JSON).
|
|
133
|
+
|
|
134
|
+
#### Demo + tooling
|
|
135
|
+
- Módulo **Demo** corrible (SQLite): dashboard con auth dual, RBAC+ABAC, **búsqueda en vivo** +
|
|
136
|
+
**scroll infinito** (HTMX), branding StackCraft (Pico.css + Alpine). 100 usuarios vía factories.
|
|
137
|
+
- **CI** (GitHub Actions): ruff + mypy strict + import-linter + pytest. Sitio de docs (MkDocs
|
|
138
|
+
Material) publicable a GitHub Pages.
|
|
139
|
+
|
|
140
|
+
### Notas
|
|
141
|
+
- Todo es **síncrono** (SQLAlchemy + Celery). Tests **sin base de datos** (fakes + monkeypatch).
|
|
142
|
+
|
|
143
|
+
[Unreleased]: https://github.com/calcifux/milpa/compare/v0.3.1...HEAD
|
|
144
|
+
[0.3.1]: https://github.com/calcifux/milpa/compare/v0.2.0...v0.3.1
|
|
145
|
+
[0.2.0]: https://github.com/calcifux/milpa/compare/v0.1.0...v0.2.0
|
|
146
|
+
[0.1.0]: https://github.com/calcifux/milpa/releases/tag/v0.1.0
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Código de Conducta
|
|
2
|
+
|
|
3
|
+
## Nuestro compromiso
|
|
4
|
+
|
|
5
|
+
Como miembros, contribuyentes y mantenedores, nos comprometemos a hacer de la
|
|
6
|
+
participación en **milpa** una experiencia libre de acoso,
|
|
7
|
+
acogedora y respetuosa para todas las personas, sin importar su origen o
|
|
8
|
+
identidad. Nos comprometemos a actuar e interactuar de formas que construyan una
|
|
9
|
+
comunidad abierta, amable, diversa y sana.
|
|
10
|
+
|
|
11
|
+
## Nuestros estándares
|
|
12
|
+
|
|
13
|
+
Ejemplos de comportamiento que ayudan a crear un ambiente positivo:
|
|
14
|
+
|
|
15
|
+
- Mostrar empatía y amabilidad hacia los demás
|
|
16
|
+
- Respetar opiniones, puntos de vista y experiencias distintas
|
|
17
|
+
- Dar y aceptar con gracia retroalimentación constructiva
|
|
18
|
+
- Asumir la responsabilidad, disculparse con quienes se vean afectados por
|
|
19
|
+
nuestros errores y aprender de ellos
|
|
20
|
+
- Enfocarse en lo que es mejor para la comunidad en su conjunto
|
|
21
|
+
|
|
22
|
+
El acoso, las conductas abusivas o irrespetuosas, los ataques personales o
|
|
23
|
+
políticos, publicar información privada de terceros sin su consentimiento y
|
|
24
|
+
cualquier otra conducta que una persona razonable consideraría inapropiada en un
|
|
25
|
+
entorno profesional **no se toleran**.
|
|
26
|
+
|
|
27
|
+
## Estándar adoptado
|
|
28
|
+
|
|
29
|
+
Este proyecto adopta el **[Contributor Covenant, versión 2.1](https://www.contributor-covenant.org/es/version/2/1/code_of_conduct/)**.
|
|
30
|
+
El texto completo —con los estándares detallados y las cuatro guías de aplicación
|
|
31
|
+
(Corrección → Advertencia → Expulsión temporal → Expulsión permanente)— aplica a
|
|
32
|
+
este proyecto. Por favor léelo ahí.
|
|
33
|
+
|
|
34
|
+
## Alcance
|
|
35
|
+
|
|
36
|
+
Este Código de Conducta aplica en todos los espacios del proyecto (issues, pull
|
|
37
|
+
requests, discusiones, código) y cuando una persona representa oficialmente al
|
|
38
|
+
proyecto en espacios públicos.
|
|
39
|
+
|
|
40
|
+
## Aplicación
|
|
41
|
+
|
|
42
|
+
Las personas mantenedoras son responsables de aclarar y hacer cumplir estos
|
|
43
|
+
estándares, y pueden eliminar, editar o rechazar contribuciones que no se
|
|
44
|
+
alineen con este Código de Conducta.
|
|
45
|
+
|
|
46
|
+
Las instancias de comportamiento abusivo, de acoso o de cualquier otra forma
|
|
47
|
+
inaceptable pueden reportarse **en privado** a la persona mantenedora
|
|
48
|
+
(`@calcifux`) vía GitHub (abrir un *private security advisory* o contactarla
|
|
49
|
+
directamente).
|
|
50
|
+
<!-- TODO: agrega un email de contacto dedicado si prefieres uno en vez de GitHub. -->
|
|
51
|
+
Todas las quejas serán revisadas e investigadas de forma rápida y justa. Las
|
|
52
|
+
personas mantenedoras están obligadas a respetar la privacidad y la seguridad de
|
|
53
|
+
quien reporta.
|
|
54
|
+
|
|
55
|
+
## Atribución
|
|
56
|
+
|
|
57
|
+
Este Código de Conducta es una adaptación del
|
|
58
|
+
[Contributor Covenant](https://www.contributor-covenant.org/es/), versión 2.1.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Contribuir a milpa
|
|
2
|
+
|
|
3
|
+
¡Gracias por tu interés en contribuir! Este documento explica cómo levantar el proyecto
|
|
4
|
+
en local, las convenciones que seguimos y cómo enviar un Pull Request con las mejores
|
|
5
|
+
probabilidades de merge.
|
|
6
|
+
|
|
7
|
+
> Si vas a tocar un subsistema, lee primero su página en
|
|
8
|
+
> [`documentation/`](documentation/README.md): ahí está el "cómo funciona".
|
|
9
|
+
|
|
10
|
+
## Inicio rápido
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
git clone https://github.com/calcifux/milpa.git
|
|
14
|
+
cd milpa
|
|
15
|
+
uv sync # crea el venv y resuelve deps (incluye las de dev)
|
|
16
|
+
cp .env.example .env # ajusta al menos DATABASE_URL
|
|
17
|
+
uv run pytest # si la suite pasa, ya puedes desarrollar
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Si no usas `uv`, ver [documentation/02-instalacion.md](documentation/02-instalacion.md)
|
|
21
|
+
(opción pip). Con `uv`, antepón `uv run` a los comandos; con el venv activo, omítelo.
|
|
22
|
+
|
|
23
|
+
> **¿Quieres ver algo funcionando ya?** Corre el demo (sqlite, sin infra):
|
|
24
|
+
> ```bash
|
|
25
|
+
> uv run python jornal migrate run && uv run python jornal db seed && uv run python jornal serve
|
|
26
|
+
> # http://127.0.0.1:8000 · admin@demo.test / password
|
|
27
|
+
> ```
|
|
28
|
+
> Auth dual (JWT + sesión/CSRF), RBAC + ABAC, búsqueda + scroll infinito, factories con Faker.
|
|
29
|
+
|
|
30
|
+
## Requisitos
|
|
31
|
+
|
|
32
|
+
- **Python 3.14+**
|
|
33
|
+
- **[uv](https://docs.astral.sh/uv/)** (recomendado) como gestor de entorno y deps
|
|
34
|
+
- **Docker NO** es necesario para los tests: son unitarios y **sin base de datos** (usan
|
|
35
|
+
fakes y monkeypatch, no servicios vivos). Docker solo hace falta para correr la app de
|
|
36
|
+
verdad (Redis + Mailpit), no para contribuir/testear.
|
|
37
|
+
- **Git** con auth SSH o HTTPS a GitHub
|
|
38
|
+
|
|
39
|
+
## Estructura del repo
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
app/
|
|
43
|
+
Core/ ← EL FRAMEWORK (kernel genérico, reutilizable)
|
|
44
|
+
Models/ ← modelos SQLAlchemy compartidos (auto-discovery)
|
|
45
|
+
Dictionaries/ ← constantes de dominio compartidas
|
|
46
|
+
Modules/ ← los módulos del proyecto (independientes entre sí)
|
|
47
|
+
Resources/ ← vistas/lang/estáticos compartidos
|
|
48
|
+
Tests/ ← espeja app/ 1:1; tests unitarios sin BD
|
|
49
|
+
documentation/ ← guía estilo Laravel (pública)
|
|
50
|
+
jornal ← entrypoint de consola (el "artisan")
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Detalle en [documentation/04-estructura-directorios.md](documentation/04-estructura-directorios.md).
|
|
54
|
+
|
|
55
|
+
## Las dos fronteras (no las rompas)
|
|
56
|
+
|
|
57
|
+
`import-linter` las fuerza en CI:
|
|
58
|
+
|
|
59
|
+
1. **El kernel no depende de los módulos**: `app.Core` / `app.Models` / `app.Dictionaries`
|
|
60
|
+
no importan `app.Modules`.
|
|
61
|
+
2. **Los módulos son independientes entre sí**: `app.Modules.A` no importa `app.Modules.B`.
|
|
62
|
+
|
|
63
|
+
Si dos módulos necesitan compartir algo, ese algo sube al kernel compartido. Ver
|
|
64
|
+
[documentation/06-monolito-modular.md](documentation/06-monolito-modular.md).
|
|
65
|
+
|
|
66
|
+
## Ramas y commits
|
|
67
|
+
|
|
68
|
+
- `main` siempre verde. No hagas push directo; abre un PR.
|
|
69
|
+
- Ramas de feature: `feat/mail-cc-bcc`, `fix/cron-lock-timeout`, `docs/install-guide`.
|
|
70
|
+
- [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `docs:`,
|
|
71
|
+
`refactor:`, `test:`, `ci:`, `chore:`.
|
|
72
|
+
|
|
73
|
+
## Estilo de código
|
|
74
|
+
|
|
75
|
+
- Identificadores en **inglés**; comentarios y docstrings en **español**, explicando el
|
|
76
|
+
*porqué* (no abreviar).
|
|
77
|
+
- Sin emojis en código/comentarios/docstrings.
|
|
78
|
+
- Tipos completos: `mypy` corre en modo **estricto** sobre `app/` y `Tests/Core`.
|
|
79
|
+
- Un archivo por clase/responsabilidad (estilo Laravel/PascalCase en `app/`).
|
|
80
|
+
- Formato e imports los maneja **Ruff** (no formatees a mano).
|
|
81
|
+
|
|
82
|
+
## Guardrails (lo que valida CI)
|
|
83
|
+
|
|
84
|
+
Antes de abrir el PR, corre todo y déjalo verde:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
uv run ruff format . # formato | --check solo verifica (modo CI)
|
|
88
|
+
uv run ruff check . # lint | --fix arregla lo auto-arreglable
|
|
89
|
+
uv run mypy # tipos (estricto)
|
|
90
|
+
uv run lint-imports # fronteras entre módulos
|
|
91
|
+
uv run pytest # tests (rápidos, sin BD)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Todo de una:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
uv run ruff format --check . && uv run ruff check . && uv run mypy && uv run lint-imports && uv run pytest
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Contribuir al Core
|
|
101
|
+
|
|
102
|
+
milpa es un **framework**: las contribuciones van al **kernel** (`app/Core`), a sus tests
|
|
103
|
+
(`Tests/Core`) y a la documentación. **No** se trata de crear módulos de negocio nuevos —
|
|
104
|
+
eso lo hace cada proyecto que *usa* milpa, en su propio repo. `app/Modules/Example` es
|
|
105
|
+
solo el módulo de **referencia/demo**: tócalo únicamente para demostrar una capacidad del
|
|
106
|
+
Core, no para meter features de dominio.
|
|
107
|
+
|
|
108
|
+
Al tocar el Core:
|
|
109
|
+
|
|
110
|
+
1. **Mantén el Core genérico.** Nada de dominio ni de un proyecto en particular (ni
|
|
111
|
+
nombres, ni reglas de negocio): el kernel debe servir igual a cualquier proyecto. Si
|
|
112
|
+
dudas si algo es "del framework" o "de un proyecto", probablemente no va en Core.
|
|
113
|
+
2. **Respeta la frontera `app.Core ↛ app.Modules`**: el kernel no importa módulos (el
|
|
114
|
+
discovery es dinámico, no por imports estáticos). Lo valida `lint-imports`.
|
|
115
|
+
3. **Espeja la estructura por capas**: cada subsistema vive en `app/Core/<Subsistema>/`
|
|
116
|
+
con un `__init__.py` que expone su API pública.
|
|
117
|
+
4. **Agrega tests** en `Tests/Core/...` (sin BD) y, si cambia comportamiento público,
|
|
118
|
+
**documéntalo** en `documentation/`.
|
|
119
|
+
|
|
120
|
+
Para entender un subsistema antes de tocarlo, lee su página en
|
|
121
|
+
[documentation/](documentation/README.md).
|
|
122
|
+
|
|
123
|
+
## Tests
|
|
124
|
+
|
|
125
|
+
- Espeja `app/` en `Tests/` (misma ruta). Tests **unitarios y sin BD**: usa fakes y
|
|
126
|
+
monkeypatch, no levantes Postgres/Redis.
|
|
127
|
+
- Los tests escriben su log en `logs/tests/` (lo fija `Tests/conftest.py`), no en
|
|
128
|
+
`logs/app.log`.
|
|
129
|
+
- Corre uno solo: `uv run pytest Tests/Core/Mail/test_Mailer.py -x`.
|
|
130
|
+
|
|
131
|
+
## Checklist del PR
|
|
132
|
+
|
|
133
|
+
- [ ] `ruff format --check .` y `ruff check .` pasan
|
|
134
|
+
- [ ] `mypy` pasa (estricto)
|
|
135
|
+
- [ ] `lint-imports` pasa (no rompiste las fronteras)
|
|
136
|
+
- [ ] `pytest` pasa
|
|
137
|
+
- [ ] Subject en Conventional Commits
|
|
138
|
+
- [ ] Sin datos personales, secretos ni credenciales
|
|
139
|
+
- [ ] Si cambió comportamiento público, actualizaste `documentation/`
|
|
140
|
+
|
|
141
|
+
## Código de Conducta
|
|
142
|
+
|
|
143
|
+
Este proyecto adopta el [Código de Conducta](CODE_OF_CONDUCT.md) (Contributor Covenant
|
|
144
|
+
2.1). Al participar, aceptas cumplirlo.
|
|
145
|
+
|
|
146
|
+
## Licencia
|
|
147
|
+
|
|
148
|
+
Al contribuir aceptas que tu aporte queda bajo la [Licencia MIT](LICENSE).
|
milpa_core-0.3.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 @Calcifux (Carlos Guillermo Reyes Ramiro)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|