tetra-cli 0.2.0__py3-none-any.whl
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.
- tetra_cli/__init__.py +6 -0
- tetra_cli/api_client/__init__.py +10 -0
- tetra_cli/api_client/client.py +173 -0
- tetra_cli/api_client/config.py +125 -0
- tetra_cli/api_client/operations/__init__.py +9 -0
- tetra_cli/api_client/operations/accounts.py +303 -0
- tetra_cli/api_client/operations/ai.py +278 -0
- tetra_cli/api_client/operations/analysis.py +190 -0
- tetra_cli/api_client/operations/api_keys.py +145 -0
- tetra_cli/api_client/operations/archive.py +114 -0
- tetra_cli/api_client/operations/awards.py +123 -0
- tetra_cli/api_client/operations/capacity.py +84 -0
- tetra_cli/api_client/operations/conversations.py +447 -0
- tetra_cli/api_client/operations/conversations_2.py +262 -0
- tetra_cli/api_client/operations/cosmetics.py +148 -0
- tetra_cli/api_client/operations/dashboard.py +282 -0
- tetra_cli/api_client/operations/data.py +250 -0
- tetra_cli/api_client/operations/events.py +734 -0
- tetra_cli/api_client/operations/gamification.py +470 -0
- tetra_cli/api_client/operations/goals.py +1144 -0
- tetra_cli/api_client/operations/groups.py +647 -0
- tetra_cli/api_client/operations/issues.py +198 -0
- tetra_cli/api_client/operations/offset.py +61 -0
- tetra_cli/api_client/operations/onboarding.py +284 -0
- tetra_cli/api_client/operations/outcome_schemas.py +292 -0
- tetra_cli/api_client/operations/peer_connections.py +243 -0
- tetra_cli/api_client/operations/plaid.py +329 -0
- tetra_cli/api_client/operations/reminders.py +273 -0
- tetra_cli/api_client/operations/scratches.py +280 -0
- tetra_cli/api_client/operations/skill_trees.py +160 -0
- tetra_cli/api_client/operations/social_2.py +560 -0
- tetra_cli/api_client/operations/social_3.py +618 -0
- tetra_cli/api_client/operations/social_4.py +527 -0
- tetra_cli/api_client/operations/strava.py +215 -0
- tetra_cli/api_client/operations/stripe.py +113 -0
- tetra_cli/api_client/operations/tags.py +488 -0
- tetra_cli/api_client/operations/values.py +867 -0
- tetra_cli/api_client/operations/values_2.py +584 -0
- tetra_cli/api_client/operations/watch.py +105 -0
- tetra_cli/api_client/operations/webhooks.py +50 -0
- tetra_cli/api_client/operations/xp.py +27 -0
- tetra_cli/cli/__init__.py +5 -0
- tetra_cli/cli/__main__.py +5 -0
- tetra_cli/cli/app.py +86 -0
- tetra_cli/cli/commands/__init__.py +1 -0
- tetra_cli/cli/commands/auth.py +201 -0
- tetra_cli/cli/commands/guide.py +8 -0
- tetra_cli/cli/commands/messages.py +161 -0
- tetra_cli/cli/commands/skill.py +71 -0
- tetra_cli/cli/context.py +13 -0
- tetra_cli/cli/generate.py +282 -0
- tetra_cli/cli/output.py +58 -0
- tetra_cli/mcp_gen.py +137 -0
- tetra_cli/ontology.py +70 -0
- tetra_cli/registry.py +118 -0
- tetra_cli/skill/SKILL.md +69 -0
- tetra_cli/skill/__init__.py +1 -0
- tetra_cli-0.2.0.dist-info/METADATA +140 -0
- tetra_cli-0.2.0.dist-info/RECORD +62 -0
- tetra_cli-0.2.0.dist-info/WHEEL +5 -0
- tetra_cli-0.2.0.dist-info/entry_points.txt +2 -0
- tetra_cli-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
"""Pure async operations for the social API — group membership, ownership,
|
|
2
|
+
content links, and Arena cohort standings/joins.
|
|
3
|
+
|
|
4
|
+
This module wraps a slice of the ``/api/v1/social`` router covering:
|
|
5
|
+
|
|
6
|
+
* group ownership transfer + member removal / leave-for / accept / decline /
|
|
7
|
+
role + label changes,
|
|
8
|
+
* sub-group removal and group content (events listing, goal/value unlink),
|
|
9
|
+
* Arena cohort standings (Everyone + any group) and joins, plus the caller's
|
|
10
|
+
own skill-tree cohort participation.
|
|
11
|
+
|
|
12
|
+
Every op is a thin async wrapper over :class:`TetraClient`; optional body and
|
|
13
|
+
query fields that are ``None`` are omitted so the backend's own defaults apply.
|
|
14
|
+
"""
|
|
15
|
+
from typing import Any
|
|
16
|
+
from urllib.parse import urlencode
|
|
17
|
+
|
|
18
|
+
from tetra_cli.api_client import TetraClient
|
|
19
|
+
from tetra_cli.registry import arg, operation, opt
|
|
20
|
+
|
|
21
|
+
# All social routes are mounted under this prefix.
|
|
22
|
+
_BASE = "/api/v1/social"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# =============================================================================
|
|
26
|
+
# OWNERSHIP + MEMBERSHIP
|
|
27
|
+
# =============================================================================
|
|
28
|
+
|
|
29
|
+
@operation(
|
|
30
|
+
cli="social transfer-ownership",
|
|
31
|
+
summary="Transfer group ownership to another member.",
|
|
32
|
+
covers=[("POST", "/api/v1/social/groups/{uid}/transfer")],
|
|
33
|
+
params={
|
|
34
|
+
"uid": arg(help="Group UID whose ownership is being transferred"),
|
|
35
|
+
"new_owner_group_uid": opt(
|
|
36
|
+
"--new-owner",
|
|
37
|
+
help="Group UID of the new owner (a member of this group).",
|
|
38
|
+
),
|
|
39
|
+
},
|
|
40
|
+
)
|
|
41
|
+
async def transfer_group_ownership(
|
|
42
|
+
client: TetraClient,
|
|
43
|
+
*,
|
|
44
|
+
uid: str,
|
|
45
|
+
new_owner_group_uid: str,
|
|
46
|
+
) -> dict[str, Any]:
|
|
47
|
+
"""Transfer ownership of a group to another member.
|
|
48
|
+
|
|
49
|
+
The new owner is identified by their group UID (people are groups of
|
|
50
|
+
one). ``new_owner_group_uid`` is sent as a query parameter to mirror the
|
|
51
|
+
backend handler signature.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
client: Authenticated TetraClient
|
|
55
|
+
uid: Group UID whose ownership is being transferred
|
|
56
|
+
new_owner_group_uid: Group UID of the new owner
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
The new owner's membership record.
|
|
60
|
+
"""
|
|
61
|
+
query = urlencode({"new_owner_group_uid": new_owner_group_uid})
|
|
62
|
+
return await client.post(f"{_BASE}/groups/{uid}/transfer?{query}")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@operation(
|
|
66
|
+
cli="social remove-member",
|
|
67
|
+
summary="Remove (kick) a member from a group.",
|
|
68
|
+
covers=[("DELETE", "/api/v1/social/groups/{uid}/members/{member_uid}")],
|
|
69
|
+
params={
|
|
70
|
+
"uid": arg(help="Group UID"),
|
|
71
|
+
"member_uid": arg(help="Member's group UID to remove"),
|
|
72
|
+
},
|
|
73
|
+
)
|
|
74
|
+
async def remove_group_member(
|
|
75
|
+
client: TetraClient, uid: str, member_uid: str,
|
|
76
|
+
) -> dict[str, Any]:
|
|
77
|
+
"""Remove a member from a group (kick).
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
client: Authenticated TetraClient
|
|
81
|
+
uid: Group UID
|
|
82
|
+
member_uid: Group UID of the member to remove
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Deletion confirmation dict (the endpoint returns 204).
|
|
86
|
+
"""
|
|
87
|
+
return await client.delete(f"{_BASE}/groups/{uid}/members/{member_uid}")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@operation(
|
|
91
|
+
cli="social leave-for",
|
|
92
|
+
summary="Remove an owned group from another group.",
|
|
93
|
+
covers=[("POST", "/api/v1/social/groups/{uid}/leave/{member_uid}")],
|
|
94
|
+
params={
|
|
95
|
+
"uid": arg(help="Group UID to leave"),
|
|
96
|
+
"member_uid": arg(help="Owned group UID being withdrawn from the group"),
|
|
97
|
+
},
|
|
98
|
+
)
|
|
99
|
+
async def leave_group_for(
|
|
100
|
+
client: TetraClient, uid: str, member_uid: str,
|
|
101
|
+
) -> dict[str, Any]:
|
|
102
|
+
"""Withdraw an owned group from another group's membership.
|
|
103
|
+
|
|
104
|
+
The caller must own ``member_uid``. The membership is fully deleted.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
client: Authenticated TetraClient
|
|
108
|
+
uid: Group UID to leave
|
|
109
|
+
member_uid: Group UID (owned by the caller) being withdrawn
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Status dict ``{"status": "left"}``.
|
|
113
|
+
"""
|
|
114
|
+
return await client.post(f"{_BASE}/groups/{uid}/leave/{member_uid}", json=None)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@operation(
|
|
118
|
+
cli="social accept-member",
|
|
119
|
+
summary="Accept an invite or approve a join request for a member.",
|
|
120
|
+
covers=[("POST", "/api/v1/social/groups/{uid}/members/{member_uid}/accept")],
|
|
121
|
+
params={
|
|
122
|
+
"uid": arg(help="Group UID"),
|
|
123
|
+
"member_uid": arg(help="Member's group UID (own UID to accept own invite)"),
|
|
124
|
+
"requested_label": opt(
|
|
125
|
+
"--requested-label", choices=["mentor", "mentee", "coop"],
|
|
126
|
+
help="Optionally request a different label on accept.",
|
|
127
|
+
),
|
|
128
|
+
},
|
|
129
|
+
)
|
|
130
|
+
async def accept_group_member(
|
|
131
|
+
client: TetraClient,
|
|
132
|
+
uid: str,
|
|
133
|
+
member_uid: str,
|
|
134
|
+
*,
|
|
135
|
+
requested_label: str | None = None,
|
|
136
|
+
) -> dict[str, Any]:
|
|
137
|
+
"""Accept an invitation (invitee) or approve a join request (admin).
|
|
138
|
+
|
|
139
|
+
Pass ``requested_label`` to request a different label than the one
|
|
140
|
+
assigned; downgrades auto-accept while upgrades await owner approval.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
client: Authenticated TetraClient
|
|
144
|
+
uid: Group UID
|
|
145
|
+
member_uid: Member's group UID. Use the caller's own personal-group
|
|
146
|
+
UID to accept their own invitation.
|
|
147
|
+
requested_label: Optional requested label (mentor/mentee/coop).
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
The resulting membership record.
|
|
151
|
+
"""
|
|
152
|
+
body: dict[str, Any] | None = None
|
|
153
|
+
if requested_label is not None:
|
|
154
|
+
body = {"requested_label": requested_label}
|
|
155
|
+
return await client.post(
|
|
156
|
+
f"{_BASE}/groups/{uid}/members/{member_uid}/accept", json=body,
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@operation(
|
|
161
|
+
cli="social decline-member",
|
|
162
|
+
summary="Decline an invite or deny a join request for a member.",
|
|
163
|
+
covers=[("POST", "/api/v1/social/groups/{uid}/members/{member_uid}/decline")],
|
|
164
|
+
params={
|
|
165
|
+
"uid": arg(help="Group UID"),
|
|
166
|
+
"member_uid": arg(help="Member's group UID (own UID to decline own invite)"),
|
|
167
|
+
},
|
|
168
|
+
)
|
|
169
|
+
async def decline_group_member(
|
|
170
|
+
client: TetraClient, uid: str, member_uid: str,
|
|
171
|
+
) -> dict[str, Any]:
|
|
172
|
+
"""Decline an invitation (invitee) or deny a join request (admin).
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
client: Authenticated TetraClient
|
|
176
|
+
uid: Group UID
|
|
177
|
+
member_uid: Member's group UID
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
Deletion confirmation dict (the endpoint returns 204).
|
|
181
|
+
"""
|
|
182
|
+
return await client.post(
|
|
183
|
+
f"{_BASE}/groups/{uid}/members/{member_uid}/decline", json=None,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@operation(
|
|
188
|
+
cli="social member-label",
|
|
189
|
+
summary="Change a member's role label (mentor/mentee/coop).",
|
|
190
|
+
covers=[("PUT", "/api/v1/social/groups/{uid}/members/{member_uid}/label")],
|
|
191
|
+
params={
|
|
192
|
+
"uid": arg(help="Group UID"),
|
|
193
|
+
"member_uid": arg(help="Member's group UID"),
|
|
194
|
+
"label": opt(
|
|
195
|
+
"--label", choices=["mentor", "mentee", "coop"],
|
|
196
|
+
help="New role label.",
|
|
197
|
+
),
|
|
198
|
+
},
|
|
199
|
+
)
|
|
200
|
+
async def update_member_label(
|
|
201
|
+
client: TetraClient,
|
|
202
|
+
uid: str,
|
|
203
|
+
member_uid: str,
|
|
204
|
+
*,
|
|
205
|
+
label: str,
|
|
206
|
+
) -> dict[str, Any]:
|
|
207
|
+
"""Change a member's role label (mentor/mentee/coop).
|
|
208
|
+
|
|
209
|
+
Only the group owner may change labels; changing power dynamics triggers
|
|
210
|
+
a consent reset. ``label`` is sent as a query parameter to mirror the
|
|
211
|
+
backend handler signature.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
client: Authenticated TetraClient
|
|
215
|
+
uid: Group UID
|
|
216
|
+
member_uid: Member's group UID
|
|
217
|
+
label: New label — one of mentor/mentee/coop
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
The updated membership record.
|
|
221
|
+
"""
|
|
222
|
+
query = urlencode({"label": label})
|
|
223
|
+
return await client.put(
|
|
224
|
+
f"{_BASE}/groups/{uid}/members/{member_uid}/label?{query}",
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
@operation(
|
|
229
|
+
cli="social member-role",
|
|
230
|
+
summary="Change a member's role (owner/admin/member).",
|
|
231
|
+
covers=[("PUT", "/api/v1/social/groups/{uid}/members/{member_uid}/role")],
|
|
232
|
+
params={
|
|
233
|
+
"uid": arg(help="Group UID"),
|
|
234
|
+
"member_uid": arg(help="Member's group UID"),
|
|
235
|
+
"role": opt(
|
|
236
|
+
"--role", choices=["owner", "admin", "member"],
|
|
237
|
+
help="New role.",
|
|
238
|
+
),
|
|
239
|
+
},
|
|
240
|
+
)
|
|
241
|
+
async def update_member_role(
|
|
242
|
+
client: TetraClient,
|
|
243
|
+
uid: str,
|
|
244
|
+
member_uid: str,
|
|
245
|
+
*,
|
|
246
|
+
role: str,
|
|
247
|
+
) -> dict[str, Any]:
|
|
248
|
+
"""Change a member's role (owner/admin/member).
|
|
249
|
+
|
|
250
|
+
``role`` is sent as a query parameter to mirror the backend handler
|
|
251
|
+
signature. Promoting to owner and demoting are handled server-side.
|
|
252
|
+
|
|
253
|
+
Args:
|
|
254
|
+
client: Authenticated TetraClient
|
|
255
|
+
uid: Group UID
|
|
256
|
+
member_uid: Member's group UID
|
|
257
|
+
role: New role — one of owner/admin/member
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
The updated membership record.
|
|
261
|
+
"""
|
|
262
|
+
query = urlencode({"role": role})
|
|
263
|
+
return await client.put(
|
|
264
|
+
f"{_BASE}/groups/{uid}/members/{member_uid}/role?{query}",
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
@operation(
|
|
269
|
+
cli="social remove-sub-group",
|
|
270
|
+
summary="Remove a sub-group from a composite group.",
|
|
271
|
+
covers=[("DELETE", "/api/v1/social/groups/{uid}/sub-groups/{sub_uid}")],
|
|
272
|
+
params={
|
|
273
|
+
"uid": arg(help="Composite group UID"),
|
|
274
|
+
"sub_uid": arg(help="Sub-group UID to remove"),
|
|
275
|
+
},
|
|
276
|
+
)
|
|
277
|
+
async def remove_sub_group(
|
|
278
|
+
client: TetraClient, uid: str, sub_uid: str,
|
|
279
|
+
) -> dict[str, Any]:
|
|
280
|
+
"""Remove a sub-group from a composite group.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
client: Authenticated TetraClient
|
|
284
|
+
uid: Composite group UID
|
|
285
|
+
sub_uid: Sub-group UID to remove
|
|
286
|
+
|
|
287
|
+
Returns:
|
|
288
|
+
Deletion confirmation dict (the endpoint returns 204).
|
|
289
|
+
"""
|
|
290
|
+
return await client.delete(f"{_BASE}/groups/{uid}/sub-groups/{sub_uid}")
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
# =============================================================================
|
|
294
|
+
# GROUP CONTENT
|
|
295
|
+
# =============================================================================
|
|
296
|
+
|
|
297
|
+
@operation(
|
|
298
|
+
cli="social group-events",
|
|
299
|
+
summary="List events from group members' mapped goals and values.",
|
|
300
|
+
covers=[("GET", "/api/v1/social/groups/{uid}/content/events")],
|
|
301
|
+
params={
|
|
302
|
+
"uid": arg(help="Group UID"),
|
|
303
|
+
"member_uid": opt("--member-uid", help="Filter by member account UID."),
|
|
304
|
+
"goal": opt("--goal", help="Filter by group goal name."),
|
|
305
|
+
"value": opt("--value", help="Filter by group value name."),
|
|
306
|
+
"start_date": opt("--start-date", help="On or after (YYYY-MM-DD)."),
|
|
307
|
+
"end_date": opt("--end-date", help="On or before (YYYY-MM-DD)."),
|
|
308
|
+
"limit": opt("--limit", min=1, max=200, help="Pagination limit (1-200)."),
|
|
309
|
+
"offset": opt("--offset", min=0, help="Pagination offset."),
|
|
310
|
+
},
|
|
311
|
+
)
|
|
312
|
+
async def list_group_member_events(
|
|
313
|
+
client: TetraClient,
|
|
314
|
+
uid: str,
|
|
315
|
+
*,
|
|
316
|
+
member_uid: str | None = None,
|
|
317
|
+
goal: str | None = None,
|
|
318
|
+
value: str | None = None,
|
|
319
|
+
start_date: str | None = None,
|
|
320
|
+
end_date: str | None = None,
|
|
321
|
+
limit: int | None = None,
|
|
322
|
+
offset: int | None = None,
|
|
323
|
+
) -> dict[str, Any]:
|
|
324
|
+
"""List events from group members' mapped goals and values.
|
|
325
|
+
|
|
326
|
+
Returns events with member attribution and group goal/value context.
|
|
327
|
+
Any active member can view; blind groups return an empty result. All
|
|
328
|
+
filters are optional query parameters; ``None`` values are dropped by the
|
|
329
|
+
client so the backend defaults (limit=50, offset=0) apply.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
client: Authenticated TetraClient
|
|
333
|
+
uid: Group UID
|
|
334
|
+
member_uid: Filter by member account UID
|
|
335
|
+
goal: Filter by group goal name
|
|
336
|
+
value: Filter by group value name
|
|
337
|
+
start_date: Inclusive lower bound (YYYY-MM-DD)
|
|
338
|
+
end_date: Inclusive upper bound (YYYY-MM-DD)
|
|
339
|
+
limit: Pagination limit (1-200)
|
|
340
|
+
offset: Pagination offset (>=0)
|
|
341
|
+
|
|
342
|
+
Returns:
|
|
343
|
+
Dict with ``events``, ``total``, and ``members``.
|
|
344
|
+
"""
|
|
345
|
+
params: dict[str, Any] = {
|
|
346
|
+
"member_uid": member_uid,
|
|
347
|
+
"goal": goal,
|
|
348
|
+
"value": value,
|
|
349
|
+
"start_date": start_date,
|
|
350
|
+
"end_date": end_date,
|
|
351
|
+
"limit": limit,
|
|
352
|
+
"offset": offset,
|
|
353
|
+
}
|
|
354
|
+
return await client.get(f"{_BASE}/groups/{uid}/content/events", params=params)
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
@operation(
|
|
358
|
+
cli="social unlink-goal",
|
|
359
|
+
summary="Unlink a personal goal from a group goal.",
|
|
360
|
+
covers=[("DELETE", "/api/v1/social/groups/{uid}/content/goals/{goal_uid}/link")],
|
|
361
|
+
params={
|
|
362
|
+
"uid": arg(help="Group UID"),
|
|
363
|
+
"goal_uid": arg(help="Group goal UID to unlink"),
|
|
364
|
+
},
|
|
365
|
+
)
|
|
366
|
+
async def unlink_group_goal(
|
|
367
|
+
client: TetraClient, uid: str, goal_uid: str,
|
|
368
|
+
) -> dict[str, Any]:
|
|
369
|
+
"""Remove the link between a personal goal and a group goal.
|
|
370
|
+
|
|
371
|
+
Args:
|
|
372
|
+
client: Authenticated TetraClient
|
|
373
|
+
uid: Group UID
|
|
374
|
+
goal_uid: Group goal UID to unlink
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
Deletion confirmation dict (the endpoint returns 204).
|
|
378
|
+
"""
|
|
379
|
+
return await client.delete(
|
|
380
|
+
f"{_BASE}/groups/{uid}/content/goals/{goal_uid}/link",
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
@operation(
|
|
385
|
+
cli="social unlink-value",
|
|
386
|
+
summary="Unlink a personal value from a group value.",
|
|
387
|
+
covers=[("DELETE", "/api/v1/social/groups/{uid}/content/values/{val_uid}/link")],
|
|
388
|
+
params={
|
|
389
|
+
"uid": arg(help="Group UID"),
|
|
390
|
+
"val_uid": arg(help="Group value UID to unlink"),
|
|
391
|
+
},
|
|
392
|
+
)
|
|
393
|
+
async def unlink_group_value(
|
|
394
|
+
client: TetraClient, uid: str, val_uid: str,
|
|
395
|
+
) -> dict[str, Any]:
|
|
396
|
+
"""Remove the link between a personal value and a group value.
|
|
397
|
+
|
|
398
|
+
Args:
|
|
399
|
+
client: Authenticated TetraClient
|
|
400
|
+
uid: Group UID
|
|
401
|
+
val_uid: Group value UID to unlink
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
Deletion confirmation dict (the endpoint returns 204).
|
|
405
|
+
"""
|
|
406
|
+
return await client.delete(
|
|
407
|
+
f"{_BASE}/groups/{uid}/content/values/{val_uid}/link",
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
# =============================================================================
|
|
412
|
+
# ARENA — EVERYONE COHORTS
|
|
413
|
+
# =============================================================================
|
|
414
|
+
|
|
415
|
+
@operation(
|
|
416
|
+
cli="social everyone-tree-standings",
|
|
417
|
+
summary="Leaderboard + viewer standing for an Everyone skill-tree cohort.",
|
|
418
|
+
covers=[(
|
|
419
|
+
"GET",
|
|
420
|
+
"/api/v1/social/groups/everyone/skill-trees/{cohort_value_uid}/standings",
|
|
421
|
+
)],
|
|
422
|
+
params={"cohort_value_uid": arg(help="Cohort value (skill tree) UID")},
|
|
423
|
+
)
|
|
424
|
+
async def everyone_tree_standings(
|
|
425
|
+
client: TetraClient, cohort_value_uid: str,
|
|
426
|
+
) -> dict[str, Any]:
|
|
427
|
+
"""Top-50 leaderboard plus the viewer's standing for one Everyone skill tree.
|
|
428
|
+
|
|
429
|
+
The viewer's row is always included even when outside the top 50; an empty
|
|
430
|
+
cohort returns an empty leaderboard and a viewer with ``rank=None``.
|
|
431
|
+
|
|
432
|
+
Args:
|
|
433
|
+
client: Authenticated TetraClient
|
|
434
|
+
cohort_value_uid: Cohort value (skill tree) UID
|
|
435
|
+
|
|
436
|
+
Returns:
|
|
437
|
+
Standings dict (leaderboard + viewer).
|
|
438
|
+
"""
|
|
439
|
+
return await client.get(
|
|
440
|
+
f"{_BASE}/groups/everyone/skill-trees/{cohort_value_uid}/standings",
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
@operation(
|
|
445
|
+
cli="social everyone-goal-standings",
|
|
446
|
+
summary="Leaderboard + viewer standing for an Everyone goal cohort.",
|
|
447
|
+
covers=[(
|
|
448
|
+
"GET",
|
|
449
|
+
"/api/v1/social/groups/everyone/goals/{cohort_goal_uid}/standings",
|
|
450
|
+
)],
|
|
451
|
+
params={"cohort_goal_uid": arg(help="Cohort goal UID")},
|
|
452
|
+
)
|
|
453
|
+
async def everyone_goal_standings(
|
|
454
|
+
client: TetraClient, cohort_goal_uid: str,
|
|
455
|
+
) -> dict[str, Any]:
|
|
456
|
+
"""Top-50 leaderboard plus the viewer's standing for one Everyone goal cohort.
|
|
457
|
+
|
|
458
|
+
Members are ranked by their best single-event score descending.
|
|
459
|
+
|
|
460
|
+
Args:
|
|
461
|
+
client: Authenticated TetraClient
|
|
462
|
+
cohort_goal_uid: Cohort goal UID
|
|
463
|
+
|
|
464
|
+
Returns:
|
|
465
|
+
Standings dict (leaderboard + viewer).
|
|
466
|
+
"""
|
|
467
|
+
return await client.get(
|
|
468
|
+
f"{_BASE}/groups/everyone/goals/{cohort_goal_uid}/standings",
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
@operation(
|
|
473
|
+
cli="social everyone-join-tree",
|
|
474
|
+
summary="Adopt a published skill tree and join its Everyone cohort.",
|
|
475
|
+
covers=[(
|
|
476
|
+
"POST",
|
|
477
|
+
"/api/v1/social/groups/everyone/skill-trees/{cohort_value_uid}/join",
|
|
478
|
+
)],
|
|
479
|
+
params={"cohort_value_uid": arg(help="Cohort value (skill tree) UID")},
|
|
480
|
+
)
|
|
481
|
+
async def everyone_join_tree(
|
|
482
|
+
client: TetraClient, cohort_value_uid: str,
|
|
483
|
+
) -> dict[str, Any]:
|
|
484
|
+
"""Adopt a published skill tree and join its Everyone cohort.
|
|
485
|
+
|
|
486
|
+
Idempotent: when already a member, returns the current standing without
|
|
487
|
+
re-adopting.
|
|
488
|
+
|
|
489
|
+
Args:
|
|
490
|
+
client: Authenticated TetraClient
|
|
491
|
+
cohort_value_uid: Cohort value (skill tree) UID
|
|
492
|
+
|
|
493
|
+
Returns:
|
|
494
|
+
The viewer's standing in the joined cohort.
|
|
495
|
+
"""
|
|
496
|
+
return await client.post(
|
|
497
|
+
f"{_BASE}/groups/everyone/skill-trees/{cohort_value_uid}/join", json=None,
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
@operation(
|
|
502
|
+
cli="social everyone-join-goal",
|
|
503
|
+
summary="Adopt a public goal and join its Everyone cohort.",
|
|
504
|
+
covers=[("POST", "/api/v1/social/groups/everyone/goals/{cohort_goal_uid}/join")],
|
|
505
|
+
params={"cohort_goal_uid": arg(help="Cohort goal UID")},
|
|
506
|
+
)
|
|
507
|
+
async def everyone_join_goal(
|
|
508
|
+
client: TetraClient, cohort_goal_uid: str,
|
|
509
|
+
) -> dict[str, Any]:
|
|
510
|
+
"""Adopt a public goal and join its Everyone cohort.
|
|
511
|
+
|
|
512
|
+
Idempotent via the backend's "Already linked" guard.
|
|
513
|
+
|
|
514
|
+
Args:
|
|
515
|
+
client: Authenticated TetraClient
|
|
516
|
+
cohort_goal_uid: Cohort goal UID
|
|
517
|
+
|
|
518
|
+
Returns:
|
|
519
|
+
The viewer's standing in the joined cohort.
|
|
520
|
+
"""
|
|
521
|
+
return await client.post(
|
|
522
|
+
f"{_BASE}/groups/everyone/goals/{cohort_goal_uid}/join", json=None,
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
@operation(
|
|
527
|
+
cli="social my-tree-cohorts",
|
|
528
|
+
summary="List the cohorts the caller's personal skill tree participates in.",
|
|
529
|
+
covers=[("GET", "/api/v1/social/skill-trees/mine/{source_value_uid}/cohorts")],
|
|
530
|
+
params={"source_value_uid": arg(help="Root value UID of the caller's tree")},
|
|
531
|
+
)
|
|
532
|
+
async def my_tree_cohorts(
|
|
533
|
+
client: TetraClient, source_value_uid: str,
|
|
534
|
+
) -> dict[str, Any]:
|
|
535
|
+
"""List every cohort the caller's personal tree participates in.
|
|
536
|
+
|
|
537
|
+
Walks the caller's own ValueLinks from ``source_value_uid`` and reports
|
|
538
|
+
their standing (rank, size, percentile, tier, is_god) in each linked
|
|
539
|
+
cohort. Account-scoped to the caller.
|
|
540
|
+
|
|
541
|
+
Args:
|
|
542
|
+
client: Authenticated TetraClient
|
|
543
|
+
source_value_uid: Root value UID of the caller's skill tree
|
|
544
|
+
|
|
545
|
+
Returns:
|
|
546
|
+
Dict with a ``cohorts`` list.
|
|
547
|
+
"""
|
|
548
|
+
return await client.get(
|
|
549
|
+
f"{_BASE}/skill-trees/mine/{source_value_uid}/cohorts",
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
# =============================================================================
|
|
554
|
+
# ARENA — GROUP-SCOPED COHORTS
|
|
555
|
+
# =============================================================================
|
|
556
|
+
|
|
557
|
+
@operation(
|
|
558
|
+
cli="social group-tree-standings",
|
|
559
|
+
summary="Leaderboard + viewer standing for a skill-tree cohort in a group.",
|
|
560
|
+
covers=[(
|
|
561
|
+
"GET",
|
|
562
|
+
"/api/v1/social/groups/{group_uid}/arena/skill-trees/{cohort_value_uid}/standings",
|
|
563
|
+
)],
|
|
564
|
+
params={
|
|
565
|
+
"group_uid": arg(help="Group UID"),
|
|
566
|
+
"cohort_value_uid": arg(help="Cohort value (skill tree) UID"),
|
|
567
|
+
},
|
|
568
|
+
)
|
|
569
|
+
async def group_tree_standings(
|
|
570
|
+
client: TetraClient, group_uid: str, cohort_value_uid: str,
|
|
571
|
+
) -> dict[str, Any]:
|
|
572
|
+
"""Top-50 leaderboard plus the viewer's standing for one skill tree in a group.
|
|
573
|
+
|
|
574
|
+
Requires the viewer to be a member of the group.
|
|
575
|
+
|
|
576
|
+
Args:
|
|
577
|
+
client: Authenticated TetraClient
|
|
578
|
+
group_uid: Group UID
|
|
579
|
+
cohort_value_uid: Cohort value (skill tree) UID
|
|
580
|
+
|
|
581
|
+
Returns:
|
|
582
|
+
Standings dict (leaderboard + viewer).
|
|
583
|
+
"""
|
|
584
|
+
return await client.get(
|
|
585
|
+
f"{_BASE}/groups/{group_uid}/arena/skill-trees/{cohort_value_uid}/standings",
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
@operation(
|
|
590
|
+
cli="social group-goal-standings",
|
|
591
|
+
summary="Leaderboard + viewer standing for a goal cohort in a group.",
|
|
592
|
+
covers=[(
|
|
593
|
+
"GET",
|
|
594
|
+
"/api/v1/social/groups/{group_uid}/arena/goals/{cohort_goal_uid}/standings",
|
|
595
|
+
)],
|
|
596
|
+
params={
|
|
597
|
+
"group_uid": arg(help="Group UID"),
|
|
598
|
+
"cohort_goal_uid": arg(help="Cohort goal UID"),
|
|
599
|
+
},
|
|
600
|
+
)
|
|
601
|
+
async def group_goal_standings(
|
|
602
|
+
client: TetraClient, group_uid: str, cohort_goal_uid: str,
|
|
603
|
+
) -> dict[str, Any]:
|
|
604
|
+
"""Top-50 leaderboard plus the viewer's standing for one goal cohort in a group.
|
|
605
|
+
|
|
606
|
+
Requires the viewer to be a member of the group.
|
|
607
|
+
|
|
608
|
+
Args:
|
|
609
|
+
client: Authenticated TetraClient
|
|
610
|
+
group_uid: Group UID
|
|
611
|
+
cohort_goal_uid: Cohort goal UID
|
|
612
|
+
|
|
613
|
+
Returns:
|
|
614
|
+
Standings dict (leaderboard + viewer).
|
|
615
|
+
"""
|
|
616
|
+
return await client.get(
|
|
617
|
+
f"{_BASE}/groups/{group_uid}/arena/goals/{cohort_goal_uid}/standings",
|
|
618
|
+
)
|