bw-essentials-core 0.0.9__tar.gz → 0.1.1__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.

Potentially problematic release.


This version of bw-essentials-core might be problematic. Click here for more details.

Files changed (32) hide show
  1. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/PKG-INFO +1 -1
  2. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/constants/services.py +1 -0
  3. bw_essentials_core-0.1.1/bw_essentials/services/notification.py +77 -0
  4. bw_essentials_core-0.1.1/bw_essentials/services/user_app.py +323 -0
  5. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials_core.egg-info/PKG-INFO +1 -1
  6. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials_core.egg-info/SOURCES.txt +2 -0
  7. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/setup.py +1 -1
  8. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/README.md +0 -0
  9. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/__init__.py +0 -0
  10. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/constants/__init__.py +0 -0
  11. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/data_loch/__init__.py +0 -0
  12. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/data_loch/data_loch.py +0 -0
  13. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/email_client/__init__.py +0 -0
  14. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/email_client/email_client.py +0 -0
  15. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/notifications/__init__.py +0 -0
  16. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/notifications/teams_notification_schemas.py +0 -0
  17. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/notifications/teams_notifications.py +0 -0
  18. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/s3_utils/__init__.py +0 -0
  19. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/s3_utils/s3_utils.py +0 -0
  20. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/services/__init__.py +0 -0
  21. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/services/api_client.py +0 -0
  22. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/services/broker.py +0 -0
  23. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/services/market_pricer.py +0 -0
  24. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/services/master_data.py +0 -0
  25. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/services/model_portfolio_reporting.py +0 -0
  26. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/services/trade_placement.py +0 -0
  27. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/services/user_portfolio.py +0 -0
  28. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials/services/user_portfolio_reporting.py +0 -0
  29. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials_core.egg-info/dependency_links.txt +0 -0
  30. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials_core.egg-info/requires.txt +0 -0
  31. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/bw_essentials_core.egg-info/top_level.txt +0 -0
  32. {bw_essentials_core-0.0.9 → bw_essentials_core-0.1.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bw-essentials-core
3
- Version: 0.0.9
3
+ Version: 0.1.1
4
4
  Summary: Reusable utilities for S3, email, Data Loch, Microsoft Teams Notifications and more.
5
5
  Author: InvestorAI
6
6
  Author-email: support+tech@investorai.in
@@ -17,3 +17,4 @@ class Services(Enum):
17
17
  USER_REPORTING = 'User_Reporting'
18
18
  PAYMENT = 'Payment'
19
19
  MODEL_PORTFOLIO = "Model_Portfolio"
20
+ PROMETHEUS_USER_APP = "Prometheus_User_App"
@@ -0,0 +1,77 @@
1
+ """
2
+ Module to make API calls to Notification Service
3
+ """
4
+ import logging
5
+
6
+ from bw_essentials.constants.services import Services
7
+ from bw_essentials.services.api_client import ApiClient
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ class NotificationService(ApiClient):
13
+ """
14
+ Handles notifications through various channels.
15
+ """
16
+ PLATFORM = "PLATFORM"
17
+ NOTIFICATION_API_KEY = 'NOTIFICATION_API_KEY'
18
+ NOTIFICATION_SENDER_NUMBER = "NOTIFICATION_SENDER_NUMBER"
19
+
20
+ def __init__(self):
21
+ """
22
+ Initializes the Notification object.
23
+
24
+ Args:
25
+ - user: The user associated with the notification.
26
+ """
27
+ super().__init__("notification")
28
+ self.name = Services.NOTIFICATION.value
29
+ self.base_url = self.get_base_url(self.name)
30
+ self.urls = {
31
+ "whatsapp": "whatsapp"
32
+ }
33
+
34
+ def _whatsapp(self, title, template, platform, params, to, user_id):
35
+ """
36
+ Sends a WhatsApp notification.
37
+
38
+ Args:
39
+ - user_id (str): The ID of the user receiving the notification.
40
+ - number (str): The phone number for the recipient.
41
+ - title (str): Title of the notification.
42
+ - template (str): Template for the WhatsApp message.
43
+ - platform (str): The platform used for sending
44
+ (WhatsApp, in this case).
45
+ - params: Parameters for the notification message.
46
+
47
+ Returns:
48
+ None
49
+ """
50
+ logger.info(f"In - whatsapp {user_id =}, {to =}, "
51
+ f"{title =}, {template =}, {platform =}, {params =}")
52
+ payload = {
53
+ "from": self._get_env_var(NotificationService.NOTIFICATION_SENDER_NUMBER),
54
+ "to": to,
55
+ "userId": user_id,
56
+ "platform": platform,
57
+ "title": title,
58
+ "template": template,
59
+ "params": params
60
+ }
61
+ logger.info(f"whatsapp {payload =}")
62
+ headers = {
63
+ 'api-key': self._get_env_var(NotificationService.NOTIFICATION_API_KEY)
64
+ }
65
+ self.set_headers(headers)
66
+ resp_data = self._post(url=self.base_url, endpoint=self.urls.get('whatsapp'), data=payload)
67
+ logger.info(f"Whatsapp response {resp_data =}")
68
+
69
+ def send_whatsapp(self, template, title, params, to, user_id):
70
+ logger.info(f"In - send_whatsapp_notification {user_id =} {title = } {params = } {to = }")
71
+
72
+ self._whatsapp(title=title,
73
+ template=template,
74
+ platform=self._get_env_var(NotificationService.PLATFORM),
75
+ params=params,
76
+ to=to,
77
+ user_id=user_id)
@@ -0,0 +1,323 @@
1
+ """
2
+ prometheus_user_app.py
3
+
4
+ Module to interact with the Prometheus User App Service API.
5
+
6
+ This module provides a high-level client wrapper around the Prometheus User App Service,
7
+ enabling secure, structured, and logged communication with its endpoints. It includes:
8
+
9
+ - Type-safe interfaces
10
+ - Detailed request and response logging
11
+ - Validated endpoint routing
12
+ - Clear, maintainable service integration points
13
+ """
14
+
15
+ from typing import Optional, Dict, Any
16
+ import logging
17
+
18
+ from bw_essentials.constants.services import Services
19
+ from bw_essentials.services.api_client import ApiClient
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ class PrometheusUserApp(ApiClient):
25
+ """
26
+ Client for interacting with the Prometheus User App Service API.
27
+
28
+ This class handles API communication with Prometheus User App endpoints. It abstracts
29
+ request handling, URL construction, and logging while ensuring robust error management.
30
+
31
+ Attributes:
32
+ base_url (str): Base URL derived from tenant configuration
33
+ name (str): Service identifier
34
+ urls (Dict[str, str]): A dictionary of endpoint path templates
35
+ """
36
+
37
+ def __init__(self, service_user: str):
38
+ """
39
+ Initialize the PrometheusUserApp client with the given service user.
40
+
41
+ Args:
42
+ service_user (str): Username or service identifier for authentication.
43
+ """
44
+ super().__init__(user=service_user)
45
+ self.base_url = self.get_base_url(Services.PROMETHEUS_USER_APP.value)
46
+ self.name = Services.PROMETHEUS_USER_APP.value
47
+ self.urls = {
48
+ "user_details": "user/details",
49
+ "profile": "user/profile",
50
+ "get_profile": "user/profile/",
51
+ "login": "user/login",
52
+ "register_user": "user/register",
53
+ "update_dealer_disclaimer": "user/{}/dealer/disclaimer/",
54
+ "dealer_users": "user/{}/dealer/users",
55
+ "user_disclaimer": "user/{}/disclaimer/",
56
+ "dealer_login": "user/{}/login/dealer",
57
+ "send_otp": "user/{}/otp/send",
58
+ "verify_otp": "user/{}/otp/verify",
59
+ "register_dealer_user": "user/{}/register/dealer",
60
+ "sso": "user/{}/sso"
61
+ }
62
+
63
+ def get_user_details(self, user_id: str) -> Optional[Dict[str, Any]]:
64
+ """
65
+ Fetch detailed user information by user ID.
66
+
67
+ Args:
68
+ user_id (str): Unique identifier of the user.
69
+
70
+ Returns:
71
+ Optional[Dict[str, Any]]: Parsed user data if found, else None.
72
+ """
73
+ logger.info("Fetching user details for user_id=%s", user_id)
74
+ response = self._get(
75
+ endpoint=self.urls["user_details"],
76
+ url=self.base_url,
77
+ params={'user_id': user_id}
78
+ )
79
+ return response.get('data')
80
+
81
+ def update_user_profile(self, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
82
+ """
83
+ Update the user profile with provided data.
84
+
85
+ Args:
86
+ data (Dict[str, Any]): Dictionary containing user profile updates.
87
+
88
+ Returns:
89
+ Optional[Dict[str, Any]]: Updated profile data if successful, else None.
90
+ """
91
+ logger.info("Updating user profile with data: %s", data)
92
+ response = self._put(
93
+ endpoint=self.urls["profile"],
94
+ url=self.base_url,
95
+ data=data
96
+ )
97
+ return response.get('data')
98
+
99
+ def login(self, user_id: str, password: str) -> Optional[Dict[str, Any]]:
100
+ """
101
+ Authenticate a user using credentials.
102
+
103
+ Args:
104
+ user_id (str): User identifier (e.g., username).
105
+ password (str): User password.
106
+
107
+ Returns:
108
+ Optional[Dict[str, Any]]: Auth token or login response if successful.
109
+ """
110
+ logger.info("Logging in user %s", user_id)
111
+ response = self._post(
112
+ endpoint=self.urls["login"],
113
+ url=self.base_url,
114
+ json={'username': user_id, 'password': password}
115
+ )
116
+ return response.get('data')
117
+
118
+ def get_user_profile(self, user_id: str) -> Optional[Dict[str, Any]]:
119
+ """
120
+ Retrieve profile details of a user.
121
+
122
+ Args:
123
+ user_id (str): Unique user identifier.
124
+
125
+ Returns:
126
+ Optional[Dict[str, Any]]: User profile information if successful.
127
+ """
128
+ logger.info("Fetching profile for user %s", user_id)
129
+ response = self._get(
130
+ endpoint=self.urls["get_profile"],
131
+ url=self.base_url
132
+ )
133
+ return response.get('data')
134
+
135
+ def register_user(self, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
136
+ """
137
+ Register a new user with the service.
138
+
139
+ Args:
140
+ data (Dict[str, Any]): Registration details including user information.
141
+
142
+ Returns:
143
+ Optional[Dict[str, Any]]: Registration confirmation or created user details.
144
+ """
145
+ logger.info("Registering new user with data: %s", data)
146
+ response = self._post(
147
+ endpoint=self.urls["register_user"],
148
+ url=self.base_url,
149
+ json=data
150
+ )
151
+ return response
152
+
153
+ def update_dealer_disclaimer(self, broker: str, user_id: str, disclaimer_accepted: bool) -> Optional[Dict[str, Any]]:
154
+ """
155
+ Update a user's dealer disclaimer status.
156
+
157
+ Args:
158
+ broker (str): Broker identifier.
159
+ user_id (str): User ID whose disclaimer is being updated.
160
+ disclaimer_accepted (bool): Whether disclaimer is accepted.
161
+
162
+ Returns:
163
+ Optional[Dict[str, Any]]: Updated disclaimer status if successful.
164
+ """
165
+ logger.info("Updating dealer disclaimer for user_id=%s, broker=%s", user_id, broker)
166
+ response = self._put(
167
+ endpoint=self.urls["update_dealer_disclaimer"].format(broker),
168
+ url=self.base_url,
169
+ json={'disclaimer_accepted': disclaimer_accepted, 'user_id': user_id}
170
+ )
171
+ return response.get('data')
172
+
173
+ def dealer_users(self, broker: str, dealer_id: str) -> Optional[Dict[str, Any]]:
174
+ """
175
+ Get users associated with a specific dealer.
176
+
177
+ Args:
178
+ broker (str): Broker name.
179
+ dealer_id (str): Dealer identifier.
180
+
181
+ Returns:
182
+ Optional[Dict[str, Any]]: List of users or None if failed.
183
+ """
184
+ logger.info("Fetching dealer users for broker=%s, dealer_id=%s", broker, dealer_id)
185
+ response = self._post(
186
+ endpoint=self.urls["dealer_users"].format(broker),
187
+ url=self.base_url,
188
+ json={'dealer_id': dealer_id}
189
+ )
190
+ return response.get('data')
191
+
192
+ def user_disclaimer(self, broker: str, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
193
+ """
194
+ Fetch disclaimer details for a user under a specific broker.
195
+
196
+ Args:
197
+ broker (str): Broker name.
198
+ data (Dict[str, Any]): Payload for disclaimer lookup.
199
+
200
+ Returns:
201
+ Optional[Dict[str, Any]]: Disclaimer information if available.
202
+ """
203
+ logger.info("Fetching user disclaimer for broker=%s, data=%s", broker, data)
204
+ response = self._post(
205
+ endpoint=self.urls["user_disclaimer"].format(broker),
206
+ url=self.base_url,
207
+ json=data
208
+ )
209
+ return response.get('data')
210
+
211
+ def dealer_login(self, broker: str, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
212
+ """
213
+ Perform login for a dealer under the specified broker.
214
+
215
+ Args:
216
+ broker (str): Broker identifier.
217
+ data (Dict[str, Any]): Login payload.
218
+
219
+ Returns:
220
+ Optional[Dict[str, Any]]: Login response if successful.
221
+ """
222
+ logger.info("Dealer login request for broker=%s, data=%s", broker, data)
223
+ response = self._post(
224
+ endpoint=self.urls["dealer_login"].format(broker),
225
+ url=self.base_url,
226
+ json=data
227
+ )
228
+ return response.get('data')
229
+
230
+ def send_otp(self, broker: str, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
231
+ """
232
+ Send OTP to user for verification under a broker.
233
+
234
+ Args:
235
+ broker (str): Broker name.
236
+ data (Dict[str, Any]): Payload including mobile/email.
237
+
238
+ Returns:
239
+ Optional[Dict[str, Any]]: Response with OTP status.
240
+ """
241
+ logger.info("Sending OTP for broker=%s, data=%s", broker, data)
242
+ response = self._post(
243
+ endpoint=self.urls["send_otp"].format(broker),
244
+ url=self.base_url,
245
+ json=data
246
+ )
247
+ return response.get('data')
248
+
249
+ def verify_otp(self, broker: str, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
250
+ """
251
+ Verify user OTP under a broker.
252
+
253
+ Args:
254
+ broker (str): Broker name.
255
+ data (Dict[str, Any]): OTP verification data.
256
+
257
+ Returns:
258
+ Optional[Dict[str, Any]]: Verification status.
259
+ """
260
+ logger.info("Verifying OTP for broker=%s, data=%s", broker, data)
261
+ response = self._post(
262
+ endpoint=self.urls["verify_otp"].format(broker),
263
+ url=self.base_url,
264
+ json=data
265
+ )
266
+ return response.get('data')
267
+
268
+ def register_dealer_user(self, broker: str, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
269
+ """
270
+ Register a new dealer user.
271
+
272
+ Args:
273
+ broker (str): Broker name.
274
+ data (Dict[str, Any]): Dealer user details.
275
+
276
+ Returns:
277
+ Optional[Dict[str, Any]]: Registration status or dealer user details.
278
+ """
279
+ logger.info("Registering dealer user for broker=%s, data=%s", broker, data)
280
+ response = self._post(
281
+ endpoint=self.urls["register_dealer_user"].format(broker),
282
+ url=self.base_url,
283
+ json=data
284
+ )
285
+ return response.get('data')
286
+
287
+ def update_dealer_user(self, broker: str, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
288
+ """
289
+ Update an existing dealer user's information.
290
+
291
+ Args:
292
+ broker (str): Broker name.
293
+ data (Dict[str, Any]): Dealer user update payload.
294
+
295
+ Returns:
296
+ Optional[Dict[str, Any]]: Updated dealer user data.
297
+ """
298
+ logger.info("Updating dealer user for broker=%s, data=%s", broker, data)
299
+ response = self._put(
300
+ endpoint=self.urls["register_dealer_user"].format(broker),
301
+ url=self.base_url,
302
+ json=data
303
+ )
304
+ return response.get('data')
305
+
306
+ def sso(self, broker: str, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
307
+ """
308
+ Perform Single Sign-On (SSO) operation.
309
+
310
+ Args:
311
+ broker (str): Broker identifier.
312
+ data (Dict[str, Any]): SSO payload.
313
+
314
+ Returns:
315
+ Optional[Dict[str, Any]]: SSO token or user session.
316
+ """
317
+ logger.info("Performing SSO for broker=%s, data=%s", broker, data)
318
+ response = self._post(
319
+ endpoint=self.urls["sso"].format(broker),
320
+ url=self.base_url,
321
+ json=data
322
+ )
323
+ return response.get('data')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bw-essentials-core
3
- Version: 0.0.9
3
+ Version: 0.1.1
4
4
  Summary: Reusable utilities for S3, email, Data Loch, Microsoft Teams Notifications and more.
5
5
  Author: InvestorAI
6
6
  Author-email: support+tech@investorai.in
@@ -18,7 +18,9 @@ bw_essentials/services/broker.py
18
18
  bw_essentials/services/market_pricer.py
19
19
  bw_essentials/services/master_data.py
20
20
  bw_essentials/services/model_portfolio_reporting.py
21
+ bw_essentials/services/notification.py
21
22
  bw_essentials/services/trade_placement.py
23
+ bw_essentials/services/user_app.py
22
24
  bw_essentials/services/user_portfolio.py
23
25
  bw_essentials/services/user_portfolio_reporting.py
24
26
  bw_essentials_core.egg-info/PKG-INFO
@@ -10,7 +10,7 @@ from setuptools import setup, find_packages
10
10
 
11
11
  setup(
12
12
  name="bw-essentials-core",
13
- version="0.0.9",
13
+ version="0.1.1",
14
14
  author="InvestorAI",
15
15
  author_email="support+tech@investorai.in",
16
16
  description="Reusable utilities for S3, email, Data Loch, Microsoft Teams Notifications and more.",