core-framework 0.12.1__py3-none-any.whl → 0.12.3__py3-none-any.whl

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.
core/__init__.py CHANGED
@@ -20,7 +20,21 @@ Enterprise Features (v0.3.0+):
20
20
 
21
21
  from core.models import Model, Field, SoftDeleteMixin, SoftDeleteManager, TenantSoftDeleteManager
22
22
  from core.serializers import InputSchema, OutputSchema, Serializer
23
- from core.views import APIView, ViewSet, ModelViewSet, action
23
+ from core.views import (
24
+ APIView,
25
+ ViewSet,
26
+ ModelViewSet,
27
+ ReadOnlyModelViewSet,
28
+ CreateModelViewSet,
29
+ ListModelViewSet,
30
+ ListCreateModelViewSet,
31
+ RetrieveUpdateModelViewSet,
32
+ RetrieveDestroyModelViewSet,
33
+ RetrieveUpdateDestroyModelViewSet,
34
+ SearchModelViewSet,
35
+ BulkModelViewSet,
36
+ action,
37
+ )
24
38
  from core.routing import Router, AutoRouter
25
39
  from core.permissions import Permission, IsAuthenticated, AllowAny, IsAdmin, IsOwner, HasRole
26
40
  from core.dependencies import Depends, get_db, get_current_user
@@ -84,6 +98,25 @@ from core.datetime import (
84
98
  get_timezone,
85
99
  )
86
100
 
101
+ # Middleware - Sistema Django-style
102
+ from core.middleware import (
103
+ BaseMiddleware,
104
+ configure_middleware,
105
+ register_middleware,
106
+ apply_middlewares,
107
+ get_middleware_stack_info,
108
+ print_middleware_stack,
109
+ # Pre-built middlewares
110
+ TimingMiddleware,
111
+ RequestIDMiddleware,
112
+ LoggingMiddleware,
113
+ MaintenanceModeMiddleware,
114
+ SecurityHeadersMiddleware,
115
+ )
116
+
117
+ # Auth - ViewSet
118
+ from core.auth.views import AuthViewSet
119
+
87
120
  # Auth - Sistema plugável de autenticação
