django-agent-studio 0.3.1__py3-none-any.whl → 0.3.2__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.
@@ -17,6 +17,10 @@ from django_agent_runtime.models import (
17
17
  AgentSystemMember,
18
18
  AgentSystemVersion,
19
19
  AgentSystemSnapshot,
20
+ # Collaborator models
21
+ CollaboratorRole,
22
+ AgentCollaborator,
23
+ SystemCollaborator,
20
24
  )
21
25
 
22
26
 
@@ -621,3 +625,138 @@ class PublishVersionSerializer(serializers.Serializer):
621
625
  default=False,
622
626
  help_text="Whether to make this the active version immediately",
623
627
  )
628
+
629
+
630
+ # =============================================================================
631
+ # Collaborator Serializers for Multi-User Access Control
632
+ # =============================================================================
633
+
634
+
635
+ class AgentCollaboratorSerializer(serializers.ModelSerializer):
636
+ """Serializer for AgentCollaborator."""
637
+
638
+ user_email = serializers.SerializerMethodField()
639
+ user_name = serializers.SerializerMethodField()
640
+ added_by_email = serializers.SerializerMethodField()
641
+ role_display = serializers.CharField(source='get_role_display', read_only=True)
642
+ can_view = serializers.BooleanField(read_only=True)
643
+ can_edit = serializers.BooleanField(read_only=True)
644
+ can_admin = serializers.BooleanField(read_only=True)
645
+
646
+ class Meta:
647
+ model = AgentCollaborator
648
+ fields = [
649
+ "id",
650
+ "agent",
651
+ "user",
652
+ "user_email",
653
+ "user_name",
654
+ "role",
655
+ "role_display",
656
+ "can_view",
657
+ "can_edit",
658
+ "can_admin",
659
+ "added_by",
660
+ "added_by_email",
661
+ "added_at",
662
+ "updated_at",
663
+ ]
664
+ read_only_fields = ["id", "added_by", "added_at", "updated_at"]
665
+
666
+ def get_user_email(self, obj):
667
+ """Return email or username as identifier."""
668
+ if obj.user:
669
+ return obj.user.email or getattr(obj.user, 'username', None) or str(obj.user)
670
+ return None
671
+
672
+ def get_user_name(self, obj):
673
+ """Return full name, or fall back to email/username."""
674
+ if obj.user:
675
+ if hasattr(obj.user, 'get_full_name'):
676
+ name = obj.user.get_full_name()
677
+ if name:
678
+ return name
679
+ return obj.user.email or getattr(obj.user, 'username', None) or str(obj.user)
680
+ return None
681
+
682
+ def get_added_by_email(self, obj):
683
+ """Return added_by email or username."""
684
+ if obj.added_by:
685
+ return obj.added_by.email or getattr(obj.added_by, 'username', None) or str(obj.added_by)
686
+ return None
687
+
688
+
689
+ class SystemCollaboratorSerializer(serializers.ModelSerializer):
690
+ """Serializer for SystemCollaborator."""
691
+
692
+ user_email = serializers.SerializerMethodField()
693
+ user_name = serializers.SerializerMethodField()
694
+ added_by_email = serializers.SerializerMethodField()
695
+ role_display = serializers.CharField(source='get_role_display', read_only=True)
696
+ can_view = serializers.BooleanField(read_only=True)
697
+ can_edit = serializers.BooleanField(read_only=True)
698
+ can_admin = serializers.BooleanField(read_only=True)
699
+
700
+ class Meta:
701
+ model = SystemCollaborator
702
+ fields = [
703
+ "id",
704
+ "system",
705
+ "user",
706
+ "user_email",
707
+ "user_name",
708
+ "role",
709
+ "role_display",
710
+ "can_view",
711
+ "can_edit",
712
+ "can_admin",
713
+ "added_by",
714
+ "added_by_email",
715
+ "added_at",
716
+ "updated_at",
717
+ ]
718
+ read_only_fields = ["id", "added_by", "added_at", "updated_at"]
719
+
720
+ def get_user_email(self, obj):
721
+ """Return email or username as identifier."""
722
+ if obj.user:
723
+ return obj.user.email or getattr(obj.user, 'username', None) or str(obj.user)
724
+ return None
725
+
726
+ def get_user_name(self, obj):
727
+ """Return full name, or fall back to email/username."""
728
+ if obj.user:
729
+ if hasattr(obj.user, 'get_full_name'):
730
+ name = obj.user.get_full_name()
731
+ if name:
732
+ return name
733
+ return obj.user.email or getattr(obj.user, 'username', None) or str(obj.user)
734
+ return None
735
+
736
+ def get_added_by_email(self, obj):
737
+ """Return added_by email or username."""
738
+ if obj.added_by:
739
+ return obj.added_by.email or getattr(obj.added_by, 'username', None) or str(obj.added_by)
740
+ return None
741
+
742
+
743
+ class AddCollaboratorSerializer(serializers.Serializer):
744
+ """Serializer for adding a collaborator by email or username."""
745
+
746
+ email = serializers.CharField(
747
+ help_text="Email or username of the user to add as collaborator"
748
+ )
749
+ role = serializers.ChoiceField(
750
+ choices=CollaboratorRole.choices,
751
+ default=CollaboratorRole.VIEWER,
752
+ help_text="Role to grant: viewer, editor, or admin",
753
+ )
754
+
755
+
756
+ class UpdateCollaboratorRoleSerializer(serializers.Serializer):
757
+ """Serializer for updating a collaborator's role."""
758
+
759
+ role = serializers.ChoiceField(
760
+ choices=CollaboratorRole.choices,
761
+ help_text="New role: viewer, editor, or admin",
762
+ )
@@ -300,4 +300,39 @@ urlpatterns = [
300
300
  views.AgentSpecDocumentView.as_view(),
301
301
  name="agent_spec_document",
302
302
  ),
303
+
304
+ # ==========================================================================
305
+ # Collaborator Management Endpoints
306
+ # ==========================================================================
307
+
308
+ # Agent collaborators
309
+ path(
310
+ "agents/<uuid:agent_id>/collaborators/",
311
+ views.AgentCollaboratorListCreateView.as_view(),
312
+ name="agent_collaborator_list",
313
+ ),
314
+ path(
315
+ "agents/<uuid:agent_id>/collaborators/<uuid:pk>/",
316
+ views.AgentCollaboratorDetailView.as_view(),
317
+ name="agent_collaborator_detail",
318
+ ),
319
+
320
+ # System collaborators
321
+ path(
322
+ "systems/<uuid:system_id>/collaborators/",
323
+ views.SystemCollaboratorListCreateView.as_view(),
324
+ name="system_collaborator_list",
325
+ ),
326
+ path(
327
+ "systems/<uuid:system_id>/collaborators/<uuid:pk>/",
328
+ views.SystemCollaboratorDetailView.as_view(),
329
+ name="system_collaborator_detail",
330
+ ),
331
+
332
+ # User search for collaborator autocomplete
333
+ path(
334
+ "users/search/",
335
+ views.UserSearchView.as_view(),
336
+ name="user_search",
337
+ ),
303
338
  ]