statezero 0.1.0b15__tar.gz → 0.1.0b17__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.

Potentially problematic release.


This version of statezero might be problematic. Click here for more details.

Files changed (54) hide show
  1. {statezero-0.1.0b15 → statezero-0.1.0b17}/PKG-INFO +1 -1
  2. {statezero-0.1.0b15 → statezero-0.1.0b17}/pyproject.toml +1 -1
  3. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/schemas.py +5 -3
  4. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/urls.py +2 -1
  5. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/views.py +101 -0
  6. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/core/classes.py +1 -0
  7. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero.egg-info/PKG-INFO +1 -1
  8. {statezero-0.1.0b15 → statezero-0.1.0b17}/README.md +0 -0
  9. {statezero-0.1.0b15 → statezero-0.1.0b17}/license.md +0 -0
  10. {statezero-0.1.0b15 → statezero-0.1.0b17}/requirements.txt +0 -0
  11. {statezero-0.1.0b15 → statezero-0.1.0b17}/setup.cfg +0 -0
  12. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/__init__.py +0 -0
  13. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/__init__.py +0 -0
  14. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/__init__.py +0 -0
  15. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/actions.py +0 -0
  16. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/apps.py +0 -0
  17. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/config.py +0 -0
  18. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/context_manager.py +0 -0
  19. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/event_emitters.py +0 -0
  20. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/exception_handler.py +0 -0
  21. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/extensions/__init__.py +0 -0
  22. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/extensions/custom_field_serializers/__init__.py +0 -0
  23. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/extensions/custom_field_serializers/file_fields.py +0 -0
  24. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/extensions/custom_field_serializers/money_field.py +0 -0
  25. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/f_handler.py +0 -0
  26. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/helpers.py +0 -0
  27. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/middleware.py +0 -0
  28. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/migrations/0001_initial.py +0 -0
  29. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/migrations/0002_delete_modelviewsubscription.py +0 -0
  30. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/migrations/__init__.py +0 -0
  31. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/orm.py +0 -0
  32. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/permissions.py +0 -0
  33. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/query_optimizer.py +0 -0
  34. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/search_providers/__init__.py +0 -0
  35. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/search_providers/basic_search.py +0 -0
  36. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/search_providers/postgres_search.py +0 -0
  37. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/adaptors/django/serializers.py +0 -0
  38. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/core/__init__.py +0 -0
  39. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/core/actions.py +0 -0
  40. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/core/ast_parser.py +0 -0
  41. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/core/ast_validator.py +0 -0
  42. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/core/config.py +0 -0
  43. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/core/context_storage.py +0 -0
  44. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/core/event_bus.py +0 -0
  45. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/core/event_emitters.py +0 -0
  46. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/core/exceptions.py +0 -0
  47. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/core/hook_checks.py +0 -0
  48. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/core/interfaces.py +0 -0
  49. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/core/process_request.py +0 -0
  50. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero/core/types.py +0 -0
  51. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero.egg-info/SOURCES.txt +0 -0
  52. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero.egg-info/dependency_links.txt +0 -0
  53. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero.egg-info/requires.txt +0 -0
  54. {statezero-0.1.0b15 → statezero-0.1.0b17}/statezero.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: statezero
3
- Version: 0.1.0b15
3
+ Version: 0.1.0b17
4
4
  Summary: Connect your Python backend to a modern JavaScript SPA frontend with 90% less complexity.
5
5
  Author-email: Robert <robert.herring@statezero.dev>
6
6
  Project-URL: homepage, https://www.statezero.dev
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "statezero"
7
- version = "0.1.0b15"
7
+ version = "0.1.0b17"
8
8
  description = "Connect your Python backend to a modern JavaScript SPA frontend with 90% less complexity."
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -260,6 +260,9 @@ class DjangoSchemaGenerator(AbstractSchemaGenerator):
260
260
  elif isinstance(field, models.DateField):
261
261
  field_type = FieldType.STRING
262
262
  field_format = FieldFormat.DATE
263
+ elif isinstance(field, models.TimeField):
264
+ field_type = FieldType.STRING
265
+ field_format = FieldFormat.TIME
263
266
  elif isinstance(field, (models.ForeignKey, models.OneToOneField)):
264
267
  field_type = self.get_pk_type(field)
265
268
  field_format = self.get_relation_type(field)
@@ -292,7 +295,7 @@ class DjangoSchemaGenerator(AbstractSchemaGenerator):
292
295
 
293
296
  # Check if field should be read-only (auto_now or auto_now_add)
294
297
  read_only = False
295
- if isinstance(field, (models.DateTimeField, models.DateField)):
298
+ if isinstance(field, (models.DateTimeField, models.DateField, models.TimeField)):
296
299
  if getattr(field, "auto_now", False) or getattr(field, "auto_now_add", False):
297
300
  read_only = True
298
301
 
@@ -320,8 +323,7 @@ class DjangoSchemaGenerator(AbstractSchemaGenerator):
320
323
  @staticmethod
321
324
  def is_field_required(field: models.Field) -> bool:
322
325
  return (
323
- not field.blank
324
- and not field.null
326
+ not field.null
325
327
  and field.default == models.fields.NOT_PROVIDED
326
328
  )
327
329
 
@@ -1,6 +1,6 @@
1
1
  from django.urls import path
2
2
 
3
- from .views import EventsAuthView, ModelListView, ModelView, SchemaView, FileUploadView, FastUploadView, ActionSchemaView, ActionView, ValidateView
3
+ from .views import EventsAuthView, ModelListView, ModelView, SchemaView, FileUploadView, FastUploadView, ActionSchemaView, ActionView, ValidateView, FieldPermissionsView
4
4
 