88
121
  from core.auth import (
89
122
  # Config
@@ -123,6 +156,7 @@ from core.auth import (
123
156
  ObjectPermissionBackend,
124
157
  # Models
125
158
  AbstractUser,
159
+ AbstractUUIDUser,
126
160
  Group,
127
161
  Permission as AuthPermission,
128
162
  PermissionsMixin,
@@ -136,6 +170,9 @@ from core.auth import (
136
170
  require_staff,
137
171
  require_active,
138
172
  login_required,
173
+ # Middleware
174
+ AuthenticationMiddleware,
175
+ OptionalAuthenticationMiddleware,
139
176
  )
140
177
 
141
178
  # Migrations
@@ -241,7 +278,7 @@ from core.exceptions import (
241
278
  MissingDependency,
242
279
  )
243
280
 
244
- __version__ = "0.12.1"
281
+ __version__ = "0.12.3"
245
282
  __all__ = [
246
283
  # Models
247
284
  "Model",
@@ -257,6 +294,15 @@ __all__ = [
257
294
  "APIView",
258
295
  "ViewSet",
259
296
  "ModelViewSet",
297
+ "ReadOnlyModelViewSet",
298
+ "CreateModelViewSet",
299
+ "ListModelViewSet",
300
+ "ListCreateModelViewSet",
301
+ "RetrieveUpdateModelViewSet",
302
+ "RetrieveDestroyModelViewSet",
303
+ "RetrieveUpdateDestroyModelViewSet",
304
+ "SearchModelViewSet",
305
+ "BulkModelViewSet",
260
306
  "action",
261
307
  # Routing
262
308
  "Router",
@@ -277,6 +323,18 @@ __all__ = [
277
323
  "get_settings",
278
324
  # App
279
325
  "CoreApp",
326
+ # Middleware
327
+ "BaseMiddleware",
328
+ "configure_middleware",
329
+ "register_middleware",
330
+ "apply_middlewares",
331
+ "get_middleware_stack_info",
332
+ "print_middleware_stack",
333
+ "TimingMiddleware",
334
+ "RequestIDMiddleware",
335
+ "LoggingMiddleware",
336
+ "MaintenanceModeMiddleware",
337
+ "SecurityHeadersMiddleware",
280
338
  # Advanced Fields
281
339
  "uuid7",
282
340
  "uuid7_str",
@@ -316,6 +374,8 @@ __all__ = [
316
374
  "configure_datetime",
317
375
  "get_datetime_config",
318
376
  "get_timezone",
377
+ # Auth - ViewSet
378
+ "AuthViewSet",
319
379
  # Auth - Config
320
380
  "AuthConfig",
321
381
  "configure_auth",
@@ -352,10 +412,14 @@ __all__ = [
352
412
  "ObjectPermissionBackend",
353
413
  # Auth - Models
354
414
  "AbstractUser",
415
+ "AbstractUUIDUser",
355
416
  "Group",
356
417
  "AuthPermission",
357
418
  "PermissionsMixin",
358
419
  "get_user_model",
420
+ # Auth - Middleware
421
+ "AuthenticationMiddleware",
422
+ "OptionalAuthenticationMiddleware",
359
423
  # Auth - Decorators
360
424
  "HasPermission",
361
425
  "IsInGroup",
core/app.py CHANGED
@@ -34,7 +34,7 @@ class CoreApp:
34
34
 
35
35
  Encapsula FastAPI com configurações e lifecycle management.
36
36
 
37
- Exemplo:
37
+ Exemplo básico:
38
38
  app = CoreApp(
39
39
  title="My API",
40
40
  settings=MySettings(),
@@ -45,6 +45,23 @@ class CoreApp:
45
45
 
46
46
  # Obtém a aplicação FastAPI
47
47
  fastapi_app = app.app
48
+
49
+ Exemplo com middlewares Django-style:
50
+ app = CoreApp(
51
+ title="My API",
52
+ middleware=[
53
+ "core.middleware.TimingMiddleware",
54
+ "core.auth.AuthenticationMiddleware",
55
+ ("core.middleware.LoggingMiddleware", {"log_headers": True}),
56
+ ],
57
+ )
58
+
59
+ Shortcuts disponíveis:
60
+ - "auth": AuthenticationMiddleware
61
+ - "timing": TimingMiddleware
62
+ - "request_id": RequestIDMiddleware
63
+ - "logging": LoggingMiddleware
64
+ - "security_headers": SecurityHeadersMiddleware
48
65
  """
49
66
 
50
67
  def __init__(
@@ -57,6 +74,7 @@ class CoreApp:
57
74
  on_startup: list[Callable] | None = None,
58
75
  on_shutdown: list[Callable] | None = None,
59
76
  middlewares: list[tuple[type, dict[str, Any]]] | None = None,
77
+ middleware: list[str | type | tuple] | None = None,
60
78
  exception_handlers: dict[type, Callable] | None = None,
61
79
  auto_create_tables: bool = True,
62
80
  **fastapi_kwargs: Any,
@@ -72,10 +90,19 @@ class CoreApp:
72
90
  routers: Lista de routers a incluir
73
91
  on_startup: Callbacks de startup
74
92
  on_shutdown: Callbacks de shutdown
75
- middlewares: Lista de middlewares (classe, kwargs)
93
+ middlewares: Lista de middlewares formato antigo (classe, kwargs)
94
+ middleware: Lista de middlewares formato Django-style (strings/classes)
76
95
  exception_handlers: Handlers de exceção customizados
77
96
  auto_create_tables: Se True, cria tabelas automaticamente
78
97
  **fastapi_kwargs: Argumentos extras para FastAPI
98
+
99
+ Middleware format (novo, Django-style):
100
+ middleware=[
101
+ "core.auth.AuthenticationMiddleware", # String path
102
+ "auth", # Shortcut
103
+ MyMiddleware, # Classe direta
104
+ ("logging", {"log_body": True}), # Com kwargs
105
+ ]
79
106
  """
80
107
  self.settings = settings or get_settings()
81
108
  self._on_startup = on_startup or []
@@ -100,7 +127,12 @@ class CoreApp:
100
127
  if self.settings.tenancy_enabled:
101
128
  self._setup_tenancy_middleware()
102
129
 
103
- # Adiciona middlewares customizados
130
+ # Adiciona middlewares - formato novo Django-style (parâmetro ou settings)
131
+ middleware_list = middleware or getattr(self.settings, "middleware", None)
132
+ if middleware_list:
133
+ self._setup_django_style_middleware(middleware_list)
134
+
135
+ # Adiciona middlewares - formato antigo (tuple)
104
136
  if middlewares:
105
137
  for middleware_class, middleware_kwargs in middlewares:
106
138
  self.app.add_middleware(middleware_class, **middleware_kwargs)
@@ -206,6 +238,36 @@ class CoreApp:
206
238
  require_tenant=self.settings.tenancy_require,
207
239
  )
208
240
 
241
+ def _setup_django_style_middleware(
242
+ self,
243
+ middleware_list: list[str | type | tuple],
244
+ ) -> None:
245
+ """
246
+ Configura middlewares no estilo Django.
247
+
248
+ Args:
249
+ middleware_list: Lista de middlewares
250
+ - String: path do middleware (ex: "core.auth.AuthenticationMiddleware")
251
+ - String shortcut: nome curto (ex: "auth", "timing")
252
+ - Classe: classe do middleware diretamente
253
+ - Tuple: (middleware, kwargs) para passar configurações
254
+
255
+ Example:
256
+ middleware_list = [
257
+ "core.middleware.TimingMiddleware",
258
+ "auth", # shortcut para AuthenticationMiddleware
259
+ MyCustomMiddleware,
260
+ ("logging", {"log_body": True}),
261
+ ]
262
+ """
263
+ from core.middleware import configure_middleware, apply_middlewares
264
+
265
+ # Configura no registry global
266
+ configure_middleware(middleware_list, clear_existing=True)
267
+
268
+ # Aplica ao app
269
+ apply_middlewares(self.app)
270
+
209
271
  def _setup_exception_handlers(
210
272
  self,
211
273
  custom_handlers: dict[type, Callable] | None = None,
core/auth/__init__.py CHANGED
@@ -43,8 +43,13 @@ from core.auth.base import (
43
43
  # Config
44
44
  AuthConfig,
45
45
  AuthConfigurationError,
46
+ ConfigurationWarning,
46
47
  configure_auth,
47
48
  get_auth_config,
49
+ # Validation helpers (preventive)
50
+ validate_auth_configuration,
51
+ check_middleware_configured,
52
+ get_auth_setup_checklist,
48
53
  )
49
54
 
50
55
  # Default implementations
@@ -76,10 +81,12 @@ from core.auth.permissions import (
76
81
  # Models
77
82
  from core.auth.models import (
78
83
  AbstractUser,
84
+ AbstractUUIDUser,
79
85
  PermissionsMixin,
80
86
  Group,
81
87
  Permission,
82
88
  get_user_model,
89
+ clear_association_table_cache,
83
90
  )
84
91
 
85
92
  # Decorators and dependencies
@@ -107,7 +114,14 @@ from core.auth.schemas import (
107
114
 
108
115
  # Views
109
116
  from core.auth.views import (
110
- CoreAuthViewSet,
117
+ AuthViewSet,
118
+ )
119
+
120
+ # Middleware (Bug #8 Fix)
121
+ from core.auth.middleware import (
122
+ AuthenticationMiddleware,
123
+ OptionalAuthenticationMiddleware,
124
+ ensure_auth_middleware,
111
125
  )
112
126
 
113
127
  __all__ = [
@@ -128,8 +142,13 @@ __all__ = [
128
142
  # Config
129
143
  "AuthConfig",
130
144
  "AuthConfigurationError",
145
+ "ConfigurationWarning",
131
146
  "configure_auth",
132
147
  "get_auth_config",
148
+ # Validation helpers
149
+ "validate_auth_configuration",
150
+ "check_middleware_configured",
151
+ "get_auth_setup_checklist",
133
152
  # Hashers
134
153
  "PBKDF2Hasher",
135
154
  "Argon2Hasher",
@@ -149,10 +168,12 @@ __all__ = [
149
168
  "ObjectPermissionBackend",
150
169
  # Models
151
170
  "AbstractUser",
171
+ "AbstractUUIDUser",
152
172
  "PermissionsMixin",
153
173
  "Group",
154
174
  "Permission",
155
175
  "get_user_model",
176
+ "clear_association_table_cache",
156
177
  # Decorators
157
178
  "HasPermission",
158
179
  "IsInGroup",
@@ -171,5 +192,9 @@ __all__ = [
171
192
  "BaseUserOutput",
172
193
  "MessageResponse",
173
194
  # Views
174
- "CoreAuthViewSet",
195
+ "AuthViewSet",
196
+ # Middleware
197
+ "AuthenticationMiddleware",
198
+ "OptionalAuthenticationMiddleware",
199
+ "ensure_auth_middleware",
175
200
  ]
core/auth/base.py CHANGED
@@ -485,6 +485,10 @@ class AuthConfig:
485
485
  password_require_lowercase: bool = False
486
486
  password_require_digit: bool = False
487
487
  password_require_special: bool = False
488
+
489
+ # Middleware automático (Bug #8 preventive)
490
+ # Se True, emite warning se middleware não estiver configurado
491
+ warn_missing_middleware: bool = True
488
492
 
489
493
 
490
494
  _auth_config: AuthConfig | None = None
@@ -599,3 +603,145 @@ def get_auth_config() -> AuthConfig:
599
603
  if _auth_config is None:
600
604
  _auth_config = AuthConfig()
601
605
  return _auth_config
606
+
607
+
608
+ # =============================================================================
609
+ # Configuration Validation (Preventive measures)
610
+ # =============================================================================
611
+
612
+ class ConfigurationWarning(UserWarning):
613
+ """Warning for potential configuration issues."""
614
+ pass
615
+
616
+
617
+ def validate_auth_configuration() -> list[str]:
618
+ """
619
+ Validate current auth configuration and return list of issues.
620
+
621
+ This is a preventive measure to catch common configuration mistakes.
622
+
623
+ Returns:
624
+ List of warning messages
625
+ """
626
+ issues = []
627
+ config = get_auth_config()
628
+
629
+ # Check secret key
630
+ if config.secret_key == "change-me-in-production":
631
+ issues.append(
632
+ "Using default SECRET_KEY. Set a secure key in production: "
633
+ "configure_auth(secret_key='your-secure-key-256-bits')"
634
+ )
635
+
636
+ # Check if user_model is configured
637
+ if config.user_model is None:
638
+ issues.append(
639
+ "No user_model configured. Authentication endpoints may not work. "
640
+ "Use: configure_auth(user_model=YourUserClass)"
641
+ )
642
+
643
+ # Check if user_model has UUID PK and warn about PermissionsMixin
644
+ if config.user_model is not None:
645
+ try:
646
+ from sqlalchemy.dialects.postgresql import UUID as PG_UUID
647
+ from sqlalchemy import Uuid
648
+
649
+ if hasattr(config.user_model, "__table__"):
650
+ pk_cols = [c for c in config.user_model.__table__.columns if c.primary_key]
651
+ if pk_cols and isinstance(pk_cols[0].type, (PG_UUID, Uuid)):
652
+ # Has UUID PK - check if PermissionsMixin is used
653
+ from core.auth.models import PermissionsMixin
654
+ if issubclass(config.user_model, PermissionsMixin):
655
+ # This is now handled, but inform the user
656
+ pass # Silently pass, we fixed the issue
657
+ except Exception:
658
+ pass
659
+
660
+ return issues
661
+
662
+
663
+ def emit_configuration_warnings() -> None:
664
+ """
665
+ Emit warnings for configuration issues.
666
+
667
+ Called automatically when using authentication features.
668
+ """
669
+ import warnings
670
+
671
+ issues = validate_auth_configuration()
672
+ for issue in issues:
673
+ warnings.warn(issue, ConfigurationWarning, stacklevel=3)
674
+
675
+
676
+ def check_middleware_configured(app: Any = None) -> bool:
677
+ """
678
+ Check if AuthenticationMiddleware is configured on the app.
679
+
680
+ Args:
681
+ app: FastAPI or CoreApp instance (optional)
682
+
683
+ Returns:
684
+ True if middleware appears to be configured
685
+ """
686
+ if app is None:
687
+ return False
688
+
689
+ # Check if app has our middleware
690
+ try:
691
+ if hasattr(app, "app"):
692
+ # CoreApp wrapping FastAPI
693
+ fastapi_app = app.app
694
+ else:
695
+ fastapi_app = app
696
+
697
+ if hasattr(fastapi_app, "middleware_stack"):
698
+ # Check middleware stack for our middleware
699
+ stack = fastapi_app.middleware_stack
700
+ while stack is not None:
701
+ if hasattr(stack, "app"):
702
+ if "AuthenticationMiddleware" in type(stack.app).__name__:
703
+ return True
704
+ stack = getattr(stack, "app", None)
705
+ else:
706
+ break
707
+ except Exception:
708
+ pass
709
+
710
+ return False
711
+
712
+
713
+ def get_auth_setup_checklist() -> str:
714
+ """
715
+ Return a checklist of auth setup steps.
716
+
717
+ Useful for documentation and debugging.
718
+
719
+ Returns:
720
+ Formatted checklist string
721
+ """
722
+ config = get_auth_config()
723
+
724
+ checklist = []
725
+ checklist.append("## Auth Setup Checklist\n")
726
+
727
+ # 1. User model
728
+ if config.user_model:
729
+ checklist.append(f" User model configured: {config.user_model.__name__}")
730
+ else:
731
+ checklist.append("X User model NOT configured")
732
+ checklist.append(" -> configure_auth(user_model=YourUserClass)")
733
+
734
+ # 2. Secret key
735
+ if config.secret_key != "change-me-in-production":
736
+ checklist.append(" Secret key configured")
737
+ else:
738
+ checklist.append("! Using default secret key (OK for development)")
739
+ checklist.append(" -> configure_auth(secret_key='secure-key') for production")
740
+
741
+ # 3. Middleware
742
+ checklist.append("")
743
+ checklist.append("[!] Don't forget to add AuthenticationMiddleware:")
744
+ checklist.append(" from core.auth import AuthenticationMiddleware")
745
+ checklist.append(" app = CoreApp(middlewares=[(AuthenticationMiddleware, {})])")
746
+
747
+ return "\n".join(checklist)