terrakio-core 0.2.3__py3-none-any.whl → 0.2.6__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.
Potentially problematic release.
This version of terrakio-core might be problematic. Click here for more details.
- terrakio_core/__init__.py +0 -0
- terrakio_core/auth.py +238 -0
- terrakio_core/client.py +1046 -0
- terrakio_core/config.py +81 -0
- terrakio_core/dataset_management.py +235 -0
- terrakio_core/exceptions.py +18 -0
- terrakio_core/group_access_management.py +232 -0
- terrakio_core/mass_stats.py +262 -0
- terrakio_core/space_management.py +101 -0
- terrakio_core/user_management.py +227 -0
- {terrakio_core-0.2.3.dist-info → terrakio_core-0.2.6.dist-info}/METADATA +1 -1
- terrakio_core-0.2.6.dist-info/RECORD +14 -0
- terrakio_core-0.2.6.dist-info/top_level.txt +1 -0
- terrakio_core-0.2.3.dist-info/RECORD +0 -4
- terrakio_core-0.2.3.dist-info/top_level.txt +0 -1
- {terrakio_core-0.2.3.dist-info → terrakio_core-0.2.6.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from typing import Optional, Dict, Any
|
|
3
|
+
|
|
4
|
+
class MassStats:
|
|
5
|
+
def __init__(self, base_url: str, api_key: str, verify: bool = True, timeout: int = 60):
|
|
6
|
+
self.base_url = base_url.rstrip('/')
|
|
7
|
+
self.api_key = api_key
|
|
8
|
+
self.verify = verify
|
|
9
|
+
self.timeout = timeout
|
|
10
|
+
self.session = requests.Session()
|
|
11
|
+
self.session.headers.update({
|
|
12
|
+
'x-api-key': self.api_key
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
def upload_request(
|
|
16
|
+
self,
|
|
17
|
+
name: str,
|
|
18
|
+
size: int,
|
|
19
|
+
bucket: str,
|
|
20
|
+
output: str,
|
|
21
|
+
location: Optional[str] = None,
|
|
22
|
+
force_loc: bool = False,
|
|
23
|
+
config: Optional[Dict[str, Any]] = None,
|
|
24
|
+
overwrite: bool = False,
|
|
25
|
+
server: Optional[str] = None,
|
|
26
|
+
skip_existing: bool = False
|
|
27
|
+
) -> Dict[str, Any]:
|
|
28
|
+
"""
|
|
29
|
+
Initiate a mass stats upload job.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
name: Name of the job
|
|
33
|
+
size: Size of the data
|
|
34
|
+
bucket: Storage bucket
|
|
35
|
+
output: Output path or identifier
|
|
36
|
+
location: (Optional) Location for the upload
|
|
37
|
+
force_loc: Force location usage
|
|
38
|
+
config: Optional configuration dictionary
|
|
39
|
+
overwrite: Overwrite existing data
|
|
40
|
+
server: Optional server
|
|
41
|
+
skip_existing: Skip existing files
|
|
42
|
+
"""
|
|
43
|
+
url = f"{self.base_url}/mass_stats/upload"
|
|
44
|
+
data = {
|
|
45
|
+
"name": name,
|
|
46
|
+
"size": size,
|
|
47
|
+
"bucket": bucket,
|
|
48
|
+
"output": output,
|
|
49
|
+
"force_loc": force_loc,
|
|
50
|
+
"overwrite": overwrite,
|
|
51
|
+
"skip_existing": skip_existing
|
|
52
|
+
}
|
|
53
|
+
if location is not None:
|
|
54
|
+
data["location"] = location
|
|
55
|
+
if config is not None:
|
|
56
|
+
data["config"] = config
|
|
57
|
+
if server is not None:
|
|
58
|
+
data["server"] = server
|
|
59
|
+
response = self.session.post(url, json=data, verify=self.verify, timeout=self.timeout)
|
|
60
|
+
print("the response is ", response.text)
|
|
61
|
+
# response.raise_for_status()
|
|
62
|
+
return response.json()
|
|
63
|
+
|
|
64
|
+
def start_job(self, task_id: str) -> Dict[str, Any]:
|
|
65
|
+
"""
|
|
66
|
+
Start a mass stats job by task ID.
|
|
67
|
+
"""
|
|
68
|
+
url = f"{self.base_url}/mass_stats/start/{task_id}"
|
|
69
|
+
print("the self session header is ", self.session.headers)
|
|
70
|
+
response = self.session.post(url, verify=self.verify, timeout=self.timeout)
|
|
71
|
+
response.raise_for_status()
|
|
72
|
+
return response.json()
|
|
73
|
+
|
|
74
|
+
def get_task_id(self, name: str, stage: str, uid: Optional[str] = None) -> Dict[str, Any]:
|
|
75
|
+
"""
|
|
76
|
+
Get the task ID for a mass stats job by name and stage (and optionally user ID).
|
|
77
|
+
"""
|
|
78
|
+
url = f"{self.base_url}/mass_stats/job_id?name={name}&stage={stage}"
|
|
79
|
+
if uid is not None:
|
|
80
|
+
url += f"&uid={uid}"
|
|
81
|
+
response = self.session.get(url, verify=self.verify, timeout=self.timeout)
|
|
82
|
+
print("response text is ", response.text)
|
|
83
|
+
return response.json()
|
|
84
|
+
|
|
85
|
+
def track_job(self, ids: Optional[list] = None) -> Dict[str, Any]:
|
|
86
|
+
"""
|
|
87
|
+
Track the status of one or more mass stats jobs.
|
|
88
|
+
If ids is None, gets progress for all of the user's jobs.
|
|
89
|
+
"""
|
|
90
|
+
url = f"{self.base_url}/mass_stats/track"
|
|
91
|
+
data = {"ids": ids} if ids is not None else {}
|
|
92
|
+
response = self.session.post(url, json=data, verify=self.verify, timeout=self.timeout)
|
|
93
|
+
response.raise_for_status()
|
|
94
|
+
return response.json()
|
|
95
|
+
|
|
96
|
+
def get_history(self, limit: int = 100) -> Dict[str, Any]:
|
|
97
|
+
"""
|
|
98
|
+
Get the history of mass stats jobs.
|
|
99
|
+
"""
|
|
100
|
+
url = f"{self.base_url}/mass_stats/history"
|
|
101
|
+
params = {"limit": limit}
|
|
102
|
+
response = self.session.get(url, params=params, verify=self.verify, timeout=self.timeout)
|
|
103
|
+
response.raise_for_status()
|
|
104
|
+
return response.json()
|
|
105
|
+
|
|
106
|
+
def start_post_processing(
|
|
107
|
+
self,
|
|
108
|
+
process_name: str,
|
|
109
|
+
data_name: str,
|
|
110
|
+
output: str,
|
|
111
|
+
consumer_path: str,
|
|
112
|
+
overwrite: bool = False
|
|
113
|
+
) -> Dict[str, Any]:
|
|
114
|
+
"""
|
|
115
|
+
Start post processing for a mass stats job.
|
|
116
|
+
Args:
|
|
117
|
+
process_name: Folder to store output
|
|
118
|
+
data_name: Name of job used to create data
|
|
119
|
+
output: Output type
|
|
120
|
+
consumer_path: Path to the post processing script (Python file)
|
|
121
|
+
overwrite: Overwrite existing post processing output in same location
|
|
122
|
+
Returns:
|
|
123
|
+
Dict with task_id
|
|
124
|
+
"""
|
|
125
|
+
url = f"{self.base_url}/mass_stats/post_process"
|
|
126
|
+
files = {
|
|
127
|
+
'consumer': (consumer_path, open(consumer_path, 'rb'), 'text/x-python')
|
|
128
|
+
}
|
|
129
|
+
data = {
|
|
130
|
+
'process_name': process_name,
|
|
131
|
+
'data_name': data_name,
|
|
132
|
+
'output': output,
|
|
133
|
+
'overwrite': str(overwrite).lower()
|
|
134
|
+
}
|
|
135
|
+
response = self.session.post(url, data=data, files=files, verify=self.verify, timeout=self.timeout)
|
|
136
|
+
print("the response is ", response.text)
|
|
137
|
+
# response.raise_for_status()
|
|
138
|
+
return response.json()
|
|
139
|
+
|
|
140
|
+
def download_results(
|
|
141
|
+
self,
|
|
142
|
+
id: Optional[str] = None,
|
|
143
|
+
force_loc: bool = False,
|
|
144
|
+
bucket: Optional[str] = None,
|
|
145
|
+
location: Optional[str] = None,
|
|
146
|
+
output: Optional[str] = None,
|
|
147
|
+
file_name: Optional[str] = None
|
|
148
|
+
) -> bytes:
|
|
149
|
+
"""
|
|
150
|
+
Download results from a mass stats job or arbitrary results if force_loc is True.
|
|
151
|
+
Returns the content of the .zip file.
|
|
152
|
+
"""
|
|
153
|
+
url = f"{self.base_url}/mass_stats/download"
|
|
154
|
+
data = {}
|
|
155
|
+
if id is not None:
|
|
156
|
+
data["id"] = id
|
|
157
|
+
if force_loc:
|
|
158
|
+
data["force_loc"] = True
|
|
159
|
+
if bucket is not None:
|
|
160
|
+
data["bucket"] = bucket
|
|
161
|
+
if location is not None:
|
|
162
|
+
data["location"] = location
|
|
163
|
+
if output is not None:
|
|
164
|
+
data["output"] = output
|
|
165
|
+
if file_name is not None:
|
|
166
|
+
data["file_name"] = file_name
|
|
167
|
+
response = self.session.post(url, json=data, verify=self.verify, timeout=self.timeout)
|
|
168
|
+
print("the response is ", response.text)
|
|
169
|
+
# response.raise_for_status()
|
|
170
|
+
print("the response content is ", response.content)
|
|
171
|
+
return response.content
|
|
172
|
+
|
|
173
|
+
def cancel_job(self, id: str) -> Dict[str, Any]:
|
|
174
|
+
"""
|
|
175
|
+
Cancel a mass stats job by ID.
|
|
176
|
+
"""
|
|
177
|
+
url = f"{self.base_url}/mass_stats/cancel/{id}"
|
|
178
|
+
response = self.session.post(url, verify=self.verify, timeout=self.timeout)
|
|
179
|
+
response.raise_for_status()
|
|
180
|
+
return response.json()
|
|
181
|
+
|
|
182
|
+
def cancel_all_jobs(self) -> Dict[str, Any]:
|
|
183
|
+
"""
|
|
184
|
+
Cancel all mass stats jobs for the user.
|
|
185
|
+
"""
|
|
186
|
+
url = f"{self.base_url}/mass_stats/cancel"
|
|
187
|
+
response = self.session.post(url, verify=self.verify, timeout=self.timeout)
|
|
188
|
+
response.raise_for_status()
|
|
189
|
+
return response.json()
|
|
190
|
+
|
|
191
|
+
def create_pyramids(self, name: str, levels: int, config: Dict[str, Any]) -> Dict[str, Any]:
|
|
192
|
+
"""
|
|
193
|
+
Create pyramids for a dataset.
|
|
194
|
+
Args:
|
|
195
|
+
name: Name for the pyramid job
|
|
196
|
+
levels: Number of zoom levels to compute
|
|
197
|
+
config: Dataset config (mapping)
|
|
198
|
+
Returns:
|
|
199
|
+
Dict with task_id
|
|
200
|
+
"""
|
|
201
|
+
url = f"{self.base_url}/pyramids/create"
|
|
202
|
+
data = {
|
|
203
|
+
"name": name,
|
|
204
|
+
"levels": levels,
|
|
205
|
+
"config": config
|
|
206
|
+
}
|
|
207
|
+
response = self.session.post(url, json=data, verify=self.verify, timeout=self.timeout)
|
|
208
|
+
print("the url is ", url)
|
|
209
|
+
print("the response is ", response.text)
|
|
210
|
+
print("the response status code is ", response.status_code)
|
|
211
|
+
# response.raise_for_status()
|
|
212
|
+
return response.json()
|
|
213
|
+
|
|
214
|
+
def random_sample(
|
|
215
|
+
self,
|
|
216
|
+
name: str,
|
|
217
|
+
config: dict,
|
|
218
|
+
aoi: dict,
|
|
219
|
+
samples: int,
|
|
220
|
+
year_range: list,
|
|
221
|
+
crs: str,
|
|
222
|
+
tile_size: int,
|
|
223
|
+
res: float,
|
|
224
|
+
output: str,
|
|
225
|
+
server: str,
|
|
226
|
+
region: str,
|
|
227
|
+
bucket: str,
|
|
228
|
+
overwrite: bool = False
|
|
229
|
+
) -> Dict[str, Any]:
|
|
230
|
+
"""
|
|
231
|
+
Submit a random sample job.
|
|
232
|
+
"""
|
|
233
|
+
if year_range is None or len(year_range) != 2:
|
|
234
|
+
raise ValueError("year_range must be a list of two integers")
|
|
235
|
+
start_year, end_year = year_range
|
|
236
|
+
if start_year is None or end_year is None:
|
|
237
|
+
raise ValueError("Both start_year and end_year must be provided for year_range.")
|
|
238
|
+
|
|
239
|
+
url = f"{self.base_url}/random_sample"
|
|
240
|
+
data = {
|
|
241
|
+
"name": name,
|
|
242
|
+
"overwrite": overwrite,
|
|
243
|
+
"config": config,
|
|
244
|
+
"aoi": aoi,
|
|
245
|
+
"samples": samples,
|
|
246
|
+
"year_range": [start_year, end_year],
|
|
247
|
+
"crs": crs,
|
|
248
|
+
"tile_size": tile_size,
|
|
249
|
+
"res": res,
|
|
250
|
+
"output": output,
|
|
251
|
+
"server": server,
|
|
252
|
+
"region": region,
|
|
253
|
+
"bucket": bucket
|
|
254
|
+
}
|
|
255
|
+
print("the data is ", data)
|
|
256
|
+
print("the url is ", url)
|
|
257
|
+
response = self.session.post(url, json=data, verify=self.verify, timeout=self.timeout)
|
|
258
|
+
print("Status code:", response.status_code)
|
|
259
|
+
print("Response text:", response.text)
|
|
260
|
+
# response.raise_for_status()
|
|
261
|
+
return response.json()
|
|
262
|
+
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from typing import Dict, Any, Optional
|
|
3
|
+
from .exceptions import APIError
|
|
4
|
+
|
|
5
|
+
class SpaceManagement:
|
|
6
|
+
def __init__(self, api_url: str, api_key: str, verify: bool = True, timeout: int = 60):
|
|
7
|
+
self.api_url = api_url.rstrip('/')
|
|
8
|
+
self.api_key = api_key
|
|
9
|
+
self.verify = verify
|
|
10
|
+
self.timeout = timeout
|
|
11
|
+
self.session = requests.Session()
|
|
12
|
+
self.session.headers.update({
|
|
13
|
+
'x-api-key': self.api_key,
|
|
14
|
+
'Content-Type': 'application/json'
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
def get_total_space_used(self) -> Dict[str, Any]:
|
|
18
|
+
"""
|
|
19
|
+
Get total space used by the user.
|
|
20
|
+
Returns a dict with user, total, and jobs breakdown.
|
|
21
|
+
"""
|
|
22
|
+
endpoint = f"{self.api_url}/users/jobs"
|
|
23
|
+
try:
|
|
24
|
+
response = self.session.get(endpoint, timeout=self.timeout, verify=self.verify)
|
|
25
|
+
if not response.ok:
|
|
26
|
+
error_msg = f"API request failed: {response.status_code} {response.reason}"
|
|
27
|
+
try:
|
|
28
|
+
error_data = response.json()
|
|
29
|
+
if "detail" in error_data:
|
|
30
|
+
error_msg += f" - {error_data['detail']}"
|
|
31
|
+
except:
|
|
32
|
+
pass
|
|
33
|
+
raise APIError(error_msg)
|
|
34
|
+
return response.json()
|
|
35
|
+
except requests.RequestException as e:
|
|
36
|
+
raise APIError(f"Request failed: {str(e)}")
|
|
37
|
+
|
|
38
|
+
def get_space_used_by_job(self, name: str, region: Optional[str] = None) -> Dict[str, Any]:
|
|
39
|
+
"""
|
|
40
|
+
Get space used by a specific job.
|
|
41
|
+
"""
|
|
42
|
+
endpoint = f"{self.api_url}/users/jobs/{name}"
|
|
43
|
+
params = {"region": region} if region else {}
|
|
44
|
+
try:
|
|
45
|
+
response = self.session.get(endpoint, params=params, timeout=self.timeout, verify=self.verify)
|
|
46
|
+
if not response.ok:
|
|
47
|
+
error_msg = f"API request failed: {response.status_code} {response.reason}"
|
|
48
|
+
try:
|
|
49
|
+
error_data = response.json()
|
|
50
|
+
if "detail" in error_data:
|
|
51
|
+
error_msg += f" - {error_data['detail']}"
|
|
52
|
+
except:
|
|
53
|
+
pass
|
|
54
|
+
raise APIError(error_msg)
|
|
55
|
+
return response.json()
|
|
56
|
+
except requests.RequestException as e:
|
|
57
|
+
raise APIError(f"Request failed: {str(e)}")
|
|
58
|
+
|
|
59
|
+
def delete_user_job(self, name: str, region: Optional[str] = None) -> Dict[str, Any]:
|
|
60
|
+
"""
|
|
61
|
+
Delete a user job by name and region.
|
|
62
|
+
"""
|
|
63
|
+
endpoint = f"{self.api_url}/users/job/{name}"
|
|
64
|
+
params = {"region": region} if region else {}
|
|
65
|
+
try:
|
|
66
|
+
response = self.session.delete(endpoint, params=params, timeout=self.timeout, verify=self.verify)
|
|
67
|
+
if not response.ok:
|
|
68
|
+
error_msg = f"API request failed: {response.status_code} {response.reason}"
|
|
69
|
+
try:
|
|
70
|
+
error_data = response.json()
|
|
71
|
+
if "detail" in error_data:
|
|
72
|
+
error_msg += f" - {error_data['detail']}"
|
|
73
|
+
except:
|
|
74
|
+
pass
|
|
75
|
+
raise APIError(error_msg)
|
|
76
|
+
return response.json()
|
|
77
|
+
except requests.RequestException as e:
|
|
78
|
+
raise APIError(f"Request failed: {str(e)}")
|
|
79
|
+
|
|
80
|
+
def delete_data_in_path(self, path: str, region: Optional[str] = None) -> Dict[str, Any]:
|
|
81
|
+
"""
|
|
82
|
+
Delete data in a GCS path for a given region.
|
|
83
|
+
"""
|
|
84
|
+
endpoint = f"{self.api_url}/users/jobs"
|
|
85
|
+
params = {"path": path}
|
|
86
|
+
if region:
|
|
87
|
+
params["region"] = region
|
|
88
|
+
try:
|
|
89
|
+
response = self.session.delete(endpoint, params=params, timeout=self.timeout, verify=self.verify)
|
|
90
|
+
if not response.ok:
|
|
91
|
+
error_msg = f"API request failed: {response.status_code} {response.reason}"
|
|
92
|
+
try:
|
|
93
|
+
error_data = response.json()
|
|
94
|
+
if "detail" in error_data:
|
|
95
|
+
error_msg += f" - {error_data['detail']}"
|
|
96
|
+
except:
|
|
97
|
+
pass
|
|
98
|
+
raise APIError(error_msg)
|
|
99
|
+
return response.json()
|
|
100
|
+
except requests.RequestException as e:
|
|
101
|
+
raise APIError(f"Request failed: {str(e)}")
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from typing import Dict, Any, List, Optional
|
|
3
|
+
from .exceptions import APIError, ConfigurationError
|
|
4
|
+
|
|
5
|
+
class UserManagement:
|
|
6
|
+
def __init__(self, api_url: str, api_key: str, verify: bool = True, timeout: int = 60):
|
|
7
|
+
"""
|
|
8
|
+
Initialize the User Management client.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
api_url: API base URL
|
|
12
|
+
api_key: API key for authentication
|
|
13
|
+
verify: Verify SSL certificates
|
|
14
|
+
timeout: Request timeout in seconds
|
|
15
|
+
"""
|
|
16
|
+
self.api_url = api_url.rstrip('/')
|
|
17
|
+
self.api_key = api_key
|
|
18
|
+
self.verify = verify
|
|
19
|
+
self.timeout = timeout
|
|
20
|
+
self.session = requests.Session()
|
|
21
|
+
self.session.headers.update({
|
|
22
|
+
'x-api-key': self.api_key,
|
|
23
|
+
'Content-Type': 'application/json'
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
def get_user_by_id(self, user_id: str) -> Dict[str, Any]:
|
|
27
|
+
"""
|
|
28
|
+
Retrieve user info by user ID.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
user_id: User ID to retrieve
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
User information as a dictionary
|
|
35
|
+
|
|
36
|
+
Raises:
|
|
37
|
+
APIError: If the API request fails
|
|
38
|
+
"""
|
|
39
|
+
endpoint = f"{self.api_url}/admin/users/{user_id}"
|
|
40
|
+
try:
|
|
41
|
+
response = self.session.get(
|
|
42
|
+
endpoint,
|
|
43
|
+
timeout=self.timeout,
|
|
44
|
+
verify=self.verify
|
|
45
|
+
)
|
|
46
|
+
if not response.ok:
|
|
47
|
+
raise APIError(f"API request failed: {response.status_code} {response.reason}")
|
|
48
|
+
return response.json()
|
|
49
|
+
except requests.RequestException as e:
|
|
50
|
+
raise APIError(f"Request failed: {str(e)}")
|
|
51
|
+
|
|
52
|
+
def get_user_by_email(self, email: str) -> Dict[str, Any]:
|
|
53
|
+
"""
|
|
54
|
+
Retrieve user info by email.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
email: User email to retrieve
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
User information as a dictionary
|
|
61
|
+
|
|
62
|
+
Raises:
|
|
63
|
+
APIError: If the API request fails
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
endpoint = f"{self.api_url}/admin/users/email/{email}"
|
|
67
|
+
try:
|
|
68
|
+
response = self.session.get(
|
|
69
|
+
endpoint,
|
|
70
|
+
timeout=self.timeout,
|
|
71
|
+
verify=self.verify
|
|
72
|
+
)
|
|
73
|
+
if not response.ok:
|
|
74
|
+
raise APIError(f"API request failed: {response.status_code} {response.reason}")
|
|
75
|
+
return response.json()
|
|
76
|
+
except requests.RequestException as e:
|
|
77
|
+
raise APIError(f"Request failed: {str(e)}")
|
|
78
|
+
|
|
79
|
+
def edit_user(
|
|
80
|
+
self,
|
|
81
|
+
user_id: str,
|
|
82
|
+
uid: Optional[str] = None,
|
|
83
|
+
email: Optional[str] = None,
|
|
84
|
+
role: Optional[str] = None,
|
|
85
|
+
apiKey: Optional[str] = None,
|
|
86
|
+
groups: Optional[List[str]] = None,
|
|
87
|
+
quota: Optional[int] = None
|
|
88
|
+
) -> Dict[str, Any]:
|
|
89
|
+
"""
|
|
90
|
+
Edit user info. Only provided fields will be updated.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
user_id: User ID (required)
|
|
94
|
+
uid: New user ID (optional)
|
|
95
|
+
email: New user email (optional)
|
|
96
|
+
role: New user role (optional)
|
|
97
|
+
apiKey: New API key (optional)
|
|
98
|
+
groups: New list of groups (optional)
|
|
99
|
+
quota: New quota value (optional)
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Updated user information
|
|
103
|
+
|
|
104
|
+
Raises:
|
|
105
|
+
APIError: If the API request fails
|
|
106
|
+
"""
|
|
107
|
+
endpoint = f"{self.api_url}/admin/users"
|
|
108
|
+
payload = {"uid": user_id}
|
|
109
|
+
|
|
110
|
+
if uid is not None:
|
|
111
|
+
payload["uid"] = uid
|
|
112
|
+
if email is not None:
|
|
113
|
+
payload["email"] = email
|
|
114
|
+
if role is not None:
|
|
115
|
+
payload["role"] = role
|
|
116
|
+
if apiKey is not None:
|
|
117
|
+
payload["apiKey"] = apiKey
|
|
118
|
+
if groups is not None:
|
|
119
|
+
payload["groups"] = groups
|
|
120
|
+
if quota is not None:
|
|
121
|
+
payload["quota"] = quota
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
response = self.session.patch(
|
|
125
|
+
endpoint,
|
|
126
|
+
json=payload,
|
|
127
|
+
timeout=self.timeout,
|
|
128
|
+
verify=self.verify
|
|
129
|
+
)
|
|
130
|
+
if not response.ok:
|
|
131
|
+
raise APIError(f"API request failed: {response.status_code} {response.reason}")
|
|
132
|
+
return response.json()
|
|
133
|
+
except requests.RequestException as e:
|
|
134
|
+
raise APIError(f"Request failed: {str(e)}")
|
|
135
|
+
|
|
136
|
+
def list_users(self, substring: Optional[str] = None, uid: bool = False) -> List[Dict[str, Any]]:
|
|
137
|
+
"""
|
|
138
|
+
List users, optionally filtering by a substring.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
substring: Optional substring to filter users
|
|
142
|
+
uid: If True, includes the user ID in the response (default: False)
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
List of users
|
|
146
|
+
|
|
147
|
+
Raises:
|
|
148
|
+
APIError: If the API request fails
|
|
149
|
+
"""
|
|
150
|
+
# Use the base API URL instead of hardcoding
|
|
151
|
+
endpoint = "https://terrakio-server-lark-573248941006.australia-southeast1.run.app/admin/users"
|
|
152
|
+
|
|
153
|
+
params = {}
|
|
154
|
+
if substring:
|
|
155
|
+
params["substring"] = substring
|
|
156
|
+
if uid:
|
|
157
|
+
params["uid"] = "true"
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
response = self.session.get(
|
|
161
|
+
endpoint,
|
|
162
|
+
params=params,
|
|
163
|
+
timeout=self.timeout,
|
|
164
|
+
verify=self.verify
|
|
165
|
+
)
|
|
166
|
+
if not response.ok:
|
|
167
|
+
raise APIError(f"API request failed: {response.status_code} {response.reason}")
|
|
168
|
+
return response.json()
|
|
169
|
+
except requests.RequestException as e:
|
|
170
|
+
raise APIError(f"Request failed: {str(e)}")
|
|
171
|
+
|
|
172
|
+
def reset_quota(self, email: str, quota: Optional[int] = None) -> Dict[str, Any]:
|
|
173
|
+
"""
|
|
174
|
+
Reset the quota for a user by email.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
email: The user's email (required)
|
|
178
|
+
quota: The new quota value (optional)
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
API response as a dictionary
|
|
182
|
+
|
|
183
|
+
Raises:
|
|
184
|
+
APIError: If the API request fails
|
|
185
|
+
"""
|
|
186
|
+
endpoint = f"{self.api_url}/admin/users/reset_quota/{email}"
|
|
187
|
+
payload = {"email": email}
|
|
188
|
+
if quota is not None:
|
|
189
|
+
payload["quota"] = quota
|
|
190
|
+
try:
|
|
191
|
+
response = self.session.patch(
|
|
192
|
+
endpoint,
|
|
193
|
+
json=payload,
|
|
194
|
+
timeout=self.timeout,
|
|
195
|
+
verify=self.verify
|
|
196
|
+
)
|
|
197
|
+
if not response.ok:
|
|
198
|
+
raise APIError(f"API request failed: {response.status_code} {response.reason}")
|
|
199
|
+
return response.json()
|
|
200
|
+
except requests.RequestException as e:
|
|
201
|
+
raise APIError(f"Request failed: {str(e)}")
|
|
202
|
+
|
|
203
|
+
def delete_user(self, uid: str) -> Dict[str, Any]:
|
|
204
|
+
"""
|
|
205
|
+
Delete a user by UID.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
uid: The user's UID (required)
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
API response as a dictionary
|
|
212
|
+
|
|
213
|
+
Raises:
|
|
214
|
+
APIError: If the API request fails
|
|
215
|
+
"""
|
|
216
|
+
endpoint = f"{self.api_url}/admin/users/{uid}"
|
|
217
|
+
try:
|
|
218
|
+
response = self.session.delete(
|
|
219
|
+
endpoint,
|
|
220
|
+
timeout=self.timeout,
|
|
221
|
+
verify=self.verify
|
|
222
|
+
)
|
|
223
|
+
if not response.ok:
|
|
224
|
+
raise APIError(f"API request failed: {response.status_code} {response.reason}")
|
|
225
|
+
return response.json()
|
|
226
|
+
except requests.RequestException as e:
|
|
227
|
+
raise APIError(f"Request failed: {str(e)}")
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
terrakio_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
terrakio_core/auth.py,sha256=Nuj0_X3Hiy17svYgGxrSAR-LXpTlP0J0dSrfMnkPUbI,7717
|
|
3
|
+
terrakio_core/client.py,sha256=ykbgD_81HAtZXY9wDpPKR9audo5Xkh1Mh0HQcLPgyKs,46878
|
|
4
|
+
terrakio_core/config.py,sha256=AwJ1VgR5K7N32XCU5k7_Dp1nIv_FYt8MBonq9yKlGzA,2658
|
|
5
|
+
terrakio_core/dataset_management.py,sha256=hhO35fwStS6HYFQdKP9wkr3DxHgjvpctmIU8UWH6w6U,8742
|
|
6
|
+
terrakio_core/exceptions.py,sha256=9S-I20-QiDRj1qgjFyYUwYM7BLic_bxurcDOIm2Fu_0,410
|
|
7
|
+
terrakio_core/group_access_management.py,sha256=NJ7SX4keUzZAUENmJ5L6ynKf4eRlqtyir5uoKFyY17A,7315
|
|
8
|
+
terrakio_core/mass_stats.py,sha256=AqYJsd6nqo2BDh4vEPUDgsv4T0UR1_TPDoXa3WO3gTU,9284
|
|
9
|
+
terrakio_core/space_management.py,sha256=wlUUQrlj_4U_Lpjn9lbF5oj0Rv3NPvvnrd5mWej5kmA,4211
|
|
10
|
+
terrakio_core/user_management.py,sha256=MMNWkz0V_9X7ZYjjteuRU4H4W3F16iuQw1dpA2wVTGg,7400
|
|
11
|
+
terrakio_core-0.2.6.dist-info/METADATA,sha256=K-2CqTD95e3a7TgXSEk2JTadmVLQFbDdppRXBrMYyao,1405
|
|
12
|
+
terrakio_core-0.2.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
13
|
+
terrakio_core-0.2.6.dist-info/top_level.txt,sha256=5cBj6O7rNWyn97ND4YuvvXm0Crv4RxttT4JZvNdOG6Q,14
|
|
14
|
+
terrakio_core-0.2.6.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
terrakio_core
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
terrakio_core-0.2.3.dist-info/METADATA,sha256=y2lq4MvHKznM_bVtqtlrTW92lVpaOO9MpRz-e2wPVPQ,1405
|
|
2
|
-
terrakio_core-0.2.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
3
|
-
terrakio_core-0.2.3.dist-info/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
4
|
-
terrakio_core-0.2.3.dist-info/RECORD,,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
File without changes
|