5
5
  app_name = "statezero"
6
6
 
@@ -12,6 +12,7 @@ urlpatterns = [
12
12
  path("actions/<str:action_name>/", ActionView.as_view(), name="action"),
13
13
  path("actions-schema/", ActionSchemaView.as_view(), name="actions_schema"),
14
14
  path("<str:model_name>/validate/", ValidateView.as_view(), name="validate"),
15
+ path("<str:model_name>/field-permissions/", FieldPermissionsView.as_view(), name="field_permissions"),
15
16
  path("<str:model_name>/get-schema/", SchemaView.as_view(), name="schema_view"),
16
17
  path("<str:model_name>/", ModelView.as_view(), name="model_view"),
17
18
  ]
@@ -485,3 +485,104 @@ class ValidateView(APIView):
485
485
  except Exception as original_exception:
486
486
  # Let StateZero's exception handler deal with ValidationError, PermissionDenied, etc.
487
487
  return explicit_exception_handler(original_exception)
488
+
489
+
490
+ class FieldPermissionsView(APIView):
491
+ """
492
+ Returns user-specific field permissions for a given model.
493
+ Used by frontend forms to determine which fields to show/enable at runtime.
494
+ """
495
+
496
+ permission_classes = [permission_class]
497
+
498
+ def get(self, request, model_name):
499
+ """Get field permissions for the current user."""
500
+ try:
501
+ # Create processor following the same pattern as other views
502
+ processor = RequestProcessor(config=config, registry=registry)
503
+
504
+ # Get model using the processor's ORM provider
505
+ try:
506
+ model = processor.orm_provider.get_model_by_name(model_name)
507
+ except (LookupError, ValueError):
508
+ return Response({"error": f"Model {model_name} not found"}, status=404)
509
+
510
+ if not model:
511
+ return Response({"error": f"Model {model_name} not found"}, status=404)
512
+
513
+ try:
514
+ model_config = processor.registry.get_config(model)
515
+ except ValueError:
516
+ return Response(
517
+ {"error": f"Model {model_name} not registered"}, status=404
518
+ )
519
+
520
+ # Compute field permissions using the same logic as ASTParser._get_operation_fields
521
+ all_fields = processor.orm_provider.get_fields(model)
522
+
523
+ visible_fields = self._compute_operation_fields(
524
+ model, model_config, all_fields, request, "read"
525
+ )
526
+ creatable_fields = self._compute_operation_fields(
527
+ model, model_config, all_fields, request, "create"
528
+ )
529
+ editable_fields = self._compute_operation_fields(
530
+ model, model_config, all_fields, request, "update"
531
+ )
532
+
533
+ return Response(
534
+ {
535
+ "visible_fields": list(visible_fields),
536
+ "creatable_fields": list(creatable_fields),
537
+ "editable_fields": list(editable_fields),
538
+ },
539
+ status=200,
540
+ )
541
+
542
+ except Exception as original_exception:
543
+ # Let StateZero's exception handler deal with errors
544
+ return explicit_exception_handler(original_exception)
545
+
546
+ def _compute_operation_fields(self, model, model_config, all_fields, request, operation_type):
547
+ """
548
+ Compute allowed fields for a specific operation type.
549
+ Replicates the logic from ASTParser._get_operation_fields.
550
+ """
551
+ from typing import Union, Set, Literal
552
+
553
+ allowed_fields = set()
554
+
555
+ for permission_cls in model_config.permissions:
556
+ permission = permission_cls()
557
+
558
+ # Get the appropriate field set based on operation
559
+ if operation_type == "read":
560
+ fields = permission.visible_fields(request, model)
561
+ elif operation_type == "create":
562
+ fields = permission.create_fields(request, model)
563
+ elif operation_type == "update":
564
+ fields = permission.editable_fields(request, model)
565
+ else:
566
+ fields = set()
567
+
568
+ # If any permission allows all fields
569
+ if fields == "__all__":
570
+ # For read operations, default "__all__" to frontend_fields
571
+ if operation_type == "read":
572
+ # If frontend_fields is also "__all__", then return all fields
573
+ if model_config.frontend_fields == "__all__":
574
+ return all_fields
575
+ # Otherwise, use frontend_fields as the default for "__all__"
576
+ else:
577
+ fields = model_config.frontend_fields
578
+ fields &= all_fields # Ensure fields actually exist
579
+ allowed_fields |= fields
580
+ else:
581
+ # For create/update operations, "__all__" means truly all fields
582
+ return all_fields
583
+ else:
584
+ # Add allowed fields from this permission
585
+ fields &= all_fields # Ensure fields actually exist
586
+ allowed_fields |= fields
587
+
588
+ return allowed_fields
@@ -71,6 +71,7 @@ class FieldFormat(str, Enum):
71
71
  TEXT = "text"
72
72
  DATE = "date"
73
73
  DATETIME = "date-time"
74
+ TIME = "time"
74
75
  FOREIGN_KEY = "foreign-key"
75
76
  ONE_TO_ONE = "one-to-one"
76
77
  MANY_TO_MANY = "many-to-many"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: statezero
3
- Version: 0.1.0b15
3
+ Version: 0.1.0b17
4
4
  Summary: Connect your Python backend to a modern JavaScript SPA frontend with 90% less complexity.
5
5
  Author-email: Robert <robert.herring@statezero.dev>
6
6
  Project-URL: homepage, https://www.statezero.dev
File without changes
File without changes
File without changes