magicfeedback 1.0.19__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.
- magicfeedback-1.0.19/LICENCE +19 -0
- magicfeedback-1.0.19/PKG-INFO +241 -0
- magicfeedback-1.0.19/README.md +218 -0
- magicfeedback-1.0.19/pyproject.toml +42 -0
- magicfeedback-1.0.19/setup.cfg +4 -0
- magicfeedback-1.0.19/setup.py +23 -0
- magicfeedback-1.0.19/src/deepdots_sdk/__init__.py +12 -0
- magicfeedback-1.0.19/src/deepdots_sdk/api/__init__.py +0 -0
- magicfeedback-1.0.19/src/deepdots_sdk/api/campaigns.py +5 -0
- magicfeedback-1.0.19/src/deepdots_sdk/api/companies.py +5 -0
- magicfeedback-1.0.19/src/deepdots_sdk/api/contacts.py +5 -0
- magicfeedback-1.0.19/src/deepdots_sdk/api/feedback.py +5 -0
- magicfeedback-1.0.19/src/deepdots_sdk/api/integrations_questions.py +5 -0
- magicfeedback-1.0.19/src/deepdots_sdk/api/metrics.py +5 -0
- magicfeedback-1.0.19/src/deepdots_sdk/api/products.py +5 -0
- magicfeedback-1.0.19/src/deepdots_sdk/api/reports.py +5 -0
- magicfeedback-1.0.19/src/deepdots_sdk/api/requests.py +5 -0
- magicfeedback-1.0.19/src/deepdots_sdk/api/signals.py +5 -0
- magicfeedback-1.0.19/src/deepdots_sdk/auth.py +5 -0
- magicfeedback-1.0.19/src/deepdots_sdk/client.py +5 -0
- magicfeedback-1.0.19/src/deepdots_sdk/logging_config.py +5 -0
- magicfeedback-1.0.19/src/deepdots_sdk/utils/__init__.py +0 -0
- magicfeedback-1.0.19/src/deepdots_sdk/utils/request.py +5 -0
- magicfeedback-1.0.19/src/magicfeedback.egg-info/PKG-INFO +241 -0
- magicfeedback-1.0.19/src/magicfeedback.egg-info/SOURCES.txt +52 -0
- magicfeedback-1.0.19/src/magicfeedback.egg-info/dependency_links.txt +1 -0
- magicfeedback-1.0.19/src/magicfeedback.egg-info/requires.txt +3 -0
- magicfeedback-1.0.19/src/magicfeedback.egg-info/top_level.txt +2 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/__init__.py +3 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/api/__init__.py +0 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/api/campaigns.py +47 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/api/companies.py +22 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/api/contacts.py +31 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/api/feedback.py +63 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/api/integrations_questions.py +15 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/api/metrics.py +15 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/api/products.py +15 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/api/reports.py +51 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/api/requests.py +94 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/api/signals.py +45 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/auth.py +217 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/client.py +117 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/logging_config.py +7 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/utils/__init__.py +0 -0
- magicfeedback-1.0.19/src/magicfeedback_sdk/utils/request.py +16 -0
- magicfeedback-1.0.19/tests/test_apikey.py +16 -0
- magicfeedback-1.0.19/tests/test_campaign.py +88 -0
- magicfeedback-1.0.19/tests/test_contact.py +59 -0
- magicfeedback-1.0.19/tests/test_datastore_token.py +200 -0
- magicfeedback-1.0.19/tests/test_deepdots_alias.py +62 -0
- magicfeedback-1.0.19/tests/test_feedback_answers_array.py +51 -0
- magicfeedback-1.0.19/tests/test_feedback_create.py +47 -0
- magicfeedback-1.0.19/tests/test_integrations_questions.py +28 -0
- magicfeedback-1.0.19/tests/test_request_done_message.py +60 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2024 MagicFeedback OÜ
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: magicfeedback
|
|
3
|
+
Version: 1.0.19
|
|
4
|
+
Summary: SDK for the Deepdots API (formerly MagicFeedback)
|
|
5
|
+
Home-page: https://github.com/MagicFeedback/magicfeedback_python_sdk
|
|
6
|
+
Author: Francisco Arias
|
|
7
|
+
Author-email: Francisco Arias <farias@magicfeedback.io>
|
|
8
|
+
Project-URL: Homepage, https://github.com/MagicFeedback/magicfeedback_python_sdk
|
|
9
|
+
Project-URL: Issues, https://github.com/MagicFeedback/magicfeedback_python_sdk/issues
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Requires-Python: >=3.8
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENCE
|
|
16
|
+
Requires-Dist: requests>=2.0.0
|
|
17
|
+
Requires-Dist: google-cloud-pubsub>=2.0.0
|
|
18
|
+
Requires-Dist: google-cloud-datastore>=2.16.0
|
|
19
|
+
Dynamic: author
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
Dynamic: requires-python
|
|
23
|
+
|
|
24
|
+
# Deepdots Python SDK
|
|
25
|
+
|
|
26
|
+
Python SDK for the Deepdots API (the company was formerly called MagicFeedback).
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install deepdots
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The original distribution is still published and still works:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install magicfeedback
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Naming
|
|
41
|
+
|
|
42
|
+
MagicFeedback was renamed **Deepdots**. Both sets of names work and refer to the
|
|
43
|
+
*same* objects, so **no existing code needs to change**:
|
|
44
|
+
|
|
45
|
+
| | Current name | Original name |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| PyPI distribution | `deepdots` | `magicfeedback` |
|
|
48
|
+
| Import package | `deepdots_sdk` | `magicfeedback_sdk` |
|
|
49
|
+
| Client class | `Deepdots` | `MagicFeedback` |
|
|
50
|
+
|
|
51
|
+
Distribution names are written lowercase throughout — that is the packaging
|
|
52
|
+
convention, and PyPI treats names case-insensitively anyway, so
|
|
53
|
+
`pip install MagicFeedback` keeps working for anyone who has it written that way.
|
|
54
|
+
|
|
55
|
+
`deepdots_sdk` re-exports `magicfeedback_sdk` module by module, and `Deepdots`
|
|
56
|
+
is the same class object as `MagicFeedback` — `MagicFeedback is Deepdots` is
|
|
57
|
+
`True`, so `isinstance()` checks and subclasses behave identically. Submodule
|
|
58
|
+
imports work under either name (`from deepdots_sdk.api.feedback import
|
|
59
|
+
FeedbackAPI`). New code should prefer the Deepdots names.
|
|
60
|
+
|
|
61
|
+
## Usage
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from deepdots_sdk import Deepdots
|
|
65
|
+
|
|
66
|
+
client = Deepdots("email", "password")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The original names remain fully supported:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from magicfeedback_sdk import MagicFeedback
|
|
73
|
+
|
|
74
|
+
client = MagicFeedback("email", "password")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Authentication
|
|
78
|
+
|
|
79
|
+
The bearer token is resolved from one of two sources, selected with
|
|
80
|
+
`auth_source`:
|
|
81
|
+
|
|
82
|
+
- `"datastore"` **(default)** — read the token cached in Google Cloud Datastore
|
|
83
|
+
by the `update-token` job (kind `token-storage`, email
|
|
84
|
+
`robot@magicfeedback.io`, database `shared`). This avoids an Identity Platform
|
|
85
|
+
login on every use. If the cached token is missing, stale (older than
|
|
86
|
+
`token_max_age_min`, default 50 min) or Datastore is unreachable, the client
|
|
87
|
+
falls back to Identity Platform using `email`/`password`.
|
|
88
|
+
- `"identity"` — always log in via Identity Platform (`signInWithPassword`), the
|
|
89
|
+
original behaviour, with no Datastore lookup.
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# Datastore-cached token (default), with Identity Platform fallback.
|
|
93
|
+
# email/password are only needed for the fallback.
|
|
94
|
+
client = MagicFeedback("email", "password")
|
|
95
|
+
|
|
96
|
+
# Tune the Datastore lookup (all optional; shown with their defaults):
|
|
97
|
+
client = MagicFeedback(
|
|
98
|
+
"email", "password",
|
|
99
|
+
auth_source="datastore",
|
|
100
|
+
gcp_project_id=None, # None => inferred from Application Default Credentials
|
|
101
|
+
datastore_database_id="shared",
|
|
102
|
+
token_kind="token-storage",
|
|
103
|
+
token_email="robot@magicfeedback.io",
|
|
104
|
+
token_max_age_min=50,
|
|
105
|
+
datastore_timeout_s=5.0, # cap the lookup so the fallback stays fast
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Original behaviour — always mint a fresh token via Identity Platform:
|
|
109
|
+
client = MagicFeedback("email", "password", auth_source="identity")
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The Datastore lookup is bounded by `datastore_timeout_s` (default 5s): if the
|
|
113
|
+
cache is unreachable or the credentials are stale, the client falls back to
|
|
114
|
+
Identity Platform within that budget instead of blocking on the Datastore
|
|
115
|
+
client's default ~60s retry deadline.
|
|
116
|
+
|
|
117
|
+
The Datastore path needs the `google-cloud-datastore` package (installed as a
|
|
118
|
+
dependency) and Google Application Default Credentials with read access to the
|
|
119
|
+
token entity (`gcloud auth application-default login` or
|
|
120
|
+
`GOOGLE_APPLICATION_CREDENTIALS`).
|
|
121
|
+
|
|
122
|
+
Helper methods:
|
|
123
|
+
|
|
124
|
+
- `client.refresh_token()` — re-resolve the token (same `auth_source`) and
|
|
125
|
+
update the auth header in place across all sub-API clients. Useful for
|
|
126
|
+
long-lived clients whose token has expired.
|
|
127
|
+
- `client.auth.get_token_from_datastore(allow_stale=False)` — read the cached
|
|
128
|
+
token directly; returns `None` when missing, stale or unreachable.
|
|
129
|
+
|
|
130
|
+
## API Reference
|
|
131
|
+
|
|
132
|
+
### `client.feedbacks`
|
|
133
|
+
- `create(feedback)` — creates a new feedback item. Required fields: `name`, `type`, `identity`, `integrationId`, `companyId`, `productId`.
|
|
134
|
+
- `get(filter=None)` — lists feedback items.
|
|
135
|
+
- `get_id(feedback_id, filter=None)` — retrieves a specific feedback item.
|
|
136
|
+
- `update(feedback_id, feedback)` — updates a feedback item.
|
|
137
|
+
- `delete(feedback_id)` — deletes a feedback item.
|
|
138
|
+
- `upload_attachment(feedback_id, file_path, filename=None, extra_data=None)` — uploads a file and attaches it to a feedback.
|
|
139
|
+
|
|
140
|
+
### `client.contacts`
|
|
141
|
+
- `create(contact)`, `get(filter=None)`, `update(contact_id, contact)`, `delete(contact_id)`
|
|
142
|
+
|
|
143
|
+
### `client.campaigns`
|
|
144
|
+
- `create(campaign)`, `get(filter=None)`
|
|
145
|
+
- `create_session(campaign_id, session)`, `get_sessions(campaign_id, filter=None)`, `get_sessions_feedbacks(campaign_id, filter=None)`
|
|
146
|
+
|
|
147
|
+
### `client.metrics`
|
|
148
|
+
- `get(filter=None)`
|
|
149
|
+
|
|
150
|
+
### `client.products`
|
|
151
|
+
- `get(filter=None)`
|
|
152
|
+
|
|
153
|
+
### `client.companies`
|
|
154
|
+
- `get(filter=None)`, `get_id(id, filter=None)`
|
|
155
|
+
|
|
156
|
+
### `client.integrations_questions`
|
|
157
|
+
- `get(integration_id, filter=None)`
|
|
158
|
+
|
|
159
|
+
### `client.reports`
|
|
160
|
+
- `get(filter=None)`, `get_newsletter(filter=None)`, `update(report_id, report)`
|
|
161
|
+
|
|
162
|
+
### `client.requests`
|
|
163
|
+
- `get(filter=None)`, `get_id(request_id, filter=None)`, `update(request_id, request)`
|
|
164
|
+
|
|
165
|
+
To mark a request DONE/ERROR asynchronously, publish a completion event to the
|
|
166
|
+
`request-done` Pub/Sub topic (project `magicfeedback-prod-api`, topic
|
|
167
|
+
`request-done`); the `request-done` Cloud Function consumes it and PATCHes the
|
|
168
|
+
request. The SDK does not publish this itself — build the envelope with
|
|
169
|
+
`build_done_message` and publish it directly. See
|
|
170
|
+
[`examples/mark_request_done.py`](examples/mark_request_done.py).
|
|
171
|
+
|
|
172
|
+
## Examples
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
# Create a feedback
|
|
176
|
+
client.feedbacks.create({
|
|
177
|
+
"name": "Test Feedback",
|
|
178
|
+
"type": "APP",
|
|
179
|
+
"identity": "MAGICFORM",
|
|
180
|
+
"integrationId": "your-integration-id",
|
|
181
|
+
"companyId": "YOUR_COMPANY",
|
|
182
|
+
"productId": "YOUR_PRODUCT",
|
|
183
|
+
"answers": [
|
|
184
|
+
{"key": "score", "value": "4"},
|
|
185
|
+
{"key": "comment", "value": "Great service!"},
|
|
186
|
+
],
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
# Get a feedback with its attachments
|
|
190
|
+
client.feedbacks.get_id(
|
|
191
|
+
"<feedback_id>",
|
|
192
|
+
filter={"include": [{"relation": "feedbackAttachments"}]}
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Upload a file attachment
|
|
196
|
+
client.feedbacks.upload_attachment(
|
|
197
|
+
"<feedback_id>",
|
|
198
|
+
file_path="/path/to/file.pdf",
|
|
199
|
+
filename="report.pdf", # optional, defaults to file name
|
|
200
|
+
extra_data={"source": "crm"} # optional, any JSON-serialisable dict
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# Mark a request DONE via the request-done Pub/Sub topic.
|
|
204
|
+
# The SDK builds the envelope; the producer publishes it directly.
|
|
205
|
+
import json
|
|
206
|
+
from google.cloud import pubsub_v1
|
|
207
|
+
from magicfeedback_sdk.api.requests import build_done_message
|
|
208
|
+
|
|
209
|
+
message = build_done_message(
|
|
210
|
+
"<request_id>",
|
|
211
|
+
"<company_id>",
|
|
212
|
+
output={"value": "…final result…"},
|
|
213
|
+
sources=["<feedbackId1>", "<feedbackId2>"], # optional
|
|
214
|
+
logs="processed 2 items", # optional
|
|
215
|
+
# success=False, error={"message": "processing failed"} # to mark ERROR
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
publisher = pubsub_v1.PublisherClient()
|
|
219
|
+
topic_path = publisher.topic_path("magicfeedback-prod-api", "request-done")
|
|
220
|
+
publisher.publish(topic_path, json.dumps(message).encode("utf-8")).result()
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Logging
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
import logging
|
|
227
|
+
client.set_logging(logging.DEBUG)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
MIT
|
|
233
|
+
|
|
234
|
+
## Contributing
|
|
235
|
+
|
|
236
|
+
Developing on the SDK itself — layout, tests, and how to cut a release — is
|
|
237
|
+
documented in [DEVELOPERS.md](DEVELOPERS.md).
|
|
238
|
+
|
|
239
|
+
## Contact
|
|
240
|
+
|
|
241
|
+
farias@magicfeedback.io
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Deepdots Python SDK
|
|
2
|
+
|
|
3
|
+
Python SDK for the Deepdots API (the company was formerly called MagicFeedback).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install deepdots
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The original distribution is still published and still works:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install magicfeedback
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Naming
|
|
18
|
+
|
|
19
|
+
MagicFeedback was renamed **Deepdots**. Both sets of names work and refer to the
|
|
20
|
+
*same* objects, so **no existing code needs to change**:
|
|
21
|
+
|
|
22
|
+
| | Current name | Original name |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| PyPI distribution | `deepdots` | `magicfeedback` |
|
|
25
|
+
| Import package | `deepdots_sdk` | `magicfeedback_sdk` |
|
|
26
|
+
| Client class | `Deepdots` | `MagicFeedback` |
|
|
27
|
+
|
|
28
|
+
Distribution names are written lowercase throughout — that is the packaging
|
|
29
|
+
convention, and PyPI treats names case-insensitively anyway, so
|
|
30
|
+
`pip install MagicFeedback` keeps working for anyone who has it written that way.
|
|
31
|
+
|
|
32
|
+
`deepdots_sdk` re-exports `magicfeedback_sdk` module by module, and `Deepdots`
|
|
33
|
+
is the same class object as `MagicFeedback` — `MagicFeedback is Deepdots` is
|
|
34
|
+
`True`, so `isinstance()` checks and subclasses behave identically. Submodule
|
|
35
|
+
imports work under either name (`from deepdots_sdk.api.feedback import
|
|
36
|
+
FeedbackAPI`). New code should prefer the Deepdots names.
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from deepdots_sdk import Deepdots
|
|
42
|
+
|
|
43
|
+
client = Deepdots("email", "password")
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The original names remain fully supported:
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from magicfeedback_sdk import MagicFeedback
|
|
50
|
+
|
|
51
|
+
client = MagicFeedback("email", "password")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Authentication
|
|
55
|
+
|
|
56
|
+
The bearer token is resolved from one of two sources, selected with
|
|
57
|
+
`auth_source`:
|
|
58
|
+
|
|
59
|
+
- `"datastore"` **(default)** — read the token cached in Google Cloud Datastore
|
|
60
|
+
by the `update-token` job (kind `token-storage`, email
|
|
61
|
+
`robot@magicfeedback.io`, database `shared`). This avoids an Identity Platform
|
|
62
|
+
login on every use. If the cached token is missing, stale (older than
|
|
63
|
+
`token_max_age_min`, default 50 min) or Datastore is unreachable, the client
|
|
64
|
+
falls back to Identity Platform using `email`/`password`.
|
|
65
|
+
- `"identity"` — always log in via Identity Platform (`signInWithPassword`), the
|
|
66
|
+
original behaviour, with no Datastore lookup.
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
# Datastore-cached token (default), with Identity Platform fallback.
|
|
70
|
+
# email/password are only needed for the fallback.
|
|
71
|
+
client = MagicFeedback("email", "password")
|
|
72
|
+
|
|
73
|
+
# Tune the Datastore lookup (all optional; shown with their defaults):
|
|
74
|
+
client = MagicFeedback(
|
|
75
|
+
"email", "password",
|
|
76
|
+
auth_source="datastore",
|
|
77
|
+
gcp_project_id=None, # None => inferred from Application Default Credentials
|
|
78
|
+
datastore_database_id="shared",
|
|
79
|
+
token_kind="token-storage",
|
|
80
|
+
token_email="robot@magicfeedback.io",
|
|
81
|
+
token_max_age_min=50,
|
|
82
|
+
datastore_timeout_s=5.0, # cap the lookup so the fallback stays fast
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Original behaviour — always mint a fresh token via Identity Platform:
|
|
86
|
+
client = MagicFeedback("email", "password", auth_source="identity")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The Datastore lookup is bounded by `datastore_timeout_s` (default 5s): if the
|
|
90
|
+
cache is unreachable or the credentials are stale, the client falls back to
|
|
91
|
+
Identity Platform within that budget instead of blocking on the Datastore
|
|
92
|
+
client's default ~60s retry deadline.
|
|
93
|
+
|
|
94
|
+
The Datastore path needs the `google-cloud-datastore` package (installed as a
|
|
95
|
+
dependency) and Google Application Default Credentials with read access to the
|
|
96
|
+
token entity (`gcloud auth application-default login` or
|
|
97
|
+
`GOOGLE_APPLICATION_CREDENTIALS`).
|
|
98
|
+
|
|
99
|
+
Helper methods:
|
|
100
|
+
|
|
101
|
+
- `client.refresh_token()` — re-resolve the token (same `auth_source`) and
|
|
102
|
+
update the auth header in place across all sub-API clients. Useful for
|
|
103
|
+
long-lived clients whose token has expired.
|
|
104
|
+
- `client.auth.get_token_from_datastore(allow_stale=False)` — read the cached
|
|
105
|
+
token directly; returns `None` when missing, stale or unreachable.
|
|
106
|
+
|
|
107
|
+
## API Reference
|
|
108
|
+
|
|
109
|
+
### `client.feedbacks`
|
|
110
|
+
- `create(feedback)` — creates a new feedback item. Required fields: `name`, `type`, `identity`, `integrationId`, `companyId`, `productId`.
|
|
111
|
+
- `get(filter=None)` — lists feedback items.
|
|
112
|
+
- `get_id(feedback_id, filter=None)` — retrieves a specific feedback item.
|
|
113
|
+
- `update(feedback_id, feedback)` — updates a feedback item.
|
|
114
|
+
- `delete(feedback_id)` — deletes a feedback item.
|
|
115
|
+
- `upload_attachment(feedback_id, file_path, filename=None, extra_data=None)` — uploads a file and attaches it to a feedback.
|
|
116
|
+
|
|
117
|
+
### `client.contacts`
|
|
118
|
+
- `create(contact)`, `get(filter=None)`, `update(contact_id, contact)`, `delete(contact_id)`
|
|
119
|
+
|
|
120
|
+
### `client.campaigns`
|
|
121
|
+
- `create(campaign)`, `get(filter=None)`
|
|
122
|
+
- `create_session(campaign_id, session)`, `get_sessions(campaign_id, filter=None)`, `get_sessions_feedbacks(campaign_id, filter=None)`
|
|
123
|
+
|
|
124
|
+
### `client.metrics`
|
|
125
|
+
- `get(filter=None)`
|
|
126
|
+
|
|
127
|
+
### `client.products`
|
|
128
|
+
- `get(filter=None)`
|
|
129
|
+
|
|
130
|
+
### `client.companies`
|
|
131
|
+
- `get(filter=None)`, `get_id(id, filter=None)`
|
|
132
|
+
|
|
133
|
+
### `client.integrations_questions`
|
|
134
|
+
- `get(integration_id, filter=None)`
|
|
135
|
+
|
|
136
|
+
### `client.reports`
|
|
137
|
+
- `get(filter=None)`, `get_newsletter(filter=None)`, `update(report_id, report)`
|
|
138
|
+
|
|
139
|
+
### `client.requests`
|
|
140
|
+
- `get(filter=None)`, `get_id(request_id, filter=None)`, `update(request_id, request)`
|
|
141
|
+
|
|
142
|
+
To mark a request DONE/ERROR asynchronously, publish a completion event to the
|
|
143
|
+
`request-done` Pub/Sub topic (project `magicfeedback-prod-api`, topic
|
|
144
|
+
`request-done`); the `request-done` Cloud Function consumes it and PATCHes the
|
|
145
|
+
request. The SDK does not publish this itself — build the envelope with
|
|
146
|
+
`build_done_message` and publish it directly. See
|
|
147
|
+
[`examples/mark_request_done.py`](examples/mark_request_done.py).
|
|
148
|
+
|
|
149
|
+
## Examples
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
# Create a feedback
|
|
153
|
+
client.feedbacks.create({
|
|
154
|
+
"name": "Test Feedback",
|
|
155
|
+
"type": "APP",
|
|
156
|
+
"identity": "MAGICFORM",
|
|
157
|
+
"integrationId": "your-integration-id",
|
|
158
|
+
"companyId": "YOUR_COMPANY",
|
|
159
|
+
"productId": "YOUR_PRODUCT",
|
|
160
|
+
"answers": [
|
|
161
|
+
{"key": "score", "value": "4"},
|
|
162
|
+
{"key": "comment", "value": "Great service!"},
|
|
163
|
+
],
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
# Get a feedback with its attachments
|
|
167
|
+
client.feedbacks.get_id(
|
|
168
|
+
"<feedback_id>",
|
|
169
|
+
filter={"include": [{"relation": "feedbackAttachments"}]}
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# Upload a file attachment
|
|
173
|
+
client.feedbacks.upload_attachment(
|
|
174
|
+
"<feedback_id>",
|
|
175
|
+
file_path="/path/to/file.pdf",
|
|
176
|
+
filename="report.pdf", # optional, defaults to file name
|
|
177
|
+
extra_data={"source": "crm"} # optional, any JSON-serialisable dict
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# Mark a request DONE via the request-done Pub/Sub topic.
|
|
181
|
+
# The SDK builds the envelope; the producer publishes it directly.
|
|
182
|
+
import json
|
|
183
|
+
from google.cloud import pubsub_v1
|
|
184
|
+
from magicfeedback_sdk.api.requests import build_done_message
|
|
185
|
+
|
|
186
|
+
message = build_done_message(
|
|
187
|
+
"<request_id>",
|
|
188
|
+
"<company_id>",
|
|
189
|
+
output={"value": "…final result…"},
|
|
190
|
+
sources=["<feedbackId1>", "<feedbackId2>"], # optional
|
|
191
|
+
logs="processed 2 items", # optional
|
|
192
|
+
# success=False, error={"message": "processing failed"} # to mark ERROR
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
publisher = pubsub_v1.PublisherClient()
|
|
196
|
+
topic_path = publisher.topic_path("magicfeedback-prod-api", "request-done")
|
|
197
|
+
publisher.publish(topic_path, json.dumps(message).encode("utf-8")).result()
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Logging
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
import logging
|
|
204
|
+
client.set_logging(logging.DEBUG)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## License
|
|
208
|
+
|
|
209
|
+
MIT
|
|
210
|
+
|
|
211
|
+
## Contributing
|
|
212
|
+
|
|
213
|
+
Developing on the SDK itself — layout, tests, and how to cut a release — is
|
|
214
|
+
documented in [DEVELOPERS.md](DEVELOPERS.md).
|
|
215
|
+
|
|
216
|
+
## Contact
|
|
217
|
+
|
|
218
|
+
farias@magicfeedback.io
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "magicfeedback"
|
|
3
|
+
version = "1.0.19"
|
|
4
|
+
authors = [
|
|
5
|
+
{ name="Francisco Arias", email="farias@magicfeedback.io" },
|
|
6
|
+
]
|
|
7
|
+
description = "SDK for the Deepdots API (formerly MagicFeedback)"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.8"
|
|
10
|
+
# Must be kept in sync with setup.py's install_requires. When this [project]
|
|
11
|
+
# table is present, setuptools uses it for metadata and IGNORES setup.py's
|
|
12
|
+
# install_requires, so dependencies declared only there never reach the built
|
|
13
|
+
# wheel (that was the case up to 1.0.16 — the published wheels had no
|
|
14
|
+
# Requires-Dist). google-cloud-datastore>=2.16.0 is required for the named
|
|
15
|
+
# `database=` kwarg the Datastore-first auth relies on.
|
|
16
|
+
dependencies = [
|
|
17
|
+
"requests>=2.0.0",
|
|
18
|
+
"google-cloud-pubsub>=2.0.0",
|
|
19
|
+
"google-cloud-datastore>=2.16.0",
|
|
20
|
+
]
|
|
21
|
+
classifiers = [
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Operating System :: OS Independent",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
# src-layout with TWO top-level packages: `magicfeedback_sdk` (the implementation)
|
|
28
|
+
# and `deepdots_sdk` (re-export mirror under the new company name). Declared
|
|
29
|
+
# explicitly so both are guaranteed to ship in the wheel rather than relying on
|
|
30
|
+
# setuptools auto-discovery.
|
|
31
|
+
[tool.setuptools.packages.find]
|
|
32
|
+
where = ["src"]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://github.com/MagicFeedback/magicfeedback_python_sdk"
|
|
36
|
+
Issues = "https://github.com/MagicFeedback/magicfeedback_python_sdk/issues"
|
|
37
|
+
|
|
38
|
+
[tool.pytest.ini_options]
|
|
39
|
+
# src-layout project: put src/ on sys.path so tests import the working tree
|
|
40
|
+
# (not a stale installed build) without requiring `pip install -e .`.
|
|
41
|
+
pythonpath = ["src"]
|
|
42
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from setuptools import find_packages, setup
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="magicfeedback_sdk",
|
|
5
|
+
version="1.0.19",
|
|
6
|
+
description="A Python SDK for interacting with the MagicFeedback API",
|
|
7
|
+
author="Francisco Arias",
|
|
8
|
+
author_email="farias@magicfeedback.io",
|
|
9
|
+
url="https://github.com/MagicFeedback/magicfeedback_python_sdk",
|
|
10
|
+
package_dir={"": "src"},
|
|
11
|
+
packages=find_packages(where="src"),
|
|
12
|
+
install_requires=[
|
|
13
|
+
"requests>=2.0.0",
|
|
14
|
+
"google-cloud-pubsub>=2.0.0",
|
|
15
|
+
"google-cloud-datastore>=2.16.0",
|
|
16
|
+
],
|
|
17
|
+
classifiers=[
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
],
|
|
22
|
+
python_requires=">=3.8",
|
|
23
|
+
)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Deepdots Python SDK.
|
|
2
|
+
|
|
3
|
+
``Deepdots`` is the current name of the company formerly called MagicFeedback.
|
|
4
|
+
This package is the forward-looking import name; the implementation still lives
|
|
5
|
+
in :mod:`magicfeedback_sdk` and is re-exported here module by module, so both
|
|
6
|
+
import paths expose the very same objects. Existing code importing
|
|
7
|
+
``magicfeedback_sdk`` keeps working unchanged.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from magicfeedback_sdk.client import Deepdots, MagicFeedback
|
|
11
|
+
|
|
12
|
+
__all__ = ["Deepdots", "MagicFeedback"]
|
|
File without changes
|
|
File without changes
|