mbu-dev-shared-components 0.0.36__tar.gz → 0.0.38__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.
- {mbu_dev_shared_components-0.0.36/mbu_dev_shared_components.egg-info → mbu_dev_shared_components-0.0.38}/PKG-INFO +1 -1
- mbu_dev_shared_components-0.0.38/mbu_dev_shared_components/google/api/auth.py +134 -0
- mbu_dev_shared_components-0.0.38/mbu_dev_shared_components/google/workspace/alerts.py +53 -0
- mbu_dev_shared_components-0.0.38/mbu_dev_shared_components/os2forms/__init__.py +0 -0
- mbu_dev_shared_components-0.0.38/mbu_dev_shared_components/sap/__init__.py +0 -0
- mbu_dev_shared_components-0.0.38/mbu_dev_shared_components/utils/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38/mbu_dev_shared_components.egg-info}/PKG-INFO +1 -1
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components.egg-info/SOURCES.txt +5 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/.gitignore +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/LICENSE +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/README.md +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components/getorganized/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components/getorganized/auth.py +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components/getorganized/cases.py +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components/getorganized/contacts.py +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components/getorganized/documents.py +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components/getorganized/objects.py +0 -0
- {mbu_dev_shared_components-0.0.36/mbu_dev_shared_components/office365 → mbu_dev_shared_components-0.0.38/mbu_dev_shared_components/google}/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.36/mbu_dev_shared_components/office365/excel → mbu_dev_shared_components-0.0.38/mbu_dev_shared_components/google/api}/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.36/mbu_dev_shared_components/office365/sharepoint_api → mbu_dev_shared_components-0.0.38/mbu_dev_shared_components/google/workspace}/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.36/mbu_dev_shared_components/os2forms → mbu_dev_shared_components-0.0.38/mbu_dev_shared_components/office365}/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.36/mbu_dev_shared_components/sap → mbu_dev_shared_components-0.0.38/mbu_dev_shared_components/office365/excel}/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components/office365/excel/excel_reader.py +0 -0
- {mbu_dev_shared_components-0.0.36/mbu_dev_shared_components/utils → mbu_dev_shared_components-0.0.38/mbu_dev_shared_components/office365/sharepoint_api}/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components/office365/sharepoint_api/files.py +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components/os2forms/documents.py +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components/sap/create_invoice.py +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components/utils/db_stored_procedure_executor.py +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components/utils/json_handler.py +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components.egg-info/dependency_links.txt +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components.egg-info/requires.txt +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/mbu_dev_shared_components.egg-info/top_level.txt +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/pyproject.toml +0 -0
- {mbu_dev_shared_components-0.0.36 → mbu_dev_shared_components-0.0.38}/setup.cfg +0 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Google OAuth2 Token Fetcher.
|
|
3
|
+
This file contains a generic implementation of a class for
|
|
4
|
+
fetching Google OAuth2 tokens using a P12 key file.
|
|
5
|
+
"""
|
|
6
|
+
import base64
|
|
7
|
+
import json
|
|
8
|
+
import time
|
|
9
|
+
from typing import List, Dict, Any
|
|
10
|
+
from cryptography.hazmat.primitives import hashes
|
|
11
|
+
from cryptography.hazmat.primitives.asymmetric import padding
|
|
12
|
+
from cryptography.hazmat.primitives.serialization.pkcs12 import load_key_and_certificates
|
|
13
|
+
import requests
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class GoogleTokenFetcher:
|
|
17
|
+
"""
|
|
18
|
+
Class for fetching Google OAuth2 tokens using a P12 key file.
|
|
19
|
+
|
|
20
|
+
Attributes:
|
|
21
|
+
p12_key_path (str): Path to the P12 key file.
|
|
22
|
+
scopes (List[str]): A list of scopes required for the token.
|
|
23
|
+
app_email (str): Email for the service account.
|
|
24
|
+
admin_email (str): Email for the admin account.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, p12_key_path: str, scopes: List[str], app_email: str, admin_email: str):
|
|
28
|
+
"""
|
|
29
|
+
Initializes GoogleTokenFetcher with necessary attributes.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
p12_key_path (str): Path to the P12 key file.
|
|
33
|
+
scopes (List[str]): A list of scopes required for the token.
|
|
34
|
+
app_email (str): Email for the service account.
|
|
35
|
+
admin_email (str): Email for the admin account.
|
|
36
|
+
"""
|
|
37
|
+
self.p12_key_path = p12_key_path
|
|
38
|
+
self.scopes = scopes
|
|
39
|
+
self.app_email = app_email
|
|
40
|
+
self.admin_email = admin_email
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def _url_encode(data: bytes) -> str:
|
|
44
|
+
"""
|
|
45
|
+
URL-encodes a byte sequence in Base64 format.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
data (bytes): Data to be URL-encoded.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
str: URL-safe Base64-encoded string.
|
|
52
|
+
"""
|
|
53
|
+
return base64.urlsafe_b64encode(data).rstrip(b'=').decode('utf-8')
|
|
54
|
+
|
|
55
|
+
def _load_private_key(self) -> Any:
|
|
56
|
+
"""
|
|
57
|
+
Loads the private key from the P12 file.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Any: The private key object.
|
|
61
|
+
"""
|
|
62
|
+
with open(self.p12_key_path, 'rb') as f:
|
|
63
|
+
p12_data = f.read()
|
|
64
|
+
|
|
65
|
+
private_key, _, _ = load_key_and_certificates(
|
|
66
|
+
p12_data,
|
|
67
|
+
password=b'notasecret'
|
|
68
|
+
)
|
|
69
|
+
return private_key
|
|
70
|
+
|
|
71
|
+
def _create_jwt(self, private_key: Any, now: int, expiry_date: int) -> str:
|
|
72
|
+
"""
|
|
73
|
+
Creates a JWT signed with the private key.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
private_key (Any): The private key object.
|
|
77
|
+
now (int): The current time in seconds since epoch.
|
|
78
|
+
expiry_date (int): The expiration time of the token in seconds since epoch.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
str: The signed JWT.
|
|
82
|
+
"""
|
|
83
|
+
header = {
|
|
84
|
+
"alg": "RS256",
|
|
85
|
+
"typ": "JWT"
|
|
86
|
+
}
|
|
87
|
+
raw_header = self._url_encode(json.dumps(header).encode('utf-8'))
|
|
88
|
+
|
|
89
|
+
claims = {
|
|
90
|
+
"iss": self.app_email,
|
|
91
|
+
"sub": self.admin_email,
|
|
92
|
+
"scope": ' '.join(self.scopes),
|
|
93
|
+
"aud": "https://www.googleapis.com/oauth2/v4/token",
|
|
94
|
+
"exp": expiry_date,
|
|
95
|
+
"iat": now
|
|
96
|
+
}
|
|
97
|
+
raw_claims = self._url_encode(json.dumps(claims).encode('utf-8'))
|
|
98
|
+
|
|
99
|
+
to_sign = f"{raw_header}.{raw_claims}".encode('utf-8')
|
|
100
|
+
signature = private_key.sign(
|
|
101
|
+
to_sign,
|
|
102
|
+
padding.PKCS1v15(),
|
|
103
|
+
hashes.SHA256()
|
|
104
|
+
)
|
|
105
|
+
return f"{raw_header}.{raw_claims}.{self._url_encode(signature)}"
|
|
106
|
+
|
|
107
|
+
def get_google_token(self) -> Dict[str, Any]:
|
|
108
|
+
"""
|
|
109
|
+
Fetches a Google OAuth2 token using the P12 key file.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Dict[str, Any]: Response data from the token request.
|
|
113
|
+
"""
|
|
114
|
+
private_key = self._load_private_key()
|
|
115
|
+
|
|
116
|
+
now = int(time.time())
|
|
117
|
+
expiry_date = now + 3600
|
|
118
|
+
|
|
119
|
+
jwt = self._create_jwt(private_key, now, expiry_date)
|
|
120
|
+
|
|
121
|
+
fields = {
|
|
122
|
+
'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
|
123
|
+
'assertion': jwt
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
response = requests.post(
|
|
127
|
+
"https://www.googleapis.com/oauth2/v4/token",
|
|
128
|
+
data=fields,
|
|
129
|
+
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
|
130
|
+
timeout=60
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
response.raise_for_status()
|
|
134
|
+
return response
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides a function to fetch alerts from the Google Alert Center
|
|
3
|
+
API with pagination support. The `get_alerts` function sends a GET request
|
|
4
|
+
to the Google Alert Center API to retrieve alerts based on the provided access
|
|
5
|
+
token and optional filter, handling paginated results.
|
|
6
|
+
"""
|
|
7
|
+
from typing import Optional, List, Dict
|
|
8
|
+
import requests
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_alerts(access_token: str, alert_filter: Optional[str] = None) -> List[Dict]:
|
|
12
|
+
"""
|
|
13
|
+
Fetch alerts from the Google Alert Center API, handling paginated results.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
access_token (str): The OAuth 2.0 token for authentication.
|
|
17
|
+
alert_filter (Optional[str], optional): The filter to apply to the alerts query. Defaults to None.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
List[Dict]: A list of alerts data.
|
|
21
|
+
|
|
22
|
+
Raises:
|
|
23
|
+
requests.RequestException: If an error occurs during the HTTP request.
|
|
24
|
+
"""
|
|
25
|
+
headers = {
|
|
26
|
+
"Authorization": f"Bearer {access_token}",
|
|
27
|
+
"Scope": "https://www.googleapis.com/auth/apps.alerts"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
url = 'https://alertcenter.googleapis.com/v1beta1/alerts'
|
|
31
|
+
if alert_filter:
|
|
32
|
+
url += f'?filter={alert_filter}'
|
|
33
|
+
|
|
34
|
+
alerts = []
|
|
35
|
+
next_page_token = None
|
|
36
|
+
|
|
37
|
+
while True:
|
|
38
|
+
if next_page_token:
|
|
39
|
+
current_url = f'{url}&pageToken={next_page_token}'
|
|
40
|
+
else:
|
|
41
|
+
current_url = url
|
|
42
|
+
|
|
43
|
+
response = requests.get(current_url, headers=headers, timeout=60)
|
|
44
|
+
response.raise_for_status()
|
|
45
|
+
|
|
46
|
+
data = response.json()
|
|
47
|
+
alerts.extend(data.get('alerts', []))
|
|
48
|
+
|
|
49
|
+
next_page_token = data.get('nextPageToken')
|
|
50
|
+
if not next_page_token:
|
|
51
|
+
break
|
|
52
|
+
|
|
53
|
+
return alerts
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -13,6 +13,11 @@ mbu_dev_shared_components/getorganized/cases.py
|
|
|
13
13
|
mbu_dev_shared_components/getorganized/contacts.py
|
|
14
14
|
mbu_dev_shared_components/getorganized/documents.py
|
|
15
15
|
mbu_dev_shared_components/getorganized/objects.py
|
|
16
|
+
mbu_dev_shared_components/google/__init__.py
|
|
17
|
+
mbu_dev_shared_components/google/api/__init__.py
|
|
18
|
+
mbu_dev_shared_components/google/api/auth.py
|
|
19
|
+
mbu_dev_shared_components/google/workspace/__init__.py
|
|
20
|
+
mbu_dev_shared_components/google/workspace/alerts.py
|
|
16
21
|
mbu_dev_shared_components/office365/__init__.py
|
|
17
22
|
mbu_dev_shared_components/office365/excel/__init__.py
|
|
18
23
|
mbu_dev_shared_components/office365/excel/excel_reader.py
|
|
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
|
|
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
|