vortex-python-sdk 0.6.0__tar.gz → 0.9.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vortex-python-sdk
3
- Version: 0.6.0
3
+ Version: 0.9.0
4
4
  Summary: Vortex Python SDK for invitation management and JWT generation
5
5
  Author-email: TeamVortexSoftware <support@vortexsoftware.com>
6
6
  License-Expression: MIT
@@ -123,21 +123,21 @@ async def get_user_invitations():
123
123
  invitations = vortex.get_invitations_by_target_sync("email", "user@example.com")
124
124
  ```
125
125
 
126
- #### Accept Invitations
126
+ #### Accept an Invitation
127
127
 
128
128
  ```python
129
- async def accept_user_invitations():
129
+ async def accept_user_invitation():
130
130
  # Async version
131
- result = await vortex.accept_invitations(
132
- invitation_ids=["inv1", "inv2"],
133
- target={"type": "email", "value": "user@example.com"}
131
+ result = await vortex.accept_invitation(
132
+ invitation_id="inv-123",
133
+ user={"email": "user@example.com"}
134
134
  )
135
135
  print(f"Result: {result}")
136
136
 
137
137
  # Sync version
138
- result = vortex.accept_invitations_sync(
139
- invitation_ids=["inv1", "inv2"],
140
- target={"type": "email", "value": "user@example.com"}
138
+ result = vortex.accept_invitation_sync(
139
+ invitation_id="inv-123",
140
+ user={"email": "user@example.com"}
141
141
  )
142
142
  ```
143
143
 
@@ -85,21 +85,21 @@ async def get_user_invitations():
85
85
  invitations = vortex.get_invitations_by_target_sync("email", "user@example.com")
86
86
  ```
87
87
 
88
- #### Accept Invitations
88
+ #### Accept an Invitation
89
89
 
90
90
  ```python
91
- async def accept_user_invitations():
91
+ async def accept_user_invitation():
92
92
  # Async version
93
- result = await vortex.accept_invitations(
94
- invitation_ids=["inv1", "inv2"],
95
- target={"type": "email", "value": "user@example.com"}
93
+ result = await vortex.accept_invitation(
94
+ invitation_id="inv-123",
95
+ user={"email": "user@example.com"}
96
96
  )
97
97
  print(f"Result: {result}")
98
98
 
99
99
  # Sync version
100
- result = vortex.accept_invitations_sync(
101
- invitation_ids=["inv1", "inv2"],
102
- target={"type": "email", "value": "user@example.com"}
100
+ result = vortex.accept_invitation_sync(
101
+ invitation_id="inv-123",
102
+ user={"email": "user@example.com"}
103
103
  )
104
104
  ```
105
105
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "vortex-python-sdk"
7
- version = "0.6.0"
7
+ version = "0.9.0"
8
8
  description = "Vortex Python SDK for invitation management and JWT generation"
9
9
  authors = [{name = "TeamVortexSoftware", email = "support@vortexsoftware.com"}]
10
10
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vortex-python-sdk
3
- Version: 0.6.0
3
+ Version: 0.9.0
4
4
  Summary: Vortex Python SDK for invitation management and JWT generation
5
5
  Author-email: TeamVortexSoftware <support@vortexsoftware.com>
6
6
  License-Expression: MIT
@@ -123,21 +123,21 @@ async def get_user_invitations():
123
123
  invitations = vortex.get_invitations_by_target_sync("email", "user@example.com")
124
124
  ```
125
125
 
126
- #### Accept Invitations
126
+ #### Accept an Invitation
127
127
 
128
128
  ```python
129
- async def accept_user_invitations():
129
+ async def accept_user_invitation():
130
130
  # Async version
131
- result = await vortex.accept_invitations(
132
- invitation_ids=["inv1", "inv2"],
133
- target={"type": "email", "value": "user@example.com"}
131
+ result = await vortex.accept_invitation(
132
+ invitation_id="inv-123",
133
+ user={"email": "user@example.com"}
134
134
  )
135
135
  print(f"Result: {result}")
136
136
 
137
137
  # Sync version
138
- result = vortex.accept_invitations_sync(
139
- invitation_ids=["inv1", "inv2"],
140
- target={"type": "email", "value": "user@example.com"}
138
+ result = vortex.accept_invitation_sync(
139
+ invitation_id="inv-123",
140
+ user={"email": "user@example.com"}
141
141
  )
142
142
  ```
143
143
 
@@ -11,6 +11,9 @@ from .types import (
11
11
  ApiResponse,
12
12
  ApiResponseJson,
13
13
  AuthenticatedUser,
14
+ AutojoinDomain,
15
+ AutojoinDomainsResponse,
16
+ ConfigureAutojoinRequest,
14
17
  CreateInvitationRequest,
15
18
  GroupInput,
16
19
  IdentifierInput,
@@ -24,7 +27,7 @@ from .types import (
24
27
  )
25
28
  from .vortex import Vortex
26
29
 
27
- __version__ = "0.0.6"
30
+ __version__ = "0.7.0"
28
31
  __author__ = "TeamVortexSoftware"
29
32
  __email__ = "support@vortexsoftware.com"
30
33
 
@@ -42,6 +45,9 @@ __all__ = [
42
45
  "CreateInvitationRequest",
43
46
  "AcceptInvitationRequest",
44
47
  "AcceptInvitationsRequest", # Alias for AcceptInvitationRequest
48
+ "AutojoinDomain",
49
+ "AutojoinDomainsResponse",
50
+ "ConfigureAutojoinRequest",
45
51
  "ApiResponse",
46
52
  "ApiResponseJson",
47
53
  "ApiRequestBody",
@@ -64,6 +64,8 @@ class User(BaseModel):
64
64
  - user_name: User's display name
65
65
  - user_avatar_url: User's avatar URL (must be HTTPS, max 2000 chars)
66
66
  - admin_scopes: List of admin scopes (e.g., ['autojoin'])
67
+ - allowed_email_domains: List of allowed email domains for invitation restrictions
68
+ (e.g., ['acme.com', 'acme.org'])
67
69
 
68
70
  Additional fields are allowed via extra parameter
69
71
  """
@@ -72,9 +74,11 @@ class User(BaseModel):
72
74
  user_name: Optional[str] = Field(None, alias="userName")
73
75
  user_avatar_url: Optional[str] = Field(None, alias="userAvatarUrl")
74
76
  admin_scopes: Optional[List[str]] = None
77
+ allowed_email_domains: Optional[List[str]] = Field(None, alias="allowedEmailDomains")
75
78
 
76
79
  class Config:
77
80
  extra = "allow" # Allow additional fields
81
+ populate_by_name = True
78
82
 
79
83
 
80
84
  class AuthenticatedUser(BaseModel):
@@ -360,3 +364,33 @@ class CreateInvitationResponse(BaseModel):
360
364
 
361
365
  class Config:
362
366
  populate_by_name = True
367
+
368
+
369
+ # --- Types for autojoin domain management ---
370
+
371
+ class AutojoinDomain(BaseModel):
372
+ """Autojoin domain configuration"""
373
+ id: str
374
+ domain: str
375
+
376
+
377
+ class AutojoinDomainsResponse(BaseModel):
378
+ """Response from autojoin API endpoints"""
379
+ autojoin_domains: List[AutojoinDomain] = Field(alias="autojoinDomains")
380
+ invitation: Optional[InvitationResult] = None
381
+
382
+ class Config:
383
+ populate_by_name = True
384
+
385
+
386
+ class ConfigureAutojoinRequest(BaseModel):
387
+ """Request body for configuring autojoin domains"""
388
+ scope: str
389
+ scope_type: str = Field(alias="scopeType")
390
+ scope_name: Optional[str] = Field(None, alias="scopeName")
391
+ domains: List[str]
392
+ widget_id: str = Field(alias="widgetId")
393
+ metadata: Optional[Dict[str, Any]] = None
394
+
395
+ class Config:
396
+ populate_by_name = True
@@ -13,7 +13,9 @@ logger = logging.getLogger(__name__)
13
13
 
14
14
  from .types import (
15
15
  AcceptUser,
16
+ AutojoinDomainsResponse,
16
17
  BackendCreateInvitationRequest,
18
+ ConfigureAutojoinRequest,
17
19
  CreateInvitationGroup,
18
20
  CreateInvitationResponse,
19
21
  CreateInvitationTarget,
@@ -138,6 +140,10 @@ class Vortex:
138
140
  if user.admin_scopes:
139
141
  jwt_payload["adminScopes"] = user.admin_scopes
140
142
 
143
+ # Add allowedEmailDomains if present (for domain-restricted invitations)
144
+ if user.allowed_email_domains:
145
+ jwt_payload["allowedEmailDomains"] = user.allowed_email_domains
146
+
141
147
  # Add any additional properties from user.model_extra
142
148
  if hasattr(user, "model_extra") and user.model_extra:
143
149
  jwt_payload.update(user.model_extra)
@@ -442,6 +448,58 @@ class Vortex:
442
448
 
443
449
  return await self._vortex_api_request("POST", "/invitations/accept", data=data)
444
450
 
451
+ async def accept_invitation(
452
+ self,
453
+ invitation_id: str,
454
+ user: Union[AcceptUser, Dict[str, Any]],
455
+ ) -> Dict:
456
+ """
457
+ Accept a single invitation (recommended method)
458
+
459
+ This is the recommended method for accepting invitations.
460
+
461
+ Args:
462
+ invitation_id: Single invitation ID to accept
463
+ user: User object with email/phone/name
464
+
465
+ Returns:
466
+ API response
467
+
468
+ Example:
469
+ user = AcceptUser(email="user@example.com", name="John Doe")
470
+ result = await client.accept_invitation("inv-123", user)
471
+
472
+ # Or with a dict:
473
+ result = await client.accept_invitation("inv-123", {"email": "user@example.com"})
474
+ """
475
+ return await self.accept_invitations([invitation_id], user)
476
+
477
+ def accept_invitation_sync(
478
+ self,
479
+ invitation_id: str,
480
+ user: Union[AcceptUser, Dict[str, Any]],
481
+ ) -> Dict:
482
+ """
483
+ Accept a single invitation (synchronous, recommended method)
484
+
485
+ This is the recommended method for accepting invitations.
486
+
487
+ Args:
488
+ invitation_id: Single invitation ID to accept
489
+ user: User object with email/phone/name
490
+
491
+ Returns:
492
+ API response
493
+
494
+ Example:
495
+ user = AcceptUser(email="user@example.com", name="John Doe")
496
+ result = client.accept_invitation_sync("inv-123", user)
497
+
498
+ # Or with a dict:
499
+ result = client.accept_invitation_sync("inv-123", {"email": "user@example.com"})
500
+ """
501
+ return self.accept_invitations_sync([invitation_id], user)
502
+
445
503
  def accept_invitations_sync(
446
504
  self,
447
505
  invitation_ids: List[str],
@@ -781,6 +839,160 @@ class Vortex:
781
839
  )
782
840
  return CreateInvitationResponse(**response)
783
841
 
842
+ async def get_autojoin_domains(
843
+ self, scope_type: str, scope: str
844
+ ) -> AutojoinDomainsResponse:
845
+ """
846
+ Get autojoin domains configured for a specific scope
847
+
848
+ Args:
849
+ scope_type: The type of scope (e.g., "organization", "team", "project")
850
+ scope: The scope identifier (customer's group ID)
851
+
852
+ Returns:
853
+ AutojoinDomainsResponse with autojoin_domains and associated invitation
854
+
855
+ Example:
856
+ result = await vortex.get_autojoin_domains("organization", "acme-org")
857
+ print(result.autojoin_domains) # [AutojoinDomain(id='...', domain='acme.com')]
858
+ """
859
+ from urllib.parse import quote
860
+
861
+ response = await self._vortex_api_request(
862
+ "GET",
863
+ f"/invitations/by-scope/{quote(scope_type, safe='')}/{quote(scope, safe='')}/autojoin",
864
+ )
865
+ return AutojoinDomainsResponse(**response)
866
+
867
+ def get_autojoin_domains_sync(
868
+ self, scope_type: str, scope: str
869
+ ) -> AutojoinDomainsResponse:
870
+ """
871
+ Get autojoin domains configured for a specific scope (synchronous)
872
+
873
+ Args:
874
+ scope_type: The type of scope (e.g., "organization", "team", "project")
875
+ scope: The scope identifier (customer's group ID)
876
+
877
+ Returns:
878
+ AutojoinDomainsResponse with autojoin_domains and associated invitation
879
+
880
+ Example:
881
+ result = vortex.get_autojoin_domains_sync("organization", "acme-org")
882
+ print(result.autojoin_domains) # [AutojoinDomain(id='...', domain='acme.com')]
883
+ """
884
+ from urllib.parse import quote
885
+
886
+ response = self._vortex_api_request_sync(
887
+ "GET",
888
+ f"/invitations/by-scope/{quote(scope_type, safe='')}/{quote(scope, safe='')}/autojoin",
889
+ )
890
+ return AutojoinDomainsResponse(**response)
891
+
892
+ async def configure_autojoin(
893
+ self,
894
+ scope: str,
895
+ scope_type: str,
896
+ domains: List[str],
897
+ widget_id: str,
898
+ scope_name: Optional[str] = None,
899
+ metadata: Optional[Dict[str, Any]] = None,
900
+ ) -> AutojoinDomainsResponse:
901
+ """
902
+ Configure autojoin domains for a specific scope
903
+
904
+ This endpoint syncs autojoin domains - it will add new domains, remove domains
905
+ not in the provided list, and deactivate the autojoin invitation if all domains
906
+ are removed (empty array).
907
+
908
+ Args:
909
+ scope: The scope identifier (customer's group ID)
910
+ scope_type: The type of scope (e.g., "organization", "team")
911
+ domains: Array of domains to configure for autojoin
912
+ widget_id: The widget configuration ID
913
+ scope_name: Optional display name for the scope
914
+ metadata: Optional metadata to attach to the invitation
915
+
916
+ Returns:
917
+ AutojoinDomainsResponse with updated autojoin_domains and associated invitation
918
+
919
+ Example:
920
+ result = await vortex.configure_autojoin(
921
+ scope="acme-org",
922
+ scope_type="organization",
923
+ domains=["acme.com", "acme.org"],
924
+ widget_id="widget-123",
925
+ scope_name="Acme Corporation",
926
+ )
927
+ """
928
+ request = ConfigureAutojoinRequest(
929
+ scope=scope,
930
+ scope_type=scope_type,
931
+ domains=domains,
932
+ widget_id=widget_id,
933
+ scope_name=scope_name,
934
+ metadata=metadata,
935
+ )
936
+
937
+ response = await self._vortex_api_request(
938
+ "POST",
939
+ "/invitations/autojoin",
940
+ data=request.model_dump(by_alias=True, exclude_none=True),
941
+ )
942
+ return AutojoinDomainsResponse(**response)
943
+
944
+ def configure_autojoin_sync(
945
+ self,
946
+ scope: str,
947
+ scope_type: str,
948
+ domains: List[str],
949
+ widget_id: str,
950
+ scope_name: Optional[str] = None,
951
+ metadata: Optional[Dict[str, Any]] = None,
952
+ ) -> AutojoinDomainsResponse:
953
+ """
954
+ Configure autojoin domains for a specific scope (synchronous)
955
+
956
+ This endpoint syncs autojoin domains - it will add new domains, remove domains
957
+ not in the provided list, and deactivate the autojoin invitation if all domains
958
+ are removed (empty array).
959
+
960
+ Args:
961
+ scope: The scope identifier (customer's group ID)
962
+ scope_type: The type of scope (e.g., "organization", "team")
963
+ domains: Array of domains to configure for autojoin
964
+ widget_id: The widget configuration ID
965
+ scope_name: Optional display name for the scope
966
+ metadata: Optional metadata to attach to the invitation
967
+
968
+ Returns:
969
+ AutojoinDomainsResponse with updated autojoin_domains and associated invitation
970
+
971
+ Example:
972
+ result = vortex.configure_autojoin_sync(
973
+ scope="acme-org",
974
+ scope_type="organization",
975
+ domains=["acme.com", "acme.org"],
976
+ widget_id="widget-123",
977
+ scope_name="Acme Corporation",
978
+ )
979
+ """
980
+ request = ConfigureAutojoinRequest(
981
+ scope=scope,
982
+ scope_type=scope_type,
983
+ domains=domains,
984
+ widget_id=widget_id,
985
+ scope_name=scope_name,
986
+ metadata=metadata,
987
+ )
988
+
989
+ response = self._vortex_api_request_sync(
990
+ "POST",
991
+ "/invitations/autojoin",
992
+ data=request.model_dump(by_alias=True, exclude_none=True),
993
+ )
994
+ return AutojoinDomainsResponse(**response)
995
+
784
996
  async def close(self) -> None:
785
997
  """Close the HTTP client"""
786
998
  await self._client.aclose()