vc-utils 2.1__tar.gz → 3.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.
- {vc_utils-2.1 → vc_utils-3.1}/PKG-INFO +1 -1
- {vc_utils-2.1 → vc_utils-3.1}/linkage/__init__.py +1 -0
- vc_utils-3.1/linkage/achievement.py +9 -0
- {vc_utils-2.1 → vc_utils-3.1}/linkage/session.py +85 -0
- {vc_utils-2.1 → vc_utils-3.1}/setup.py +1 -1
- {vc_utils-2.1 → vc_utils-3.1}/vc_utils.egg-info/PKG-INFO +1 -1
- {vc_utils-2.1 → vc_utils-3.1}/vc_utils.egg-info/SOURCES.txt +1 -0
- {vc_utils-2.1 → vc_utils-3.1}/README.md +0 -0
- {vc_utils-2.1 → vc_utils-3.1}/linkage/key_generator.py +0 -0
- {vc_utils-2.1 → vc_utils-3.1}/setup.cfg +0 -0
- {vc_utils-2.1 → vc_utils-3.1}/vc_utils.egg-info/dependency_links.txt +0 -0
- {vc_utils-2.1 → vc_utils-3.1}/vc_utils.egg-info/requires.txt +0 -0
- {vc_utils-2.1 → vc_utils-3.1}/vc_utils.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from pydantic import BaseModel
|
|
2
|
+
from typing import Any, List, Optional
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Achievement(BaseModel):
|
|
6
|
+
title: Optional[str] = None
|
|
7
|
+
description: Optional[str] = None
|
|
8
|
+
metadata: Any = None
|
|
9
|
+
files: Optional[List[str]] = None # paths to files to be uploaded
|
|
@@ -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"
|
|
@@ -126,7 +127,91 @@ class Linkage_Application:
|
|
|
126
127
|
error_data = await resp.json()
|
|
127
128
|
raise Exception(error_data)
|
|
128
129
|
return await resp.json()
|
|
130
|
+
|
|
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
|
+
if achievement.title is not None:
|
|
145
|
+
data.add_field("title", achievement.title)
|
|
146
|
+
if achievement.description is not None:
|
|
147
|
+
data.add_field("description", achievement.description)
|
|
148
|
+
if achievement.metadata is not None:
|
|
149
|
+
data.add_field("metadata", str(achievement.metadata))
|
|
150
|
+
if achievement.files:
|
|
151
|
+
for file_path in achievement.files:
|
|
152
|
+
f = open(file_path, "rb")
|
|
153
|
+
opened_files.append(f)
|
|
154
|
+
data.add_field("files", f, filename=os.path.basename(file_path))
|
|
155
|
+
resp = await self.linkage_post(session, uri, data=data)
|
|
156
|
+
if resp.status != 200:
|
|
157
|
+
error_data = await resp.json()
|
|
158
|
+
raise Exception(error_data)
|
|
159
|
+
except Exception as e:
|
|
160
|
+
raise e
|
|
161
|
+
finally:
|
|
162
|
+
for f in opened_files:
|
|
163
|
+
f.close()
|
|
164
|
+
|
|
165
|
+
return await resp.json()
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
async def batch_read_achievements(self, session, user_ids, app_ids, expiration=300):
|
|
169
|
+
"""
|
|
170
|
+
POST /achievements/batch
|
|
129
171
|
|
|
172
|
+
user_ids: List[str] = Body(..., embed=True),
|
|
173
|
+
app_ids: List[str] = Body(..., embed=True),
|
|
174
|
+
expiration: int = Query(300, description="Expiration time for signed URLs in seconds"),
|
|
175
|
+
|
|
176
|
+
"""
|
|
177
|
+
uri = f"{LINKAGE_M2M_HOST}/achievements/batch?expiration={expiration}"
|
|
178
|
+
payload = {
|
|
179
|
+
"user_ids": user_ids,
|
|
180
|
+
"app_ids": app_ids,
|
|
181
|
+
}
|
|
182
|
+
resp = await self.linkage_post(session, uri, json=payload)
|
|
183
|
+
if resp.status != 200:
|
|
184
|
+
error_data = await resp.json()
|
|
185
|
+
raise Exception(error_data)
|
|
186
|
+
|
|
187
|
+
# convert the response to a dict of user_id -> list of achievements
|
|
188
|
+
# data has this format: {user_id: {"s": status, "achievements": {"app_id": {"s": status, "data": {title, description, metadata, files}}}}}
|
|
189
|
+
data = await resp.json()
|
|
190
|
+
result = {}
|
|
191
|
+
for user_id, value in data.items():
|
|
192
|
+
if value.get("s") != "ok":
|
|
193
|
+
logging.warning(f"Failed to fetch achievements for user {user_id}, status: {value.get('s')}")
|
|
194
|
+
continue
|
|
195
|
+
|
|
196
|
+
achs = []
|
|
197
|
+
for app_id, ach_value in value.get("achievements", {}).items():
|
|
198
|
+
if app_id not in app_ids:
|
|
199
|
+
logging.warning(f"Received achievement data for unexpected app_id {app_id}, skipping")
|
|
200
|
+
continue
|
|
201
|
+
if ach_value.get("s") != "ok":
|
|
202
|
+
logging.warning(f"Failed to fetch achievement for user {user_id} and app {app_id}, status: {ach_value.get('s')}")
|
|
203
|
+
continue
|
|
204
|
+
ach_data = ach_value.get("data", {})
|
|
205
|
+
ach = Achievement(
|
|
206
|
+
title=ach_data.get("title", ""),
|
|
207
|
+
description=ach_data.get("description", ""),
|
|
208
|
+
metadata=ach_data.get("metadata", None),
|
|
209
|
+
files=[d['url_download'] for d in ach_data.get("download_links", [])]
|
|
210
|
+
)
|
|
211
|
+
achs.append(ach)
|
|
212
|
+
result[user_id] = achs
|
|
213
|
+
return result
|
|
214
|
+
|
|
130
215
|
|
|
131
216
|
async def get_user_data(token, spec_id=None):
|
|
132
217
|
if not token:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|