reach_commons 0.17.0__tar.gz → 0.17.2__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.
- {reach_commons-0.17.0 → reach_commons-0.17.2}/PKG-INFO +1 -1
- {reach_commons-0.17.0 → reach_commons-0.17.2}/pyproject.toml +1 -1
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/clients/reach_ops_api.py +7 -0
- reach_commons-0.17.2/reach_commons/reach_aws/s3.py +113 -0
- reach_commons-0.17.0/reach_commons/reach_aws/s3.py +0 -63
- {reach_commons-0.17.0 → reach_commons-0.17.2}/README.md +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/__init__.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/app_logging/__init__.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/app_logging/http_logger.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/app_logging/log_deprecated_endpoints.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/app_logging/logger.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/app_logging/logging_config.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/clients/__init__.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/clients/event_processor.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/clients/hubspot.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/clients/outscraper.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/clients/reach_data_bridge.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/mongo/__init__.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/mongo/customer_persistence.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/mongo/customer_persistence_async.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/mongo/validation/__init__.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/reach_aws/__init__.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/reach_aws/commons.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/reach_aws/dynamo_db.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/reach_aws/exceptions.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/reach_aws/firehose.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/reach_aws/kms.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/reach_aws/sqs.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/reach_base_model.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/redis_manager.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/sms_smart_encoding.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/utils.py +0 -0
- {reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/validations.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# isort .; black .; poetry build; poetry publish
|
|
2
2
|
[tool.poetry]
|
|
3
3
|
name = "reach_commons"
|
|
4
|
-
version = "0.17.
|
|
4
|
+
version = "0.17.2"
|
|
5
5
|
description = "Reach Commons is a versatile utility library designed to streamline and enhance development workflows within the Reach ecosystem."
|
|
6
6
|
authors = ["Wilson Moraes <wmoraes@getreach.ai>"]
|
|
7
7
|
license = "MIT"
|
|
@@ -63,3 +63,10 @@ class ReachOpsApiClient:
|
|
|
63
63
|
data=json.dumps(invoice),
|
|
64
64
|
)
|
|
65
65
|
return resp
|
|
66
|
+
|
|
67
|
+
def enable_text_ai(self, business_id):
|
|
68
|
+
resp = requests.post(
|
|
69
|
+
f"{self.base_url}/conversations/{business_id}/text-ai/enable",
|
|
70
|
+
headers=self.gateway_headers,
|
|
71
|
+
)
|
|
72
|
+
return resp
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from functools import cached_property
|
|
2
|
+
from io import BytesIO
|
|
3
|
+
from urllib.parse import unquote, urlparse
|
|
4
|
+
|
|
5
|
+
import boto3
|
|
6
|
+
|
|
7
|
+
from reach_commons.app_logging.logger import get_reach_logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class S3Client:
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
logger=get_reach_logger(),
|
|
14
|
+
region_name="us-east-1",
|
|
15
|
+
profile_name=None,
|
|
16
|
+
):
|
|
17
|
+
self.logger = logger
|
|
18
|
+
self.region_name = region_name
|
|
19
|
+
self.profile_name = profile_name
|
|
20
|
+
|
|
21
|
+
@cached_property
|
|
22
|
+
def client(self):
|
|
23
|
+
session = boto3.Session(
|
|
24
|
+
region_name=self.region_name, profile_name=self.profile_name
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
return session.client("s3")
|
|
28
|
+
|
|
29
|
+
def _parse_s3_url(self, url: str) -> tuple[str, str]:
|
|
30
|
+
"""
|
|
31
|
+
Support various S3 URL formats:
|
|
32
|
+
- s3://bucket/key
|
|
33
|
+
- https://bucket.s3.amazonaws.com/key
|
|
34
|
+
- https://bucket.s3.<region>.amazonaws.com/key
|
|
35
|
+
- https://s3.<region>.amazonaws.com/bucket/key (path-style)
|
|
36
|
+
- https://s3.amazonaws.com/bucket/key (path-style)
|
|
37
|
+
"""
|
|
38
|
+
p = urlparse(url)
|
|
39
|
+
|
|
40
|
+
if p.scheme == "s3":
|
|
41
|
+
bucket = p.netloc
|
|
42
|
+
key = p.path.lstrip("/")
|
|
43
|
+
return bucket, unquote(key)
|
|
44
|
+
|
|
45
|
+
host = p.netloc
|
|
46
|
+
path = p.path.lstrip("/")
|
|
47
|
+
|
|
48
|
+
# Path-style: s3.<region>.amazonaws.com/bucket/key ou s3.amazonaws.com/bucket/key
|
|
49
|
+
if host.startswith("s3.") or host == "s3.amazonaws.com":
|
|
50
|
+
parts = path.split("/", 1)
|
|
51
|
+
if not parts or not parts[0]:
|
|
52
|
+
raise ValueError(f"Invalid S3 URL (missing bucket in path): {url}")
|
|
53
|
+
bucket = parts[0]
|
|
54
|
+
key = parts[1] if len(parts) > 1 else ""
|
|
55
|
+
return bucket, unquote(key)
|
|
56
|
+
|
|
57
|
+
# Virtual-hosted: bucket.s3[.<region>].amazonaws.com/key
|
|
58
|
+
bucket = host.split(".")[0]
|
|
59
|
+
key = path
|
|
60
|
+
if not bucket:
|
|
61
|
+
raise ValueError(f"Invalid S3 URL (missing bucket in host): {url}")
|
|
62
|
+
return bucket, unquote(key)
|
|
63
|
+
|
|
64
|
+
def get_object(self, s3_bucket_name, s3_key):
|
|
65
|
+
try:
|
|
66
|
+
s3_object = self.client.get_object(Bucket=s3_bucket_name, Key=s3_key)
|
|
67
|
+
actual_message_body = s3_object["Body"].read().decode("utf-8")
|
|
68
|
+
|
|
69
|
+
self.logger.info(
|
|
70
|
+
f"Retrieved object from S3: {s3_key} in bucket: {s3_bucket_name}"
|
|
71
|
+
)
|
|
72
|
+
return actual_message_body
|
|
73
|
+
except Exception as e:
|
|
74
|
+
self.logger.error(
|
|
75
|
+
f"Error retrieving object {s3_key} from bucket: {s3_bucket_name}: {str(e)}"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
def add_object(self, s3_bucket_name, s3_key, str_content):
|
|
81
|
+
try:
|
|
82
|
+
file_object = BytesIO(str_content.encode("utf-8"))
|
|
83
|
+
|
|
84
|
+
self.client.upload_fileobj(
|
|
85
|
+
Fileobj=file_object, Bucket=s3_bucket_name, Key=s3_key
|
|
86
|
+
)
|
|
87
|
+
url = (
|
|
88
|
+
f"https://{s3_bucket_name}.s3.{self.region_name}.amazonaws.com/{s3_key}"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
self.logger.info(
|
|
92
|
+
f"Uploaded object to S3: {s3_key} in bucket: {s3_bucket_name}"
|
|
93
|
+
)
|
|
94
|
+
return url
|
|
95
|
+
except Exception as e:
|
|
96
|
+
self.logger.error(
|
|
97
|
+
f"Error uploading object {s3_key} to bucket: {s3_bucket_name}: {str(e)}"
|
|
98
|
+
)
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
def delete_object_by_url(self, url: str) -> bool:
|
|
102
|
+
"""
|
|
103
|
+
Deleta um objeto no S3 recebendo apenas a URL direta.
|
|
104
|
+
Retorna True se deletou (ou o objeto não existia) e False se falhou.
|
|
105
|
+
"""
|
|
106
|
+
try:
|
|
107
|
+
bucket, key = self._parse_s3_url(url)
|
|
108
|
+
self.client.delete_object(Bucket=bucket, Key=key)
|
|
109
|
+
self.logger.info(f"Deleted object from S3: {key} in bucket: {bucket}")
|
|
110
|
+
return True
|
|
111
|
+
except Exception as e:
|
|
112
|
+
self.logger.error(f"Error deleting S3 object from url '{url}': {e}")
|
|
113
|
+
return False
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
from functools import cached_property
|
|
2
|
-
from io import BytesIO
|
|
3
|
-
|
|
4
|
-
import boto3
|
|
5
|
-
|
|
6
|
-
from reach_commons.app_logging.logger import get_reach_logger
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class S3Client:
|
|
10
|
-
def __init__(
|
|
11
|
-
self,
|
|
12
|
-
logger=get_reach_logger(),
|
|
13
|
-
region_name="us-east-1",
|
|
14
|
-
profile_name=None,
|
|
15
|
-
):
|
|
16
|
-
self.logger = logger
|
|
17
|
-
self.region_name = region_name
|
|
18
|
-
self.profile_name = profile_name
|
|
19
|
-
|
|
20
|
-
@cached_property
|
|
21
|
-
def client(self):
|
|
22
|
-
session = boto3.Session(
|
|
23
|
-
region_name=self.region_name, profile_name=self.profile_name
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
return session.client("s3")
|
|
27
|
-
|
|
28
|
-
def get_object(self, s3_bucket_name, s3_key):
|
|
29
|
-
try:
|
|
30
|
-
s3_object = self.client.get_object(Bucket=s3_bucket_name, Key=s3_key)
|
|
31
|
-
actual_message_body = s3_object["Body"].read().decode("utf-8")
|
|
32
|
-
|
|
33
|
-
self.logger.info(
|
|
34
|
-
f"Retrieved object from S3: {s3_key} from bucket: {s3_bucket_name}"
|
|
35
|
-
)
|
|
36
|
-
return actual_message_body
|
|
37
|
-
except Exception as e:
|
|
38
|
-
self.logger.error(
|
|
39
|
-
f"Error retrieving object {s3_key} from bucket: {s3_bucket_name}: {str(e)}"
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
return None
|
|
43
|
-
|
|
44
|
-
def add_object(self, s3_bucket_name, s3_key, str_content):
|
|
45
|
-
try:
|
|
46
|
-
file_object = BytesIO(str_content.encode("utf-8"))
|
|
47
|
-
|
|
48
|
-
self.client.upload_fileobj(
|
|
49
|
-
Fileobj=file_object, Bucket=s3_bucket_name, Key=s3_key
|
|
50
|
-
)
|
|
51
|
-
url = (
|
|
52
|
-
f"https://{s3_bucket_name}.s3.{self.region_name}.amazonaws.com/{s3_key}"
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
self.logger.info(
|
|
56
|
-
f"Uploaded object to S3: {s3_key} in bucket: {s3_bucket_name}"
|
|
57
|
-
)
|
|
58
|
-
return url
|
|
59
|
-
except Exception as e:
|
|
60
|
-
self.logger.error(
|
|
61
|
-
f"Error uploading object {s3_key} to bucket: {s3_bucket_name}: {str(e)}"
|
|
62
|
-
)
|
|
63
|
-
return None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/app_logging/log_deprecated_endpoints.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
|
|
File without changes
|
|
File without changes
|
{reach_commons-0.17.0 → reach_commons-0.17.2}/reach_commons/mongo/customer_persistence_async.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|