MagicFeedback 0.0.4__tar.gz → 0.0.7__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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: MagicFeedback
3
- Version: 0.0.4
3
+ Version: 0.0.7
4
4
  Summary: SDK for MagicFeedback API
5
5
  Author-email: Francisco Arias <farias@magicfedback.io>
6
6
  Project-URL: Homepage, https://github.com/MagicFeedback/magicfeedback_python_sdk
@@ -11,6 +11,7 @@ Classifier: Operating System :: OS Independent
11
11
  Requires-Python: >=3.8
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENCE
14
+ Dynamic: license-file
14
15
 
15
16
  # MagicFeedback SDK
16
17
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "MagicFeedback"
3
- version = "0.0.4"
3
+ version = "0.0.7"
4
4
  authors = [
5
5
  { name="Francisco Arias", email="farias@magicfedback.io" },
6
6
  ]
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: MagicFeedback
3
- Version: 0.0.4
3
+ Version: 0.0.7
4
4
  Summary: SDK for MagicFeedback API
5
5
  Author-email: Francisco Arias <farias@magicfedback.io>
6
6
  Project-URL: Homepage, https://github.com/MagicFeedback/magicfeedback_python_sdk
@@ -11,6 +11,7 @@ Classifier: Operating System :: OS Independent
11
11
  Requires-Python: >=3.8
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENCE
14
+ Dynamic: license-file
14
15
 
15
16
  # MagicFeedback SDK
16
17
 
@@ -10,4 +10,5 @@ src/MagicFeedback.egg-info/top_level.txt
10
10
  tests/test_apikey.py
11
11
  tests/test_campaign.py
12
12
  tests/test_contact.py
13
+ tests/test_feedback_answers_array.py
13
14
  tests/test_feedback_create.py
@@ -1,4 +1,5 @@
1
1
  import json
2
+ import logging
2
3
  from typing import Any, Dict
3
4
 
4
5
  import requests
@@ -9,13 +10,33 @@ class MagicFeedbackClient:
9
10
 
10
11
  def __init__(self, user: str, password: str, base_url: str = "https://api.magicfeedback.io", ip_key: str = 'AIzaSyAKcR895VURSQZSN2T_RD6jX_9y5HRmH80'):
11
12
 
13
+ self.logger = logging.getLogger("magicfeedback_sdk")
14
+ self.logger.addHandler(logging.NullHandler())
15
+
12
16
  self.base_url = base_url
13
17
  self.ip_key = ip_key
14
18
 
15
19
  self.api_key = self.get_api_key(user, password)
16
- print("API Key: ", self.api_key)
20
+ self.logger.info("API Key: %s", self.api_key)
17
21
  self.headers = {"Authorization": f"Bearer {self.api_key}"}
18
22
 
23
+ def logging(self, level: int):
24
+ """Sets the logging level for the SDK.
25
+
26
+ Args:
27
+ level (int): The logging level to set (e.g., logging.DEBUG, logging.INFO).
28
+ """
29
+ self.logger.setLevel(level)
30
+
31
+ # Evita agregar múltiples handlers si ya se configuró
32
+ if not any(isinstance(h, logging.StreamHandler) for h in self.logger.handlers):
33
+ handler = logging.StreamHandler()
34
+ handler.setLevel(level)
35
+ formatter = logging.Formatter(
36
+ "%(asctime)s - %(levelname)s - %(message)s")
37
+ handler.setFormatter(formatter)
38
+ self.logger.addHandler(handler)
39
+
19
40
  def get_api_key(self, user, password):
20
41
  """Obtains the API key using user and password authentication."""
21
42
  # TODO: Implement control to check if the token is still valid - Only for 1 hour
@@ -33,9 +54,8 @@ class MagicFeedbackClient:
33
54
  str: The obtained ID token.
34
55
  """
35
56
  # TODO: Control in case the call is not good
36
- print("Logging in with user and password...")
37
- print("User: ", user)
38
- print("Password: ", password)
57
+ self.logger.info("Logging in with user and password...")
58
+ self.logger.info("User: %s", user)
39
59
 
40
60
  options = {
41
61
  "method": "POST",
@@ -64,12 +84,12 @@ class MagicFeedbackClient:
64
84
  method, url, headers=self.headers, json=json)
65
85
  response.raise_for_status() # Raise exception for non-2xx status codes
66
86
  # TODO: Control the status of the call
67
- print("Status code: ", response.status_code)
87
+ self.logger.debug("Status code: %s", response.status_code)
68
88
  # Control if exist response that can be converted in json
69
89
  if response.text:
70
- print("Response: ", response.json())
90
+ self.logger.debug("Response: %s", response.json())
71
91
  return response.json()
72
-
92
+
73
93
  return {}
74
94
 
75
95
  ####################################################################################
@@ -97,6 +117,13 @@ class MagicFeedbackClient:
97
117
  if field not in feedback:
98
118
  raise ValueError(f"Missing required field: {field}")
99
119
 
120
+ # Ensure answers.values are wrapped in a list if not already
121
+ if "answers" in feedback and isinstance(feedback["answers"], list):
122
+ for answer in feedback["answers"]:
123
+ if "value" in answer and not isinstance(answer["value"], list):
124
+ # Wrap the value in a list if it is not already
125
+ answer["value"] = [answer["value"]]
126
+
100
127
  return self._make_request("POST", url, json=feedback)
101
128
 
102
129
  def get_feedback(self, feedback_id: str) -> Dict[str, Any]:
@@ -173,7 +200,7 @@ class MagicFeedbackClient:
173
200
  url = f"{url}?filter={json.dumps(filter)}"
174
201
 
175
202
  return self._make_request("GET", url)
176
-
203
+
177
204
  def update_contact(self, contact_id: str, contact: Dict[str, Any]) -> Dict[str, Any]:
178
205
  """Updates a specific contact item.
