universal-mcp-applications 0.1.30rc1__py3-none-any.whl → 0.1.36rc1__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 universal-mcp-applications might be problematic. Click here for more details.
- universal_mcp/applications/ahrefs/app.py +52 -198
- universal_mcp/applications/airtable/app.py +23 -122
- universal_mcp/applications/apollo/app.py +111 -464
- universal_mcp/applications/asana/app.py +417 -1567
- universal_mcp/applications/aws_s3/app.py +33 -100
- universal_mcp/applications/bill/app.py +546 -1957
- universal_mcp/applications/box/app.py +1068 -3981
- universal_mcp/applications/braze/app.py +364 -1430
- universal_mcp/applications/browser_use/app.py +2 -8
- universal_mcp/applications/cal_com_v2/app.py +207 -625
- universal_mcp/applications/calendly/app.py +61 -200
- universal_mcp/applications/canva/app.py +45 -110
- universal_mcp/applications/clickup/app.py +207 -674
- universal_mcp/applications/coda/app.py +146 -426
- universal_mcp/applications/confluence/app.py +310 -1098
- universal_mcp/applications/contentful/app.py +36 -151
- universal_mcp/applications/crustdata/app.py +28 -107
- universal_mcp/applications/dialpad/app.py +283 -756
- universal_mcp/applications/digitalocean/app.py +1766 -5777
- universal_mcp/applications/domain_checker/app.py +3 -54
- universal_mcp/applications/e2b/app.py +14 -64
- universal_mcp/applications/elevenlabs/app.py +9 -47
- universal_mcp/applications/exa/app.py +6 -17
- universal_mcp/applications/falai/app.py +23 -100
- universal_mcp/applications/figma/app.py +53 -137
- universal_mcp/applications/file_system/app.py +2 -13
- universal_mcp/applications/firecrawl/app.py +51 -152
- universal_mcp/applications/fireflies/app.py +59 -281
- universal_mcp/applications/fpl/app.py +91 -528
- universal_mcp/applications/fpl/utils/fixtures.py +15 -49
- universal_mcp/applications/fpl/utils/helper.py +25 -89
- universal_mcp/applications/fpl/utils/league_utils.py +20 -64
- universal_mcp/applications/ghost_content/app.py +52 -161
- universal_mcp/applications/github/app.py +19 -56
- universal_mcp/applications/gong/app.py +88 -248
- universal_mcp/applications/google_calendar/app.py +16 -68
- universal_mcp/applications/google_docs/app.py +88 -188
- universal_mcp/applications/google_drive/app.py +140 -462
- universal_mcp/applications/google_gemini/app.py +12 -64
- universal_mcp/applications/google_mail/app.py +28 -157
- universal_mcp/applications/google_searchconsole/app.py +15 -48
- universal_mcp/applications/google_sheet/app.py +101 -578
- universal_mcp/applications/google_sheet/helper.py +10 -37
- universal_mcp/applications/hashnode/app.py +57 -269
- universal_mcp/applications/heygen/app.py +44 -122
- universal_mcp/applications/http_tools/app.py +10 -32
- universal_mcp/applications/hubspot/api_segments/crm_api.py +460 -1573
- universal_mcp/applications/hubspot/api_segments/marketing_api.py +74 -262
- universal_mcp/applications/hubspot/app.py +23 -87
- universal_mcp/applications/jira/app.py +2071 -7986
- universal_mcp/applications/klaviyo/app.py +494 -1376
- universal_mcp/applications/linkedin/README.md +23 -4
- universal_mcp/applications/linkedin/app.py +392 -212
- universal_mcp/applications/mailchimp/app.py +450 -1605
- universal_mcp/applications/markitdown/app.py +8 -20
- universal_mcp/applications/miro/app.py +217 -699
- universal_mcp/applications/ms_teams/app.py +64 -186
- universal_mcp/applications/neon/app.py +86 -192
- universal_mcp/applications/notion/app.py +21 -36
- universal_mcp/applications/onedrive/app.py +14 -36
- universal_mcp/applications/openai/app.py +42 -165
- universal_mcp/applications/outlook/app.py +16 -76
- universal_mcp/applications/perplexity/app.py +4 -19
- universal_mcp/applications/pipedrive/app.py +832 -3142
- universal_mcp/applications/posthog/app.py +163 -432
- universal_mcp/applications/reddit/app.py +40 -139
- universal_mcp/applications/resend/app.py +41 -107
- universal_mcp/applications/retell/app.py +14 -41
- universal_mcp/applications/rocketlane/app.py +221 -934
- universal_mcp/applications/scraper/README.md +7 -4
- universal_mcp/applications/scraper/app.py +280 -93
- universal_mcp/applications/semanticscholar/app.py +22 -64
- universal_mcp/applications/semrush/app.py +43 -77
- universal_mcp/applications/sendgrid/app.py +512 -1262
- universal_mcp/applications/sentry/app.py +271 -906
- universal_mcp/applications/serpapi/app.py +40 -143
- universal_mcp/applications/sharepoint/app.py +15 -37
- universal_mcp/applications/shopify/app.py +1551 -4287
- universal_mcp/applications/shortcut/app.py +155 -417
- universal_mcp/applications/slack/app.py +50 -101
- universal_mcp/applications/spotify/app.py +126 -325
- universal_mcp/applications/supabase/app.py +104 -213
- universal_mcp/applications/tavily/app.py +1 -1
- universal_mcp/applications/trello/app.py +693 -2656
- universal_mcp/applications/twilio/app.py +14 -50
- universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
- universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
- universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
- universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
- universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
- universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
- universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
- universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
- universal_mcp/applications/whatsapp/app.py +35 -186
- universal_mcp/applications/whatsapp/audio.py +2 -6
- universal_mcp/applications/whatsapp/whatsapp.py +17 -51
- universal_mcp/applications/whatsapp_business/app.py +70 -283
- universal_mcp/applications/wrike/app.py +45 -118
- universal_mcp/applications/yahoo_finance/app.py +19 -65
- universal_mcp/applications/youtube/app.py +75 -261
- universal_mcp/applications/zenquotes/app.py +2 -2
- {universal_mcp_applications-0.1.30rc1.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/METADATA +2 -2
- {universal_mcp_applications-0.1.30rc1.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/RECORD +105 -106
- universal_mcp/applications/scraper/scraper_testers.py +0 -17
- {universal_mcp_applications-0.1.30rc1.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/WHEEL +0 -0
- {universal_mcp_applications-0.1.30rc1.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import base64
|
|
2
2
|
import json
|
|
3
3
|
from typing import Any
|
|
4
|
-
|
|
5
4
|
import boto3
|
|
6
5
|
from botocore.exceptions import ClientError
|
|
7
6
|
from universal_mcp.applications.application import BaseApplication
|
|
@@ -36,10 +35,8 @@ class AwsS3App(BaseApplication):
|
|
|
36
35
|
if not self._client:
|
|
37
36
|
credentials = self.integration.get_credentials()
|
|
38
37
|
credentials = {
|
|
39
|
-
"aws_access_key_id": credentials.get("access_key_id")
|
|
40
|
-
or credentials.get("
|
|
41
|
-
"aws_secret_access_key": credentials.get("secret_access_key")
|
|
42
|
-
or credentials.get("password"),
|
|
38
|
+
"aws_access_key_id": credentials.get("access_key_id") or credentials.get("username"),
|
|
39
|
+
"aws_secret_access_key": credentials.get("secret_access_key") or credentials.get("password"),
|
|
43
40
|
"region_name": credentials.get("region"),
|
|
44
41
|
}
|
|
45
42
|
self._client = boto3.client("s3", **credentials)
|
|
@@ -55,7 +52,7 @@ class AwsS3App(BaseApplication):
|
|
|
55
52
|
response = self.client.list_buckets()
|
|
56
53
|
return [bucket["Name"] for bucket in response["Buckets"]]
|
|
57
54
|
|
|
58
|
-
def create_bucket(self, bucket_name: str, region: str | None = None) -> bool:
|
|
55
|
+
async def create_bucket(self, bucket_name: str, region: str | None = None) -> bool:
|
|
59
56
|
"""
|
|
60
57
|
Creates a new Amazon S3 bucket with a specified name and optional region. Returns `True` upon successful creation, or `False` if an AWS client error, such as a naming conflict or permission issue, occurs.
|
|
61
58
|
|
|
@@ -70,17 +67,14 @@ class AwsS3App(BaseApplication):
|
|
|
70
67
|
"""
|
|
71
68
|
try:
|
|
72
69
|
if region:
|
|
73
|
-
self.client.create_bucket(
|
|
74
|
-
Bucket=bucket_name,
|
|
75
|
-
CreateBucketConfiguration={"LocationConstraint": region},
|
|
76
|
-
)
|
|
70
|
+
self.client.create_bucket(Bucket=bucket_name, CreateBucketConfiguration={"LocationConstraint": region})
|
|
77
71
|
else:
|
|
78
72
|
self.client.create_bucket(Bucket=bucket_name)
|
|
79
73
|
return True
|
|
80
74
|
except ClientError:
|
|
81
75
|
return False
|
|
82
76
|
|
|
83
|
-
def delete_bucket(self, bucket_name: str) -> bool:
|
|
77
|
+
async def delete_bucket(self, bucket_name: str) -> bool:
|
|
84
78
|
"""
|
|
85
79
|
Deletes a specified S3 bucket. The operation requires the bucket to be empty to succeed. It returns `True` if the bucket is successfully deleted and `False` if an error occurs, such as the bucket not being found or containing objects.
|
|
86
80
|
|
|
@@ -98,7 +92,7 @@ class AwsS3App(BaseApplication):
|
|
|
98
92
|
except ClientError:
|
|
99
93
|
return False
|
|
100
94
|
|
|
101
|
-
def get_bucket_policy(self, bucket_name: str) -> dict[str, Any]:
|
|
95
|
+
async def get_bucket_policy(self, bucket_name: str) -> dict[str, Any]:
|
|
102
96
|
"""
|
|
103
97
|
Retrieves the IAM resource policy for a specified S3 bucket, parsing the JSON string into a dictionary. If the operation fails due to permissions or a non-existent policy, it returns an error dictionary. This complements `put_bucket_policy`, which applies a new policy.
|
|
104
98
|
|
|
@@ -116,7 +110,7 @@ class AwsS3App(BaseApplication):
|
|
|
116
110
|
except ClientError as e:
|
|
117
111
|
return {"error": str(e)}
|
|
118
112
|
|
|
119
|
-
def set_bucket_policy(self, bucket_name: str, policy: dict[str, Any]) -> bool:
|
|
113
|
+
async def set_bucket_policy(self, bucket_name: str, policy: dict[str, Any]) -> bool:
|
|
120
114
|
"""
|
|
121
115
|
Applies or replaces the access policy for a specified S3 bucket. The function accepts the policy as a dictionary, converts it to JSON, and assigns it to the bucket. This write operation is the counterpart to `get_bucket_policy` and returns `True` on success.
|
|
122
116
|
|
|
@@ -135,9 +129,7 @@ class AwsS3App(BaseApplication):
|
|
|
135
129
|
except ClientError:
|
|
136
130
|
return False
|
|
137
131
|
|
|
138
|
-
def list_subdirectories(
|
|
139
|
-
self, bucket_name: str, prefix: str | None = None
|
|
140
|
-
) -> list[str]:
|
|
132
|
+
async def list_subdirectories(self, bucket_name: str, prefix: str | None = None) -> list[str]:
|
|
141
133
|
"""
|
|
142
134
|
Lists immediate subdirectories (common prefixes) within an S3 bucket. If a prefix is provided, it returns subdirectories under that path; otherwise, it lists top-level directories. This function specifically lists folders, distinguishing it from `list_objects`, which lists files.
|
|
143
135
|
|
|
@@ -157,16 +149,13 @@ class AwsS3App(BaseApplication):
|
|
|
157
149
|
operation_parameters["Delimiter"] = "/"
|
|
158
150
|
else:
|
|
159
151
|
operation_parameters["Delimiter"] = "/"
|
|
160
|
-
|
|
161
152
|
prefixes = []
|
|
162
153
|
for page in paginator.paginate(**operation_parameters):
|
|
163
154
|
for cp in page.get("CommonPrefixes", []):
|
|
164
155
|
prefixes.append(cp.get("Prefix"))
|
|
165
156
|
return prefixes
|
|
166
157
|
|
|
167
|
-
def create_prefix(
|
|
168
|
-
self, bucket_name: str, prefix_name: str, parent_prefix: str | None = None
|
|
169
|
-
) -> bool:
|
|
158
|
+
async def create_prefix(self, bucket_name: str, prefix_name: str, parent_prefix: str | None = None) -> bool:
|
|
170
159
|
"""
|
|
171
160
|
Creates a prefix (folder) in an S3 bucket, optionally nested under a parent prefix. It simulates a directory by creating a zero-byte object with a key ending in a slash ('/'), distinguishing it from put_object, which uploads content.
|
|
172
161
|
|
|
@@ -187,7 +176,7 @@ class AwsS3App(BaseApplication):
|
|
|
187
176
|
self.client.put_object(Bucket=bucket_name, Key=key)
|
|
188
177
|
return True
|
|
189
178
|
|
|
190
|
-
def list_objects(self, bucket_name: str, prefix: str) -> list[dict[str, Any]]:
|
|
179
|
+
async def list_objects(self, bucket_name: str, prefix: str) -> list[dict[str, Any]]:
|
|
191
180
|
"""
|
|
192
181
|
Paginates through and lists all objects within a specified S3 bucket prefix. It returns a curated list of metadata for each object (key, name, size, last modified), excluding folder placeholders. This function specifically lists files, distinguishing it from `list_prefixes` which lists folders.
|
|
193
182
|
|
|
@@ -218,9 +207,7 @@ class AwsS3App(BaseApplication):
|
|
|
218
207
|
)
|
|
219
208
|
return objects
|
|
220
209
|
|
|
221
|
-
def put_text_object(
|
|
222
|
-
self, bucket_name: str, prefix: str, object_name: str, content: str
|
|
223
|
-
) -> bool:
|
|
210
|
+
async def put_text_object(self, bucket_name: str, prefix: str, object_name: str, content: str) -> bool:
|
|
224
211
|
"""
|
|
225
212
|
Uploads string content to create an object in a specified S3 bucket and prefix. The content is UTF-8 encoded before being written. This method is for text, distinguishing it from `put_object_from_base64` which handles binary data.
|
|
226
213
|
|
|
@@ -236,14 +223,10 @@ class AwsS3App(BaseApplication):
|
|
|
236
223
|
important
|
|
237
224
|
"""
|
|
238
225
|
key = f"{prefix.rstrip('/')}/{object_name}" if prefix else object_name
|
|
239
|
-
self.client.put_object(
|
|
240
|
-
Bucket=bucket_name, Key=key, Body=content.encode("utf-8")
|
|
241
|
-
)
|
|
226
|
+
self.client.put_object(Bucket=bucket_name, Key=key, Body=content.encode("utf-8"))
|
|
242
227
|
return True
|
|
243
228
|
|
|
244
|
-
def put_object_from_base64(
|
|
245
|
-
self, bucket_name: str, prefix: str, object_name: str, base64_content: str
|
|
246
|
-
) -> bool:
|
|
229
|
+
async def put_object_from_base64(self, bucket_name: str, prefix: str, object_name: str, base64_content: str) -> bool:
|
|
247
230
|
"""
|
|
248
231
|
Decodes a base64 string into binary data and uploads it as an object to a specified S3 location. This method is designed for binary files, differentiating it from `put_object` which handles plain text content. Returns true on success.
|
|
249
232
|
|
|
@@ -266,7 +249,7 @@ class AwsS3App(BaseApplication):
|
|
|
266
249
|
except Exception:
|
|
267
250
|
return False
|
|
268
251
|
|
|
269
|
-
def get_object_with_content(self, bucket_name: str, key: str) -> dict[str, Any]:
|
|
252
|
+
async def get_object_with_content(self, bucket_name: str, key: str) -> dict[str, Any]:
|
|
270
253
|
"""
|
|
271
254
|
Retrieves an S3 object's content. It decodes text files as UTF-8 or encodes binary files as base64 based on the object's key. This function downloads the full object body, unlike `get_object_metadata` which only fetches metadata without content, returning the content, name, size, and type.
|
|
272
255
|
|
|
@@ -282,24 +265,15 @@ class AwsS3App(BaseApplication):
|
|
|
282
265
|
try:
|
|
283
266
|
obj = self.client.get_object(Bucket=bucket_name, Key=key)
|
|
284
267
|
content = obj["Body"].read()
|
|
285
|
-
is_text_file = key.lower().endswith(
|
|
286
|
-
(".txt", ".csv", ".json", ".xml", ".html", ".md", ".js", ".css", ".py")
|
|
287
|
-
)
|
|
268
|
+
is_text_file = key.lower().endswith((".txt", ".csv", ".json", ".xml", ".html", ".md", ".js", ".css", ".py"))
|
|
288
269
|
content_dict = (
|
|
289
|
-
{"content": content.decode("utf-8")}
|
|
290
|
-
if is_text_file
|
|
291
|
-
else {"content_base64": base64.b64encode(content).decode("ascii")}
|
|
270
|
+
{"content": content.decode("utf-8")} if is_text_file else {"content_base64": base64.b64encode(content).decode("ascii")}
|
|
292
271
|
)
|
|
293
|
-
return {
|
|
294
|
-
"name": key.split("/")[-1],
|
|
295
|
-
"content_type": "text" if is_text_file else "binary",
|
|
296
|
-
**content_dict,
|
|
297
|
-
"size": len(content),
|
|
298
|
-
}
|
|
272
|
+
return {"name": key.split("/")[-1], "content_type": "text" if is_text_file else "binary", **content_dict, "size": len(content)}
|
|
299
273
|
except ClientError as e:
|
|
300
274
|
return {"error": str(e)}
|
|
301
275
|
|
|
302
|
-
def get_object_metadata(self, bucket_name: str, key: str) -> dict[str, Any]:
|
|
276
|
+
async def get_object_metadata(self, bucket_name: str, key: str) -> dict[str, Any]:
|
|
303
277
|
"""
|
|
304
278
|
Efficiently retrieves metadata for a specified S3 object, such as size and last modified date, without downloading its content. This function uses a HEAD request, making it faster than `get_object_content` for accessing object properties. Returns a dictionary of metadata or an error message on failure.
|
|
305
279
|
|
|
@@ -318,9 +292,7 @@ class AwsS3App(BaseApplication):
|
|
|
318
292
|
"key": key,
|
|
319
293
|
"name": key.split("/")[-1],
|
|
320
294
|
"size": response.get("ContentLength", 0),
|
|
321
|
-
"last_modified": response.get("LastModified", "").isoformat()
|
|
322
|
-
if response.get("LastModified")
|
|
323
|
-
else "",
|
|
295
|
+
"last_modified": response.get("LastModified", "").isoformat() if response.get("LastModified") else "",
|
|
324
296
|
"content_type": response.get("ContentType", ""),
|
|
325
297
|
"etag": response.get("ETag", ""),
|
|
326
298
|
"metadata": response.get("Metadata", {}),
|
|
@@ -328,9 +300,7 @@ class AwsS3App(BaseApplication):
|
|
|
328
300
|
except ClientError as e:
|
|
329
301
|
return {"error": str(e)}
|
|
330
302
|
|
|
331
|
-
def copy_object(
|
|
332
|
-
self, source_bucket: str, source_key: str, dest_bucket: str, dest_key: str
|
|
333
|
-
) -> bool:
|
|
303
|
+
async def copy_object(self, source_bucket: str, source_key: str, dest_bucket: str, dest_key: str) -> bool:
|
|
334
304
|
"""
|
|
335
305
|
Copies an S3 object from a specified source location to a destination, which can be in the same or a different bucket. Unlike `move_object`, the original object remains at the source after the copy operation. It returns `True` for a successful operation.
|
|
336
306
|
|
|
@@ -347,16 +317,12 @@ class AwsS3App(BaseApplication):
|
|
|
347
317
|
"""
|
|
348
318
|
try:
|
|
349
319
|
copy_source = {"Bucket": source_bucket, "Key": source_key}
|
|
350
|
-
self.client.copy_object(
|
|
351
|
-
CopySource=copy_source, Bucket=dest_bucket, Key=dest_key
|
|
352
|
-
)
|
|
320
|
+
self.client.copy_object(CopySource=copy_source, Bucket=dest_bucket, Key=dest_key)
|
|
353
321
|
return True
|
|
354
322
|
except ClientError:
|
|
355
323
|
return False
|
|
356
324
|
|
|
357
|
-
def move_object(
|
|
358
|
-
self, source_bucket: str, source_key: str, dest_bucket: str, dest_key: str
|
|
359
|
-
) -> bool:
|
|
325
|
+
async def move_object(self, source_bucket: str, source_key: str, dest_bucket: str, dest_key: str) -> bool:
|
|
360
326
|
"""
|
|
361
327
|
Moves an S3 object from a source to a destination. This is achieved by first copying the object to the new location and subsequently deleting the original. The move can occur within the same bucket or between different ones, returning `True` on success.
|
|
362
328
|
|
|
@@ -375,7 +341,7 @@ class AwsS3App(BaseApplication):
|
|
|
375
341
|
return self.delete_object(source_bucket, source_key)
|
|
376
342
|
return False
|
|
377
343
|
|
|
378
|
-
def delete_single_object(self, bucket_name: str, key: str) -> bool:
|
|
344
|
+
async def delete_single_object(self, bucket_name: str, key: str) -> bool:
|
|
379
345
|
"""
|
|
380
346
|
Deletes a single, specified object from an S3 bucket using its key. Returns `True` if successful, otherwise `False`. For bulk deletions in a single request, the `delete_objects` function should be used instead.
|
|
381
347
|
|
|
@@ -394,7 +360,7 @@ class AwsS3App(BaseApplication):
|
|
|
394
360
|
except ClientError:
|
|
395
361
|
return False
|
|
396
362
|
|
|
397
|
-
def delete_objects(self, bucket_name: str, keys: list[str]) -> dict[str, Any]:
|
|
363
|
+
async def delete_objects(self, bucket_name: str, keys: list[str]) -> dict[str, Any]:
|
|
398
364
|
"""
|
|
399
365
|
Performs a bulk deletion of objects from a specified S3 bucket in a single request. Given a list of keys, it returns a dictionary detailing successful deletions and any errors. This method is the batch-processing counterpart to the singular `delete_object` function, designed for efficiency.
|
|
400
366
|
|
|
@@ -409,9 +375,7 @@ class AwsS3App(BaseApplication):
|
|
|
409
375
|
"""
|
|
410
376
|
try:
|
|
411
377
|
delete_dict = {"Objects": [{"Key": key} for key in keys]}
|
|
412
|
-
response = self.client.delete_objects(
|
|
413
|
-
Bucket=bucket_name, Delete=delete_dict
|
|
414
|
-
)
|
|
378
|
+
response = self.client.delete_objects(Bucket=bucket_name, Delete=delete_dict)
|
|
415
379
|
return {
|
|
416
380
|
"deleted": [obj.get("Key") for obj in response.get("Deleted", [])],
|
|
417
381
|
"errors": [obj for obj in response.get("Errors", [])],
|
|
@@ -419,13 +383,7 @@ class AwsS3App(BaseApplication):
|
|
|
419
383
|
except ClientError as e:
|
|
420
384
|
return {"error": str(e)}
|
|
421
385
|
|
|
422
|
-
def generate_presigned_url(
|
|
423
|
-
self,
|
|
424
|
-
bucket_name: str,
|
|
425
|
-
key: str,
|
|
426
|
-
expiration: int = 3600,
|
|
427
|
-
http_method: str = "GET",
|
|
428
|
-
) -> str:
|
|
386
|
+
async def generate_presigned_url(self, bucket_name: str, key: str, expiration: int = 3600, http_method: str = "GET") -> str:
|
|
429
387
|
"""
|
|
430
388
|
Generates a temporary, secure URL for a specific S3 object. This URL grants time-limited permissions for actions like GET, PUT, or DELETE, expiring after a defined period. It allows object access without sharing permanent AWS credentials.
|
|
431
389
|
|
|
@@ -441,28 +399,16 @@ class AwsS3App(BaseApplication):
|
|
|
441
399
|
important
|
|
442
400
|
"""
|
|
443
401
|
try:
|
|
444
|
-
method_map = {
|
|
445
|
-
"GET": "get_object",
|
|
446
|
-
"PUT": "put_object",
|
|
447
|
-
"DELETE": "delete_object",
|
|
448
|
-
}
|
|
449
|
-
|
|
402
|
+
method_map = {"GET": "get_object", "PUT": "put_object", "DELETE": "delete_object"}
|
|
450
403
|
response = self.client.generate_presigned_url(
|
|
451
|
-
method_map.get(http_method.upper(), "get_object"),
|
|
452
|
-
Params={"Bucket": bucket_name, "Key": key},
|
|
453
|
-
ExpiresIn=expiration,
|
|
404
|
+
method_map.get(http_method.upper(), "get_object"), Params={"Bucket": bucket_name, "Key": key}, ExpiresIn=expiration
|
|
454
405
|
)
|
|
455
406
|
return response
|
|
456
407
|
except ClientError as e:
|
|
457
408
|
return f"Error: {str(e)}"
|
|
458
409
|
|
|
459
|
-
def search_objects(
|
|
460
|
-
self,
|
|
461
|
-
bucket_name: str,
|
|
462
|
-
prefix: str = "",
|
|
463
|
-
name_pattern: str = "",
|
|
464
|
-
min_size: int | None = None,
|
|
465
|
-
max_size: int | None = None,
|
|
410
|
+
async def search_objects(
|
|
411
|
+
self, bucket_name: str, prefix: str = "", name_pattern: str = "", min_size: int | None = None, max_size: int | None = None
|
|
466
412
|
) -> list[dict[str, Any]]:
|
|
467
413
|
"""
|
|
468
414
|
Filters objects within an S3 bucket and prefix based on a name pattern and size range. It retrieves all objects via `list_objects` and then applies the specified criteria client-side, returning a refined list of matching objects and their metadata.
|
|
@@ -481,23 +427,17 @@ class AwsS3App(BaseApplication):
|
|
|
481
427
|
"""
|
|
482
428
|
all_objects = self.list_objects(bucket_name, prefix)
|
|
483
429
|
filtered_objects = []
|
|
484
|
-
|
|
485
430
|
for obj in all_objects:
|
|
486
|
-
# Filter by name pattern
|
|
487
431
|
if name_pattern and name_pattern.lower() not in obj["name"].lower():
|
|
488
432
|
continue
|
|
489
|
-
|
|
490
|
-
# Filter by size
|
|
491
433
|
if min_size and obj["size"] < min_size:
|
|
492
434
|
continue
|
|
493
435
|
if max_size and obj["size"] > max_size:
|
|
494
436
|
continue
|
|
495
|
-
|
|
496
437
|
filtered_objects.append(obj)
|
|
497
|
-
|
|
498
438
|
return filtered_objects
|
|
499
439
|
|
|
500
|
-
def get_storage_summary(self, bucket_name: str, prefix: str = "") -> dict[str, Any]:
|
|
440
|
+
async def get_storage_summary(self, bucket_name: str, prefix: str = "") -> dict[str, Any]:
|
|
501
441
|
"""
|
|
502
442
|
Calculates and returns statistics for an S3 bucket or prefix. The result includes the total number of objects, their combined size in bytes, and a human-readable string representation of the size (e.g., '15.2 MB').
|
|
503
443
|
|
|
@@ -511,10 +451,8 @@ class AwsS3App(BaseApplication):
|
|
|
511
451
|
important
|
|
512
452
|
"""
|
|
513
453
|
objects = self.list_objects(bucket_name, prefix)
|
|
514
|
-
total_size = sum(obj["size"] for obj in objects)
|
|
454
|
+
total_size = sum((obj["size"] for obj in objects))
|
|
515
455
|
object_count = len(objects)
|
|
516
|
-
|
|
517
|
-
# Convert to human-readable format
|
|
518
456
|
for unit in ["B", "KB", "MB", "GB", "TB"]:
|
|
519
457
|
if total_size < 1024.0:
|
|
520
458
|
human_size = f"{total_size:.2f} {unit}"
|
|
@@ -522,12 +460,7 @@ class AwsS3App(BaseApplication):
|
|
|
522
460
|
total_size /= 1024.0
|
|
523
461
|
else:
|
|
524
462
|
human_size = f"{total_size:.2f} PB"
|
|
525
|
-
|
|
526
|
-
return {
|
|
527
|
-
"total_size_bytes": sum(obj["size"] for obj in objects),
|
|
528
|
-
"human_readable_size": human_size,
|
|
529
|
-
"object_count": object_count,
|
|
530
|
-
}
|
|
463
|
+
return {"total_size_bytes": sum((obj["size"] for obj in objects)), "human_readable_size": human_size, "object_count": object_count}
|
|
531
464
|
|
|
532
465
|
def list_tools(self):
|
|
533
466
|
return [
|