vc-utils 2.0__tar.gz → 3.0__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.
- {vc_utils-2.0 → vc_utils-3.0}/PKG-INFO +4 -3
- {vc_utils-2.0 → vc_utils-3.0}/README.md +3 -2
- {vc_utils-2.0 → vc_utils-3.0}/linkage/__init__.py +1 -0
- vc_utils-3.0/linkage/achievement.py +9 -0
- {vc_utils-2.0 → vc_utils-3.0}/linkage/session.py +101 -6
- {vc_utils-2.0 → vc_utils-3.0}/setup.py +1 -1
- {vc_utils-2.0 → vc_utils-3.0}/vc_utils.egg-info/PKG-INFO +4 -3
- {vc_utils-2.0 → vc_utils-3.0}/vc_utils.egg-info/SOURCES.txt +1 -0
- {vc_utils-2.0 → vc_utils-3.0}/linkage/key_generator.py +0 -0
- {vc_utils-2.0 → vc_utils-3.0}/setup.cfg +0 -0
- {vc_utils-2.0 → vc_utils-3.0}/vc_utils.egg-info/dependency_links.txt +0 -0
- {vc_utils-2.0 → vc_utils-3.0}/vc_utils.egg-info/requires.txt +0 -0
- {vc_utils-2.0 → vc_utils-3.0}/vc_utils.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vc-utils
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0
|
|
4
4
|
Summary: Vulcan Coalition Python Utility Library
|
|
5
5
|
Home-page: https://github.com/vulcan-coalition/vulcan-utils
|
|
6
6
|
Author: Chatavut Viriyasuthee
|
|
@@ -35,7 +35,7 @@ Vulcan python utility
|
|
|
35
35
|
## Installation
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
pip install
|
|
38
|
+
pip install vc-utils
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
## Usage
|
|
@@ -48,12 +48,13 @@ export LINKAGE_CLIENT_ID="test-client-id"
|
|
|
48
48
|
export LINKAGE_CLIENT_SECRET="test-client-secret"
|
|
49
49
|
|
|
50
50
|
export LINKAGE_M2M_HOST="https://application-linkage.vulcanproduct.com"
|
|
51
|
+
export LINKAGE_U2M_HOST="https://account-linkage.vulcanproduct.com"
|
|
51
52
|
```
|
|
52
53
|
|
|
53
54
|
Then you can import and use the Linkage API in your code:
|
|
54
55
|
|
|
55
56
|
```python
|
|
56
|
-
|
|
57
|
+
import linkage
|
|
57
58
|
```
|
|
58
59
|
|
|
59
60
|
## Test
|
|
@@ -11,7 +11,7 @@ Vulcan python utility
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
pip install
|
|
14
|
+
pip install vc-utils
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## Usage
|
|
@@ -24,12 +24,13 @@ export LINKAGE_CLIENT_ID="test-client-id"
|
|
|
24
24
|
export LINKAGE_CLIENT_SECRET="test-client-secret"
|
|
25
25
|
|
|
26
26
|
export LINKAGE_M2M_HOST="https://application-linkage.vulcanproduct.com"
|
|
27
|
+
export LINKAGE_U2M_HOST="https://account-linkage.vulcanproduct.com"
|
|
27
28
|
```
|
|
28
29
|
|
|
29
30
|
Then you can import and use the Linkage API in your code:
|
|
30
31
|
|
|
31
32
|
```python
|
|
32
|
-
|
|
33
|
+
import linkage
|
|
33
34
|
```
|
|
34
35
|
|
|
35
36
|
## Test
|
|
@@ -3,6 +3,7 @@ import logging
|
|
|
3
3
|
from . import key_generator
|
|
4
4
|
import aiohttp
|
|
5
5
|
from urllib.parse import urlencode
|
|
6
|
+
from .achievement import Achievement
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
AUTHORIZE_ENDPOINT = "/authorize"
|
|
@@ -14,6 +15,7 @@ CLIENT_ID = None
|
|
|
14
15
|
CLIENT_SECRET = None
|
|
15
16
|
|
|
16
17
|
LINKAGE_M2M_HOST = None
|
|
18
|
+
LINKAGE_U2M_HOST = None
|
|
17
19
|
|
|
18
20
|
async def init():
|
|
19
21
|
LINKAGE_OPENID_CONF_PATH = os.getenv("LINKAGE_OPENID_CONF_PATH", None)
|
|
@@ -46,6 +48,11 @@ async def init():
|
|
|
46
48
|
if not LINKAGE_M2M_HOST:
|
|
47
49
|
raise Exception("LINKAGE_M2M_HOST environment variable must be set")
|
|
48
50
|
|
|
51
|
+
global LINKAGE_U2M_HOST
|
|
52
|
+
LINKAGE_U2M_HOST = os.getenv("LINKAGE_U2M_HOST", None)
|
|
53
|
+
if not LINKAGE_U2M_HOST:
|
|
54
|
+
raise Exception("LINKAGE_U2M_HOST environment variable must be set")
|
|
55
|
+
|
|
49
56
|
|
|
50
57
|
async def application_get_token():
|
|
51
58
|
# use separate session to avoid token refresh logic in Linkage_Application_Session
|
|
@@ -120,10 +127,91 @@ class Linkage_Application:
|
|
|
120
127
|
error_data = await resp.json()
|
|
121
128
|
raise Exception(error_data)
|
|
122
129
|
return await resp.json()
|
|
130
|
+
|
|
123
131
|
|
|
132
|
+
async def update_achievement(self, session, user_id, achievement):
|
|
133
|
+
"""
|
|
134
|
+
POST /achievements/user/{user_id}
|
|
135
|
+
title: str = Form(...),
|
|
136
|
+
description: str = Form(...),
|
|
137
|
+
metadata: Any = Form(None),
|
|
138
|
+
files: List[UploadFile] = File([]),
|
|
139
|
+
"""
|
|
140
|
+
uri = f"{LINKAGE_M2M_HOST}/achievements/user/{user_id}"
|
|
141
|
+
opened_files = []
|
|
142
|
+
try:
|
|
143
|
+
data = aiohttp.FormData()
|
|
144
|
+
data.add_field("title", achievement.title)
|
|
145
|
+
data.add_field("description", achievement.description)
|
|
146
|
+
if achievement.metadata is not None:
|
|
147
|
+
data.add_field("metadata", str(achievement.metadata))
|
|
148
|
+
if achievement.files:
|
|
149
|
+
for file_path in achievement.files:
|
|
150
|
+
f = open(file_path, "rb")
|
|
151
|
+
opened_files.append(f)
|
|
152
|
+
data.add_field("files", f, filename=os.path.basename(file_path))
|
|
153
|
+
resp = await self.linkage_post(session, uri, data=data)
|
|
154
|
+
if resp.status != 200:
|
|
155
|
+
error_data = await resp.json()
|
|
156
|
+
raise Exception(error_data)
|
|
157
|
+
except Exception as e:
|
|
158
|
+
raise e
|
|
159
|
+
finally:
|
|
160
|
+
for f in opened_files:
|
|
161
|
+
f.close()
|
|
162
|
+
|
|
163
|
+
return await resp.json()
|
|
164
|
+
|
|
124
165
|
|
|
166
|
+
async def batch_read_achievements(self, session, user_ids, app_ids, expiration=300):
|
|
167
|
+
"""
|
|
168
|
+
POST /achievements/batch
|
|
125
169
|
|
|
126
|
-
|
|
170
|
+
user_ids: List[str] = Body(..., embed=True),
|
|
171
|
+
app_ids: List[str] = Body(..., embed=True),
|
|
172
|
+
expiration: int = Query(300, description="Expiration time for signed URLs in seconds"),
|
|
173
|
+
|
|
174
|
+
"""
|
|
175
|
+
uri = f"{LINKAGE_M2M_HOST}/achievements/batch?expiration={expiration}"
|
|
176
|
+
payload = {
|
|
177
|
+
"user_ids": user_ids,
|
|
178
|
+
"app_ids": app_ids,
|
|
179
|
+
}
|
|
180
|
+
resp = await self.linkage_post(session, uri, json=payload)
|
|
181
|
+
if resp.status != 200:
|
|
182
|
+
error_data = await resp.json()
|
|
183
|
+
raise Exception(error_data)
|
|
184
|
+
|
|
185
|
+
# convert the response to a dict of user_id -> list of achievements
|
|
186
|
+
# data has this format: {user_id: {"s": status, "achievements": {"app_id": {"s": status, "data": {title, description, metadata, files}}}}}
|
|
187
|
+
data = await resp.json()
|
|
188
|
+
result = {}
|
|
189
|
+
for user_id, value in data.items():
|
|
190
|
+
if value.get("s") != "ok":
|
|
191
|
+
logging.warning(f"Failed to fetch achievements for user {user_id}, status: {value.get('s')}")
|
|
192
|
+
continue
|
|
193
|
+
|
|
194
|
+
achs = []
|
|
195
|
+
for app_id, ach_value in value.get("achievements", {}).items():
|
|
196
|
+
if app_id not in app_ids:
|
|
197
|
+
logging.warning(f"Received achievement data for unexpected app_id {app_id}, skipping")
|
|
198
|
+
continue
|
|
199
|
+
if ach_value.get("s") != "ok":
|
|
200
|
+
logging.warning(f"Failed to fetch achievement for user {user_id} and app {app_id}, status: {ach_value.get('s')}")
|
|
201
|
+
continue
|
|
202
|
+
ach_data = ach_value.get("data", {})
|
|
203
|
+
ach = Achievement(
|
|
204
|
+
title=ach_data.get("title", ""),
|
|
205
|
+
description=ach_data.get("description", ""),
|
|
206
|
+
metadata=ach_data.get("metadata", None),
|
|
207
|
+
files=[d['url_download'] for d in ach_data.get("download_links", [])]
|
|
208
|
+
)
|
|
209
|
+
achs.append(ach)
|
|
210
|
+
result[user_id] = achs
|
|
211
|
+
return result
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
async def get_user_data(token, spec_id=None):
|
|
127
215
|
if not token:
|
|
128
216
|
return None
|
|
129
217
|
|
|
@@ -131,11 +219,18 @@ async def get_user_data(token):
|
|
|
131
219
|
"Authorization": f"Bearer {token}"
|
|
132
220
|
}
|
|
133
221
|
async with aiohttp.ClientSession() as session:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
222
|
+
if spec_id is not None:
|
|
223
|
+
async with session.get(f"{LINKAGE_U2M_HOST}/data/{spec_id}", headers=headers) as resp:
|
|
224
|
+
if resp.status != 200:
|
|
225
|
+
error_data = await resp.json()
|
|
226
|
+
raise Exception(error_data)
|
|
227
|
+
return await resp.json()
|
|
228
|
+
else:
|
|
229
|
+
async with session.get(USERINFO_ENDPOINT, headers=headers) as resp:
|
|
230
|
+
if resp.status != 200:
|
|
231
|
+
error_data = await resp.json()
|
|
232
|
+
raise Exception(error_data)
|
|
233
|
+
return await resp.json()
|
|
139
234
|
|
|
140
235
|
|
|
141
236
|
def get_authn_req_url(scope, redirect_uri):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vc-utils
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0
|
|
4
4
|
Summary: Vulcan Coalition Python Utility Library
|
|
5
5
|
Home-page: https://github.com/vulcan-coalition/vulcan-utils
|
|
6
6
|
Author: Chatavut Viriyasuthee
|
|
@@ -35,7 +35,7 @@ Vulcan python utility
|
|
|
35
35
|
## Installation
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
pip install
|
|
38
|
+
pip install vc-utils
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
## Usage
|
|
@@ -48,12 +48,13 @@ export LINKAGE_CLIENT_ID="test-client-id"
|
|
|
48
48
|
export LINKAGE_CLIENT_SECRET="test-client-secret"
|
|
49
49
|
|
|
50
50
|
export LINKAGE_M2M_HOST="https://application-linkage.vulcanproduct.com"
|
|
51
|
+
export LINKAGE_U2M_HOST="https://account-linkage.vulcanproduct.com"
|
|
51
52
|
```
|
|
52
53
|
|
|
53
54
|
Then you can import and use the Linkage API in your code:
|
|
54
55
|
|
|
55
56
|
```python
|
|
56
|
-
|
|
57
|
+
import linkage
|
|
57
58
|
```
|
|
58
59
|
|
|
59
60
|
## Test
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|