179
206
 
@@ -186,7 +213,7 @@ class MagicFeedbackClient:
186
213
  """
187
214
  url = f"{self.base_url}/crm/contacts/{contact_id}"
188
215
  return self._make_request("PATCH", url, json=contact)
189
-
216
+
190
217
  def delete_contact(self, contact_id: str) -> None:
191
218
  """Deletes a specific contact item.
192
219
 
@@ -220,7 +247,7 @@ class MagicFeedbackClient:
220
247
  raise ValueError(f"Missing required field: {field}")
221
248
 
222
249
  return self._make_request("POST", url, json=campaign)
223
-
250
+
224
251
  def get_campaigns(self, filter) -> Dict[str, Any]:
225
252
  """Retrieves a specific campaign item.
226
253
 
@@ -236,7 +263,7 @@ class MagicFeedbackClient:
236
263
  url = f"{url}?filter={json.dumps(filter)}"
237
264
 
238
265
  return self._make_request("GET", url)
239
-
266
+
240
267
  def create_campaign_session(self, campaign_id: str, session: Dict[str, Any]) -> Dict[str, Any]:
241
268
  """Creates a new campaign session item.
242
269
 
@@ -256,12 +283,12 @@ class MagicFeedbackClient:
256
283
  for field in required_fields:
257
284
  if field not in session:
258
285
  raise ValueError(f"Missing required field: {field}")
259
-
286
+
260
287
  if len(session.get("crmContactId")) == 0:
261
288
  raise ValueError("Contact ID cannot be empty.")
262
289
 
263
290
  return self._make_request("POST", url, json=session)
264
-
291
+
265
292
  def get_campaign_sessions(self, campaign_id: str, filter) -> Dict[str, Any]:
266
293
  """Retrieves a specific campaign session item.
267
294
 
@@ -272,8 +299,25 @@ class MagicFeedbackClient:
272
299
  Returns:
273
300
  Dict[str, Any]: The retrieved campaign session item.
274
301
  """
275
- url = f"{self.base_url}/campaigns/{campaign_id}/sessions"
302
+ url = f"{self.base_url}/campaigns/{campaign_id}/session"
276
303
  if filter:
277
304
  url = f"{url}?filter={json.dumps(filter)}"
278
305
 
279
- return self._make_request("GET", url)
306
+ return self._make_request("GET", url)
307
+
308
+ ####################################################################################
309
+ # Metrics API Methods #
310
+ ####################################################################################
311
+
312
+ def get_metrics(self, filter) -> Dict[str, Any]:
313
+ """Retrieves metrics data.
314
+ Args:
315
+ filter (Dict[str, Any]): The filter to apply to the metrics.
316
+ Returns:
317
+ Dict[str, Any]: The retrieved metrics data.
318
+ """
319
+ url = f"{self.base_url}/metrics"
320
+ if filter:
321
+ url = f"{url}?filter={json.dumps(filter)}"
322
+
323
+ return self._make_request("GET", url)
@@ -0,0 +1,49 @@
1
+ import pytest
2
+ from src.magicfeedback import MagicFeedbackClient
3
+
4
+ def test_create_feedback_with_answer_wrapping(client):
5
+ """Tests creating a new feedback item and ensures answers.value is wrapped in a list if not already."""
6
+
7
+ feedback_data = {
8
+ "name": "Test SDK Feedback",
9
+ "type": "APP",
10
+ "identity": "MAGICFORM",
11
+ "answers": [
12
+ {"key": "name", "value": "John Doe"}, # Single value (should be wrapped)
13
+ {"key": "comment", "value": ["This is a test comment."]} # Already a list
14
+ ],
15
+ "questions": [
16
+ {
17
+ "title": "Name",
18
+ "ref": "name",
19
+ "position": 1,
20
+ "type": "TEXT"
21
+ },
22
+ {
23
+ "title": "Comment",
24
+ "ref": "comment",
25
+ "position": 2,
26
+ "type": "LONGTEXT"
27
+ },
28
+ ],
29
+ "integrationId": "0eb9d270-6dd7-11ef-9987-21e04f383573",
30
+ "companyId": "MAGICFEEDBACK_DEV_SDK",
31
+ "productId": "MAGICFEEDBACK_DEV_SDK_GENERAL",
32
+ }
33
+
34
+ response = client.create_feedback(feedback_data)
35
+
36
+ assert "id" in response
37
+ # Check if the created feedback has the correct name
38
+ assert response["name"] == "Test SDK Feedback"
39
+
40
+ # Validate answers are properly wrapped
41
+ for answer in feedback_data["answers"]:
42
+ assert isinstance(answer["value"], list), f"Answer value for key '{answer['key']}' is not a list."
43
+
44
+ @pytest.fixture
45
+ def client():
46
+ """Provides a MagicFeedbackClient instance for testing."""
47
+
48
+ client = MagicFeedbackClient('sdk_tester@magicfeedback.io', 'caracter')
49
+ return client
File without changes
File without changes
File without changes