codemie-sdk-python 0.1.432__tar.gz → 0.1.434__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.
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/PKG-INFO +1 -1
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/pyproject.toml +1 -1
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/auth/credentials.py +63 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/client/client.py +43 -23
- codemie_sdk_python-0.1.434/src/codemie_sdk/models/admin.py +87 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/project.py +21 -0
- codemie_sdk_python-0.1.434/src/codemie_sdk/services/admin.py +138 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/project.py +4 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/utils/http.py +1 -1
- codemie_sdk_python-0.1.432/src/codemie_sdk/models/admin.py +0 -27
- codemie_sdk_python-0.1.432/src/codemie_sdk/services/admin.py +0 -58
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/README.md +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/__init__.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/auth/__init__.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/client/__init__.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/exceptions.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/__init__.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/analytics.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/assistant.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/categories.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/common.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/conversation.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/datasource.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/errors.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/file_operation.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/guardrails.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/integration.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/llm.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/mermaid.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/skill.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/task.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/user.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/vendor_assistant.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/vendor_guardrail.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/vendor_knowledgebase.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/vendor_workflow.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/workflow.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/workflow_execution_payload.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/workflow_state.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/workflow_thoughts.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/analytics.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/assistant.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/categories.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/codemie_guardrails.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/conversation.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/datasource.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/files.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/integration.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/llm.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/mermaid.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/skill.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/task.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/user.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/vendor_assistant.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/vendor_guardrail.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/vendor_knowledgebase.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/vendor_workflow.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/webhook.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/workflow.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/workflow_execution.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/workflow_execution_state.py +0 -0
- {codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/utils/__init__.py +0 -0
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/auth/credentials.py
RENAMED
|
@@ -1,10 +1,73 @@
|
|
|
1
1
|
"""Authentication credentials module for CodeMie SDK."""
|
|
2
2
|
|
|
3
|
+
import base64
|
|
4
|
+
import json as _json
|
|
3
5
|
import time
|
|
4
6
|
import requests
|
|
5
7
|
from typing import Callable
|
|
6
8
|
|
|
7
9
|
|
|
10
|
+
def _decode_jwt_exp(token: str) -> float | None:
|
|
11
|
+
"""Return the exp claim from a JWT payload without signature verification."""
|
|
12
|
+
try:
|
|
13
|
+
parts = token.split(".")
|
|
14
|
+
if len(parts) != 3:
|
|
15
|
+
return None
|
|
16
|
+
payload = parts[1]
|
|
17
|
+
padding = 4 - len(payload) % 4
|
|
18
|
+
if padding != 4:
|
|
19
|
+
payload += "=" * padding
|
|
20
|
+
claims = _json.loads(base64.urlsafe_b64decode(payload))
|
|
21
|
+
exp = claims.get("exp")
|
|
22
|
+
return float(exp) if exp is not None else None
|
|
23
|
+
except Exception:
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class LocalAuthCredentials:
|
|
28
|
+
"""Authenticates against the backend local-auth endpoint and caches the JWT."""
|
|
29
|
+
|
|
30
|
+
_TOKEN_EXPIRY_BUFFER_SECONDS = 30
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
api_domain: str,
|
|
35
|
+
email: str,
|
|
36
|
+
password: str,
|
|
37
|
+
verify_ssl: bool = True,
|
|
38
|
+
):
|
|
39
|
+
self._login_url = f"{api_domain.rstrip('/')}/v1/local-auth/login"
|
|
40
|
+
self._email = email
|
|
41
|
+
self._password = password
|
|
42
|
+
self._verify_ssl = verify_ssl
|
|
43
|
+
self._cached_token: str | None = None
|
|
44
|
+
self._token_expires_at: float = 0.0
|
|
45
|
+
|
|
46
|
+
def get_token(self) -> str:
|
|
47
|
+
"""Return cached JWT, re-logging in when expired."""
|
|
48
|
+
now = time.monotonic()
|
|
49
|
+
if self._cached_token and now < self._token_expires_at:
|
|
50
|
+
return self._cached_token
|
|
51
|
+
|
|
52
|
+
response = requests.post(
|
|
53
|
+
self._login_url,
|
|
54
|
+
json={"email": self._email, "password": self._password},
|
|
55
|
+
verify=self._verify_ssl,
|
|
56
|
+
)
|
|
57
|
+
response.raise_for_status()
|
|
58
|
+
self._cached_token = response.json()["access_token"]
|
|
59
|
+
|
|
60
|
+
exp = _decode_jwt_exp(self._cached_token)
|
|
61
|
+
if exp is not None:
|
|
62
|
+
ttl = exp - time.time()
|
|
63
|
+
self._token_expires_at = now + max(
|
|
64
|
+
ttl - self._TOKEN_EXPIRY_BUFFER_SECONDS, 0
|
|
65
|
+
)
|
|
66
|
+
else:
|
|
67
|
+
self._token_expires_at = now + 3570 # 1 h fallback
|
|
68
|
+
return self._cached_token
|
|
69
|
+
|
|
70
|
+
|
|
8
71
|
class KeycloakCredentials:
|
|
9
72
|
"""Keycloak authentication credentials handler."""
|
|
10
73
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Callable
|
|
4
4
|
|
|
5
|
-
from ..auth.credentials import KeycloakCredentials
|
|
5
|
+
from ..auth.credentials import KeycloakCredentials, LocalAuthCredentials
|
|
6
6
|
from ..services.admin import AdminService
|
|
7
7
|
from ..services.analytics import AnalyticsService
|
|
8
8
|
from ..services.assistant import AssistantService
|
|
@@ -56,18 +56,6 @@ class CodeMieClient:
|
|
|
56
56
|
external_idp: Identity provider ID to validate extern_token with (optional, required if using external_token)
|
|
57
57
|
verify_ssl: Whether to verify SSL certificates (default: True)
|
|
58
58
|
"""
|
|
59
|
-
self.auth = KeycloakCredentials(
|
|
60
|
-
server_url=auth_server_url,
|
|
61
|
-
realm_name=auth_realm_name,
|
|
62
|
-
client_id=auth_client_id,
|
|
63
|
-
client_secret=auth_client_secret,
|
|
64
|
-
username=username,
|
|
65
|
-
password=password,
|
|
66
|
-
external_token=external_token,
|
|
67
|
-
external_idp=external_idp,
|
|
68
|
-
verify_ssl=verify_ssl,
|
|
69
|
-
)
|
|
70
|
-
|
|
71
59
|
self._token: str | None = None
|
|
72
60
|
self._api_domain = codemie_api_domain.rstrip("/")
|
|
73
61
|
self._is_localhost = self._is_localhost_domain(self._api_domain)
|
|
@@ -78,10 +66,34 @@ class CodeMieClient:
|
|
|
78
66
|
|
|
79
67
|
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
|
80
68
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
69
|
+
if self._is_localhost and username and password:
|
|
70
|
+
self._local_auth: LocalAuthCredentials | None = LocalAuthCredentials(
|
|
71
|
+
api_domain=codemie_api_domain,
|
|
72
|
+
email=username,
|
|
73
|
+
password=password,
|
|
74
|
+
verify_ssl=verify_ssl,
|
|
75
|
+
)
|
|
76
|
+
self._token = self._local_auth.get_token()
|
|
77
|
+
_token_source = self._local_auth.get_token
|
|
78
|
+
elif self._is_localhost:
|
|
79
|
+
self._local_auth = None
|
|
80
|
+
self._token = ""
|
|
81
|
+
_token_source = ""
|
|
82
|
+
else:
|
|
83
|
+
self._local_auth = None
|
|
84
|
+
self.auth = KeycloakCredentials(
|
|
85
|
+
server_url=auth_server_url,
|
|
86
|
+
realm_name=auth_realm_name,
|
|
87
|
+
client_id=auth_client_id,
|
|
88
|
+
client_secret=auth_client_secret,
|
|
89
|
+
username=username,
|
|
90
|
+
password=password,
|
|
91
|
+
external_token=external_token,
|
|
92
|
+
external_idp=external_idp,
|
|
93
|
+
verify_ssl=verify_ssl,
|
|
94
|
+
)
|
|
95
|
+
self._token = self.auth.get_token()
|
|
96
|
+
_token_source = self.auth.get_token
|
|
85
97
|
|
|
86
98
|
# Initialize services with verify_ssl parameter and token
|
|
87
99
|
self.admin = AdminService(
|
|
@@ -145,7 +157,10 @@ class CodeMieClient:
|
|
|
145
157
|
@property
|
|
146
158
|
def token(self) -> str:
|
|
147
159
|
"""Get current token or fetch new one if not available."""
|
|
148
|
-
|
|
160
|
+
if self._is_localhost and self._local_auth:
|
|
161
|
+
self._token = self._local_auth.get_token()
|
|
162
|
+
elif not self._is_localhost:
|
|
163
|
+
self._token = self.auth.get_token()
|
|
149
164
|
return self._token
|
|
150
165
|
|
|
151
166
|
@staticmethod
|
|
@@ -162,9 +177,14 @@ class CodeMieClient:
|
|
|
162
177
|
|
|
163
178
|
def refresh_token(self) -> str:
|
|
164
179
|
"""Force token refresh."""
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
180
|
+
if self._is_localhost and self._local_auth:
|
|
181
|
+
self._local_auth._cached_token = None
|
|
182
|
+
self._local_auth._token_expires_at = 0.0
|
|
183
|
+
self._token = self._local_auth.get_token()
|
|
184
|
+
elif self._is_localhost:
|
|
185
|
+
self._token = ""
|
|
186
|
+
else:
|
|
187
|
+
self.auth._cached_token = None
|
|
188
|
+
self.auth._token_expires_at = 0.0
|
|
189
|
+
self._token = self.auth.get_token()
|
|
170
190
|
return self._token
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""Admin models for managing applications/projects."""
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ApplicationsListResponse(BaseModel):
|
|
7
|
+
"""Response model for list applications endpoint."""
|
|
8
|
+
|
|
9
|
+
model_config = ConfigDict(extra="ignore")
|
|
10
|
+
|
|
11
|
+
applications: list[str] = Field(..., description="List of application names")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ApplicationCreateRequest(BaseModel):
|
|
15
|
+
"""Request model for creating an application/project."""
|
|
16
|
+
|
|
17
|
+
model_config = ConfigDict(extra="ignore")
|
|
18
|
+
|
|
19
|
+
name: str = Field(..., description="Application/project name")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ApplicationCreateResponse(BaseModel):
|
|
23
|
+
"""Response model for create application endpoint."""
|
|
24
|
+
|
|
25
|
+
model_config = ConfigDict(extra="ignore")
|
|
26
|
+
|
|
27
|
+
message: str = Field(..., description="Created application name")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class LocalUserCreateRequest(BaseModel):
|
|
31
|
+
"""Request model for admin user creation (local auth mode only)."""
|
|
32
|
+
|
|
33
|
+
model_config = ConfigDict(extra="ignore")
|
|
34
|
+
|
|
35
|
+
email: str
|
|
36
|
+
username: str
|
|
37
|
+
password: str
|
|
38
|
+
name: str | None = None
|
|
39
|
+
is_admin: bool = False
|
|
40
|
+
is_maintainer: bool = False
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class LocalUserDetail(BaseModel):
|
|
44
|
+
"""Response model for created/fetched user (local auth mode)."""
|
|
45
|
+
|
|
46
|
+
model_config = ConfigDict(extra="ignore")
|
|
47
|
+
|
|
48
|
+
id: str
|
|
49
|
+
email: str
|
|
50
|
+
username: str
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class AdminUserListItem(BaseModel):
|
|
54
|
+
"""User item returned by the admin list-users endpoint."""
|
|
55
|
+
|
|
56
|
+
model_config = ConfigDict(extra="ignore")
|
|
57
|
+
|
|
58
|
+
id: str
|
|
59
|
+
email: str
|
|
60
|
+
username: str
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class AdminUserListPagination(BaseModel):
|
|
64
|
+
"""Pagination metadata from GET /v1/admin/users."""
|
|
65
|
+
|
|
66
|
+
model_config = ConfigDict(extra="ignore")
|
|
67
|
+
|
|
68
|
+
total: int
|
|
69
|
+
page: int
|
|
70
|
+
per_page: int
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class AdminUserListResponse(BaseModel):
|
|
74
|
+
"""Paginated response from GET /v1/admin/users."""
|
|
75
|
+
|
|
76
|
+
model_config = ConfigDict(extra="ignore")
|
|
77
|
+
|
|
78
|
+
data: list[AdminUserListItem]
|
|
79
|
+
pagination: AdminUserListPagination
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def users(self) -> list[AdminUserListItem]:
|
|
83
|
+
return self.data
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def total(self) -> int:
|
|
87
|
+
return self.pagination.total
|
|
@@ -43,6 +43,24 @@ class ProjectMember(BaseModel):
|
|
|
43
43
|
date: datetime | None = None
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
class ProjectBudgetItem(BaseModel):
|
|
47
|
+
"""Budget assigned to a project (present when include_budgets=true)."""
|
|
48
|
+
|
|
49
|
+
model_config = ConfigDict(extra="ignore")
|
|
50
|
+
|
|
51
|
+
budget_id: str
|
|
52
|
+
name: str
|
|
53
|
+
budget_category: str
|
|
54
|
+
soft_budget: float
|
|
55
|
+
max_budget: float
|
|
56
|
+
budget_duration: str
|
|
57
|
+
budget_reset_at: datetime | None = None
|
|
58
|
+
provider_sync_status: str
|
|
59
|
+
member_count: int
|
|
60
|
+
allocated_member_budget_total: float
|
|
61
|
+
current_spending: float | None = None
|
|
62
|
+
|
|
63
|
+
|
|
46
64
|
class ProjectListItem(BaseModel):
|
|
47
65
|
"""Project list response item."""
|
|
48
66
|
|
|
@@ -58,6 +76,8 @@ class ProjectListItem(BaseModel):
|
|
|
58
76
|
counters: ProjectCounters | None = None
|
|
59
77
|
cost_center_id: UUID | None = None
|
|
60
78
|
cost_center_name: str | None = None
|
|
79
|
+
spending: float | None = None
|
|
80
|
+
budgets: list[ProjectBudgetItem] = []
|
|
61
81
|
|
|
62
82
|
|
|
63
83
|
class PaginationInfo(BaseModel):
|
|
@@ -133,6 +153,7 @@ class ProjectUpdateRequest(BaseModel):
|
|
|
133
153
|
description: str | None = None
|
|
134
154
|
cost_center_id: UUID | None = None
|
|
135
155
|
clear_cost_center: bool = False
|
|
156
|
+
project_member_budget_tracking_enabled: bool | None = None
|
|
136
157
|
|
|
137
158
|
|
|
138
159
|
class ProjectDeleteResponse(BaseModel):
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""Admin service implementation."""
|
|
2
|
+
|
|
3
|
+
from ..models.admin import (
|
|
4
|
+
AdminUserListItem,
|
|
5
|
+
AdminUserListResponse,
|
|
6
|
+
ApplicationsListResponse,
|
|
7
|
+
ApplicationCreateRequest,
|
|
8
|
+
ApplicationCreateResponse,
|
|
9
|
+
LocalUserCreateRequest,
|
|
10
|
+
LocalUserDetail,
|
|
11
|
+
)
|
|
12
|
+
from ..utils import ApiRequestHandler, TokenSource
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AdminService:
|
|
16
|
+
"""Service for managing CodeMie applications/projects."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
|
|
19
|
+
"""Initialize the admin service.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
api_domain: Base URL for the CodeMie API
|
|
23
|
+
token: Authentication token
|
|
24
|
+
verify_ssl: Whether to verify SSL certificates
|
|
25
|
+
"""
|
|
26
|
+
self._api = ApiRequestHandler(api_domain, token, verify_ssl)
|
|
27
|
+
|
|
28
|
+
def list_applications(self, project_name: str | None = None) -> list[str]:
|
|
29
|
+
"""Get list of all applications/projects.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
project_name: Optional project name to filter by
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
List of application names
|
|
36
|
+
"""
|
|
37
|
+
params = {}
|
|
38
|
+
if project_name:
|
|
39
|
+
params["search"] = project_name
|
|
40
|
+
|
|
41
|
+
response = self._api.get(
|
|
42
|
+
"/v1/admin/applications",
|
|
43
|
+
ApplicationsListResponse,
|
|
44
|
+
params=params if params else None,
|
|
45
|
+
)
|
|
46
|
+
return response.applications
|
|
47
|
+
|
|
48
|
+
def create_application(self, request: ApplicationCreateRequest) -> str:
|
|
49
|
+
"""Create a new application/project.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
request: Application creation request
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Created application name
|
|
56
|
+
"""
|
|
57
|
+
response = self._api.post(
|
|
58
|
+
"/v1/admin/application",
|
|
59
|
+
ApplicationCreateResponse,
|
|
60
|
+
json_data=request.model_dump(exclude_none=True),
|
|
61
|
+
)
|
|
62
|
+
return response.message
|
|
63
|
+
|
|
64
|
+
def create_local_user(
|
|
65
|
+
self,
|
|
66
|
+
email: str,
|
|
67
|
+
username: str,
|
|
68
|
+
password: str,
|
|
69
|
+
name: str | None = None,
|
|
70
|
+
is_admin: bool = False,
|
|
71
|
+
is_maintainer: bool = False,
|
|
72
|
+
) -> LocalUserDetail:
|
|
73
|
+
"""Create a user via the admin API (local auth mode only).
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
email: User email address
|
|
77
|
+
username: Username (3-50 chars)
|
|
78
|
+
password: Initial password
|
|
79
|
+
name: Optional display name
|
|
80
|
+
is_admin: Grant admin role
|
|
81
|
+
is_maintainer: Grant maintainer role
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
Created user details
|
|
85
|
+
"""
|
|
86
|
+
request = LocalUserCreateRequest(
|
|
87
|
+
email=email,
|
|
88
|
+
username=username,
|
|
89
|
+
password=password,
|
|
90
|
+
name=name,
|
|
91
|
+
is_admin=is_admin,
|
|
92
|
+
is_maintainer=is_maintainer,
|
|
93
|
+
)
|
|
94
|
+
return self._api.post(
|
|
95
|
+
"/v1/admin/users",
|
|
96
|
+
LocalUserDetail,
|
|
97
|
+
json_data=request.model_dump(exclude_none=True),
|
|
98
|
+
wrap_response=False,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def list_users(
|
|
102
|
+
self,
|
|
103
|
+
search: str | None = None,
|
|
104
|
+
page: int = 0,
|
|
105
|
+
per_page: int = 20,
|
|
106
|
+
) -> list[AdminUserListItem]:
|
|
107
|
+
"""List users via the admin API.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
search: Search string matched against email, username, name
|
|
111
|
+
page: 0-indexed page number
|
|
112
|
+
per_page: Page size
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
List of user items
|
|
116
|
+
"""
|
|
117
|
+
params: dict = {"page": page, "per_page": per_page}
|
|
118
|
+
if search:
|
|
119
|
+
params["search"] = search
|
|
120
|
+
response = self._api.get(
|
|
121
|
+
"/v1/admin/users",
|
|
122
|
+
AdminUserListResponse,
|
|
123
|
+
params=params,
|
|
124
|
+
wrap_response=False,
|
|
125
|
+
)
|
|
126
|
+
return response.users
|
|
127
|
+
|
|
128
|
+
def delete_user(self, user_id: str) -> None:
|
|
129
|
+
"""Deactivate (soft-delete) a user via the admin API.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
user_id: ID of the user to deactivate
|
|
133
|
+
"""
|
|
134
|
+
self._api.delete(
|
|
135
|
+
f"/v1/admin/users/{user_id}",
|
|
136
|
+
dict,
|
|
137
|
+
wrap_response=False,
|
|
138
|
+
)
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/project.py
RENAMED
|
@@ -86,6 +86,7 @@ class ProjectService:
|
|
|
86
86
|
page: int = 0,
|
|
87
87
|
per_page: int = 20,
|
|
88
88
|
include_counters: bool = True,
|
|
89
|
+
include_budgets: bool = False,
|
|
89
90
|
sort_by: Literal["name", "created_at"] | None = None,
|
|
90
91
|
sort_order: Literal["asc", "desc"] = "asc",
|
|
91
92
|
) -> PaginatedProjectListResponse:
|
|
@@ -105,6 +106,7 @@ class ProjectService:
|
|
|
105
106
|
"page": page,
|
|
106
107
|
"per_page": per_page,
|
|
107
108
|
"include_counters": include_counters,
|
|
109
|
+
"include_budgets": include_budgets,
|
|
108
110
|
"sort_order": sort_order,
|
|
109
111
|
}
|
|
110
112
|
|
|
@@ -147,6 +149,7 @@ class ProjectService:
|
|
|
147
149
|
description: str | None = None,
|
|
148
150
|
cost_center_id: UUID | None = None,
|
|
149
151
|
clear_cost_center: bool = False,
|
|
152
|
+
project_member_budget_tracking_enabled: bool | None = None,
|
|
150
153
|
) -> ProjectUpdateResponse:
|
|
151
154
|
"""Update a project.
|
|
152
155
|
|
|
@@ -168,6 +171,7 @@ class ProjectService:
|
|
|
168
171
|
description=description,
|
|
169
172
|
cost_center_id=cost_center_id,
|
|
170
173
|
clear_cost_center=clear_cost_center,
|
|
174
|
+
project_member_budget_tracking_enabled=project_member_budget_tracking_enabled,
|
|
171
175
|
)
|
|
172
176
|
|
|
173
177
|
return self._api.patch(
|
|
@@ -86,7 +86,7 @@ class ApiRequestHandler:
|
|
|
86
86
|
headers["Content-Type"] = "application/json"
|
|
87
87
|
|
|
88
88
|
if include_auth:
|
|
89
|
-
if self._is_localhost:
|
|
89
|
+
if self._is_localhost and not self._token:
|
|
90
90
|
headers["Authorization"] = "dev-codemie-user"
|
|
91
91
|
else:
|
|
92
92
|
token_value = self._token() if callable(self._token) else self._token
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"""Admin models for managing applications/projects."""
|
|
2
|
-
|
|
3
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class ApplicationsListResponse(BaseModel):
|
|
7
|
-
"""Response model for list applications endpoint."""
|
|
8
|
-
|
|
9
|
-
model_config = ConfigDict(extra="ignore")
|
|
10
|
-
|
|
11
|
-
applications: list[str] = Field(..., description="List of application names")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class ApplicationCreateRequest(BaseModel):
|
|
15
|
-
"""Request model for creating an application/project."""
|
|
16
|
-
|
|
17
|
-
model_config = ConfigDict(extra="ignore")
|
|
18
|
-
|
|
19
|
-
name: str = Field(..., description="Application/project name")
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class ApplicationCreateResponse(BaseModel):
|
|
23
|
-
"""Response model for create application endpoint."""
|
|
24
|
-
|
|
25
|
-
model_config = ConfigDict(extra="ignore")
|
|
26
|
-
|
|
27
|
-
message: str = Field(..., description="Created application name")
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
"""Admin service implementation."""
|
|
2
|
-
|
|
3
|
-
from ..models.admin import (
|
|
4
|
-
ApplicationsListResponse,
|
|
5
|
-
ApplicationCreateRequest,
|
|
6
|
-
ApplicationCreateResponse,
|
|
7
|
-
)
|
|
8
|
-
from ..utils import ApiRequestHandler, TokenSource
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class AdminService:
|
|
12
|
-
"""Service for managing CodeMie applications/projects."""
|
|
13
|
-
|
|
14
|
-
def __init__(self, api_domain: str, token: TokenSource, verify_ssl: bool = True):
|
|
15
|
-
"""Initialize the admin service.
|
|
16
|
-
|
|
17
|
-
Args:
|
|
18
|
-
api_domain: Base URL for the CodeMie API
|
|
19
|
-
token: Authentication token
|
|
20
|
-
verify_ssl: Whether to verify SSL certificates
|
|
21
|
-
"""
|
|
22
|
-
self._api = ApiRequestHandler(api_domain, token, verify_ssl)
|
|
23
|
-
|
|
24
|
-
def list_applications(self, project_name: str | None = None) -> list[str]:
|
|
25
|
-
"""Get list of all applications/projects.
|
|
26
|
-
|
|
27
|
-
Args:
|
|
28
|
-
project_name: Optional project name to filter by
|
|
29
|
-
|
|
30
|
-
Returns:
|
|
31
|
-
List of application names
|
|
32
|
-
"""
|
|
33
|
-
params = {}
|
|
34
|
-
if project_name:
|
|
35
|
-
params["search"] = project_name
|
|
36
|
-
|
|
37
|
-
response = self._api.get(
|
|
38
|
-
"/v1/admin/applications",
|
|
39
|
-
ApplicationsListResponse,
|
|
40
|
-
params=params if params else None,
|
|
41
|
-
)
|
|
42
|
-
return response.applications
|
|
43
|
-
|
|
44
|
-
def create_application(self, request: ApplicationCreateRequest) -> str:
|
|
45
|
-
"""Create a new application/project.
|
|
46
|
-
|
|
47
|
-
Args:
|
|
48
|
-
request: Application creation request
|
|
49
|
-
|
|
50
|
-
Returns:
|
|
51
|
-
Created application name
|
|
52
|
-
"""
|
|
53
|
-
response = self._api.post(
|
|
54
|
-
"/v1/admin/application",
|
|
55
|
-
ApplicationCreateResponse,
|
|
56
|
-
json_data=request.model_dump(exclude_none=True),
|
|
57
|
-
)
|
|
58
|
-
return response.message
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/client/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/__init__.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/analytics.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/assistant.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/categories.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/conversation.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/datasource.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/file_operation.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/guardrails.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/integration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/vendor_assistant.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/vendor_guardrail.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/vendor_workflow.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/workflow.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/models/workflow_state.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/analytics.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/assistant.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/categories.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/conversation.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/datasource.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/integration.py
RENAMED
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/mermaid.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/webhook.py
RENAMED
|
File without changes
|
{codemie_sdk_python-0.1.432 → codemie_sdk_python-0.1.434}/src/codemie_sdk/services/workflow.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|