valentina-python-client 1.19.0__tar.gz → 1.20.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.
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/PKG-INFO +1 -1
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/pyproject.toml +1 -1
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/__init__.py +1 -1
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/campaign_book_chapters.py +28 -6
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/campaign_books.py +16 -7
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/users.py +54 -15
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/constants.py +5 -1
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/__init__.py +6 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/books.py +23 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/chapters.py +19 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/characters.py +2 -6
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/companies.py +3 -1
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/users.py +30 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/campaign_book_chapters.py +29 -6
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/campaign_books.py +19 -7
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/users.py +53 -11
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/testing/__init__.py +6 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/testing/_factories.py +22 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/testing/_router.py +9 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/testing/_routes.py +6 -3
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/validate_constants.py +1 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/LICENSE +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/README.md +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_codegen.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/__init__.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/client.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/registry.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/__init__.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/base.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/campaigns.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/character_autogen.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/character_blueprint.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/character_traits.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/characters.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/companies.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/developers.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/dicerolls.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/dictionary.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/global_admin.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/options.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/services/system.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/testing/__init__.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/_sync/testing/_client.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/client.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/config.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/endpoints.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/exceptions.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/campaigns.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/character_autogen.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/character_blueprint.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/character_trait.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/developers.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/diceroll.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/dictionary.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/full_sheet.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/global_admin.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/pagination.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/shared.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/system.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/py.typed +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/registry.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/__init__.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/base.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/campaigns.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/character_autogen.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/character_blueprint.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/character_traits.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/characters.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/companies.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/developers.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/dicerolls.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/dictionary.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/global_admin.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/options.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/services/system.py +0 -0
- {valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/testing/_client.py +0 -0
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
"""Service for interacting with the Campaign Books Chapters API."""
|
|
3
3
|
|
|
4
4
|
import mimetypes
|
|
5
|
-
from collections.abc import Iterator
|
|
5
|
+
from collections.abc import Iterator, Sequence
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
8
|
from vclient._sync.services.base import SyncBaseService
|
|
9
|
-
from vclient.constants import DEFAULT_PAGE_LIMIT
|
|
9
|
+
from vclient.constants import DEFAULT_PAGE_LIMIT, ChapterInclude
|
|
10
10
|
from vclient.endpoints import Endpoints
|
|
11
11
|
from vclient.models import (
|
|
12
12
|
Asset,
|
|
13
13
|
CampaignChapter,
|
|
14
|
+
CampaignChapterDetail,
|
|
14
15
|
ChapterCreate,
|
|
15
16
|
ChapterUpdate,
|
|
16
17
|
Note,
|
|
@@ -69,10 +70,31 @@ class SyncChaptersService(SyncBaseService):
|
|
|
69
70
|
):
|
|
70
71
|
yield CampaignChapter.model_validate(item)
|
|
71
72
|
|
|
72
|
-
def get(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
def get(
|
|
74
|
+
self, chapter_id: str, *, include: Sequence[ChapterInclude] | None = None
|
|
75
|
+
) -> CampaignChapterDetail:
|
|
76
|
+
"""Retrieve detailed information about a specific campaign book chapter.
|
|
77
|
+
|
|
78
|
+
Fetches the chapter and optionally embeds child resources directly in the
|
|
79
|
+
response, avoiding follow-up requests.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
chapter_id: The ID of the chapter to retrieve.
|
|
83
|
+
include: Child resources to embed in the response. Valid values are
|
|
84
|
+
``"notes"`` and ``"assets"``.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
The CampaignChapterDetail object with full details and any requested embeds.
|
|
88
|
+
|
|
89
|
+
Raises:
|
|
90
|
+
NotFoundError: If the chapter does not exist.
|
|
91
|
+
AuthorizationError: If you don't have access.
|
|
92
|
+
"""
|
|
93
|
+
response = self._get(
|
|
94
|
+
self._format_endpoint(Endpoints.BOOK_CHAPTER, chapter_id=chapter_id),
|
|
95
|
+
params=self._build_params(include=list(include) if include else None),
|
|
96
|
+
)
|
|
97
|
+
return CampaignChapterDetail.model_validate(response.json())
|
|
76
98
|
|
|
77
99
|
def create(self, request: ChapterCreate | None = None, **kwargs) -> CampaignChapter:
|
|
78
100
|
"""Create a new campaign book chapter.
|
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
"""Service for interacting with the Campaign Books API."""
|
|
3
3
|
|
|
4
4
|
import mimetypes
|
|
5
|
-
from collections.abc import Iterator
|
|
5
|
+
from collections.abc import Iterator, Sequence
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
8
|
from vclient._sync.services.base import SyncBaseService
|
|
9
|
-
from vclient.constants import DEFAULT_PAGE_LIMIT
|
|
9
|
+
from vclient.constants import DEFAULT_PAGE_LIMIT, BookInclude
|
|
10
10
|
from vclient.endpoints import Endpoints
|
|
11
11
|
from vclient.models import (
|
|
12
12
|
Asset,
|
|
13
13
|
BookCreate,
|
|
14
14
|
BookUpdate,
|
|
15
15
|
CampaignBook,
|
|
16
|
+
CampaignBookDetail,
|
|
16
17
|
Note,
|
|
17
18
|
NoteCreate,
|
|
18
19
|
NoteUpdate,
|
|
@@ -116,23 +117,31 @@ class SyncBooksService(SyncBaseService):
|
|
|
116
117
|
):
|
|
117
118
|
yield CampaignBook.model_validate(item)
|
|
118
119
|
|
|
119
|
-
def get(
|
|
120
|
+
def get(
|
|
121
|
+
self, book_id: str, *, include: Sequence[BookInclude] | None = None
|
|
122
|
+
) -> CampaignBookDetail:
|
|
120
123
|
"""Retrieve detailed information about a specific campaign book.
|
|
121
124
|
|
|
122
|
-
Fetches the book
|
|
125
|
+
Fetches the book and optionally embeds child resources directly in the
|
|
126
|
+
response, avoiding follow-up requests.
|
|
123
127
|
|
|
124
128
|
Args:
|
|
125
129
|
book_id: The ID of the book to retrieve.
|
|
130
|
+
include: Child resources to embed in the response. Valid values are
|
|
131
|
+
``"chapters"``, ``"notes"``, and ``"assets"``.
|
|
126
132
|
|
|
127
133
|
Returns:
|
|
128
|
-
The
|
|
134
|
+
The CampaignBookDetail object with full details and any requested embeds.
|
|
129
135
|
|
|
130
136
|
Raises:
|
|
131
137
|
NotFoundError: If the book does not exist.
|
|
132
138
|
AuthorizationError: If you don't have access.
|
|
133
139
|
"""
|
|
134
|
-
response = self._get(
|
|
135
|
-
|
|
140
|
+
response = self._get(
|
|
141
|
+
self._format_endpoint(Endpoints.CAMPAIGN_BOOK, book_id=book_id),
|
|
142
|
+
params=self._build_params(include=list(include) if include else None),
|
|
143
|
+
)
|
|
144
|
+
return CampaignBookDetail.model_validate(response.json())
|
|
136
145
|
|
|
137
146
|
def create(self, request: BookCreate | None = None, **kwargs) -> CampaignBook:
|
|
138
147
|
"""Create a new campaign book.
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"""Service for interacting with the Users API."""
|
|
3
3
|
|
|
4
4
|
import mimetypes
|
|
5
|
-
from collections.abc import Iterator
|
|
5
|
+
from collections.abc import Iterator, Sequence
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
8
|
from vclient._sync.services.base import SyncBaseService
|
|
9
|
-
from vclient.constants import DEFAULT_PAGE_LIMIT, UserRole
|
|
9
|
+
from vclient.constants import DEFAULT_PAGE_LIMIT, UserInclude, UserRole
|
|
10
10
|
from vclient.endpoints import Endpoints
|
|
11
11
|
from vclient.models import (
|
|
12
12
|
Asset,
|
|
@@ -23,6 +23,7 @@ from vclient.models import (
|
|
|
23
23
|
UserApproveDTO,
|
|
24
24
|
UserCreate,
|
|
25
25
|
UserDenyDTO,
|
|
26
|
+
UserDetail,
|
|
26
27
|
UserMergeDTO,
|
|
27
28
|
UserRegisterDTO,
|
|
28
29
|
UserUpdate,
|
|
@@ -64,13 +65,14 @@ class SyncUsersService(SyncBaseService):
|
|
|
64
65
|
return endpoint.format(company_id=self._company_id, **kwargs)
|
|
65
66
|
|
|
66
67
|
def get_unapproved_page(
|
|
67
|
-
self, *, limit: int = DEFAULT_PAGE_LIMIT, offset: int = 0
|
|
68
|
+
self, requesting_user_id: str, *, limit: int = DEFAULT_PAGE_LIMIT, offset: int = 0
|
|
68
69
|
) -> PaginatedResponse[User]:
|
|
69
70
|
"""Retrieve a paginated page of unapproved users within a company.
|
|
70
71
|
|
|
71
72
|
Unapproved users have registered but have not yet been approved by an admin.
|
|
72
73
|
|
|
73
74
|
Args:
|
|
75
|
+
requesting_user_id: ID of the user making the request (for permissions).
|
|
74
76
|
limit: Maximum number of items to return (0-100, default 10).
|
|
75
77
|
offset: Number of items to skip from the beginning (default 0).
|
|
76
78
|
|
|
@@ -78,40 +80,54 @@ class SyncUsersService(SyncBaseService):
|
|
|
78
80
|
A PaginatedResponse containing User objects and pagination metadata.
|
|
79
81
|
"""
|
|
80
82
|
return self._get_paginated_as(
|
|
81
|
-
self._format_endpoint(Endpoints.USERS_UNAPPROVED_LIST),
|
|
83
|
+
self._format_endpoint(Endpoints.USERS_UNAPPROVED_LIST),
|
|
84
|
+
User,
|
|
85
|
+
limit=limit,
|
|
86
|
+
offset=offset,
|
|
87
|
+
params=self._build_params(requesting_user_id=requesting_user_id),
|
|
82
88
|
)
|
|
83
89
|
|
|
84
|
-
def list_all_unapproved(self) -> list[User]:
|
|
90
|
+
def list_all_unapproved(self, requesting_user_id: str) -> list[User]:
|
|
85
91
|
"""Retrieve all unapproved users within a company.
|
|
86
92
|
|
|
87
93
|
Automatically paginates through all results. Use `get_unapproved_page()` for
|
|
88
94
|
paginated access or `iter_all_unapproved()` for memory-efficient streaming.
|
|
89
95
|
|
|
96
|
+
Args:
|
|
97
|
+
requesting_user_id: ID of the user making the request (for permissions).
|
|
98
|
+
|
|
90
99
|
Returns:
|
|
91
100
|
A list of all unapproved User objects.
|
|
92
101
|
"""
|
|
93
|
-
return [user for user in self.iter_all_unapproved()]
|
|
102
|
+
return [user for user in self.iter_all_unapproved(requesting_user_id)]
|
|
94
103
|
|
|
95
|
-
def iter_all_unapproved(self, *, limit: int = 100) -> Iterator[User]:
|
|
104
|
+
def iter_all_unapproved(self, requesting_user_id: str, *, limit: int = 100) -> Iterator[User]:
|
|
96
105
|
"""Iterate through all unapproved users within a company.
|
|
97
106
|
|
|
98
107
|
Yields individual unapproved users, automatically fetching subsequent pages
|
|
99
108
|
until all items have been retrieved.
|
|
100
109
|
|
|
101
110
|
Args:
|
|
111
|
+
requesting_user_id: ID of the user making the request (for permissions).
|
|
102
112
|
limit: Items per page (default 100 for efficiency).
|
|
103
113
|
|
|
104
114
|
Yields:
|
|
105
115
|
Individual User objects.
|
|
106
116
|
"""
|
|
107
117
|
for item in self._iter_all_pages(
|
|
108
|
-
self._format_endpoint(Endpoints.USERS_UNAPPROVED_LIST),
|
|
118
|
+
self._format_endpoint(Endpoints.USERS_UNAPPROVED_LIST),
|
|
119
|
+
limit=limit,
|
|
120
|
+
params=self._build_params(requesting_user_id=requesting_user_id),
|
|
109
121
|
):
|
|
110
122
|
yield User.model_validate(item)
|
|
111
123
|
|
|
112
124
|
def approve_user(self, user_id: str, role: UserRole, requesting_user_id: str) -> User:
|
|
113
125
|
"""Approve an unapproved user and assign them a role.
|
|
114
126
|
|
|
127
|
+
The assigned ``role`` is validated through the server-side role-assignment
|
|
128
|
+
hierarchy — for example, a STORYTELLER cannot approve a user directly to
|
|
129
|
+
ADMIN, and only ADMIN may approve a user to ADMIN or DEACTIVATED.
|
|
130
|
+
|
|
115
131
|
Args:
|
|
116
132
|
user_id: The ID of the unapproved user to approve.
|
|
117
133
|
role: The role to assign to the approved user.
|
|
@@ -122,7 +138,8 @@ class SyncUsersService(SyncBaseService):
|
|
|
122
138
|
|
|
123
139
|
Raises:
|
|
124
140
|
NotFoundError: If the user does not exist.
|
|
125
|
-
AuthorizationError: If
|
|
141
|
+
AuthorizationError: If the requesting user lacks permission to assign
|
|
142
|
+
the requested role under the hierarchy.
|
|
126
143
|
"""
|
|
127
144
|
body = UserApproveDTO(role=role, requesting_user_id=requesting_user_id)
|
|
128
145
|
response = self._post(
|
|
@@ -251,23 +268,31 @@ class SyncUsersService(SyncBaseService):
|
|
|
251
268
|
):
|
|
252
269
|
yield User.model_validate(item)
|
|
253
270
|
|
|
254
|
-
def get(self, user_id: str) ->
|
|
271
|
+
def get(self, user_id: str, *, include: Sequence[UserInclude] | None = None) -> UserDetail:
|
|
255
272
|
"""Retrieve detailed information about a specific user.
|
|
256
273
|
|
|
257
|
-
Fetches the user
|
|
274
|
+
Fetches the user and optionally embeds child resources directly in the
|
|
275
|
+
response, avoiding follow-up requests.
|
|
258
276
|
|
|
259
277
|
Args:
|
|
260
278
|
user_id: The ID of the user to retrieve.
|
|
279
|
+
include: Child resources to embed in the response. Valid values are
|
|
280
|
+
``"quickrolls"``, ``"notes"``, ``"assets"``, and ``"characters"``.
|
|
281
|
+
``"assets"`` returns assets attached to the user (not assets the user
|
|
282
|
+
uploaded). ``"characters"`` returns only characters the user plays.
|
|
261
283
|
|
|
262
284
|
Returns:
|
|
263
|
-
The
|
|
285
|
+
The UserDetail object with full details and any requested embeds.
|
|
264
286
|
|
|
265
287
|
Raises:
|
|
266
288
|
NotFoundError: If the user does not exist.
|
|
267
289
|
AuthorizationError: If you don't have access to the company.
|
|
268
290
|
"""
|
|
269
|
-
response = self._get(
|
|
270
|
-
|
|
291
|
+
response = self._get(
|
|
292
|
+
self._format_endpoint(Endpoints.USER, user_id=user_id),
|
|
293
|
+
params=self._build_params(include=list(include) if include else None),
|
|
294
|
+
)
|
|
295
|
+
return UserDetail.model_validate(response.json())
|
|
271
296
|
|
|
272
297
|
def create(self, request: UserCreate | None = None, **kwargs) -> User:
|
|
273
298
|
"""Create a new user within a company.
|
|
@@ -276,6 +301,10 @@ class SyncUsersService(SyncBaseService):
|
|
|
276
301
|
is optional and is not used for authentication but is included for Discord bot
|
|
277
302
|
integration.
|
|
278
303
|
|
|
304
|
+
The initial ``role`` cannot be ``UNAPPROVED`` (use :meth:`register` for SSO
|
|
305
|
+
onboarding) or ``DEACTIVATED`` (not a creation path); either will surface as
|
|
306
|
+
``ValidationError``.
|
|
307
|
+
|
|
279
308
|
Args:
|
|
280
309
|
request: A UserCreate model, OR pass fields as keyword arguments.
|
|
281
310
|
**kwargs: Fields for UserCreate if request is not provided.
|
|
@@ -332,6 +361,14 @@ class SyncUsersService(SyncBaseService):
|
|
|
332
361
|
|
|
333
362
|
Only include fields that need to be changed; omitted fields remain unchanged.
|
|
334
363
|
|
|
364
|
+
Setting ``role="DEACTIVATED"`` is the canonical way to deactivate a user:
|
|
365
|
+
the account can no longer log in or act, but their characters, assets, XP,
|
|
366
|
+
and notes remain intact and manageable by other users. Reactivate by calling
|
|
367
|
+
this same endpoint with any other valid role. Role changes are subject to a
|
|
368
|
+
server-side role-assignment hierarchy (e.g. only ADMIN may assign or remove
|
|
369
|
+
ADMIN/DEACTIVATED) and the server refuses to demote or deactivate the last
|
|
370
|
+
remaining active admin.
|
|
371
|
+
|
|
335
372
|
Args:
|
|
336
373
|
user_id: The ID of the user to update.
|
|
337
374
|
request: A UserUpdate model, OR pass fields as keyword arguments.
|
|
@@ -345,7 +382,9 @@ class SyncUsersService(SyncBaseService):
|
|
|
345
382
|
|
|
346
383
|
Raises:
|
|
347
384
|
NotFoundError: If the user does not exist.
|
|
348
|
-
AuthorizationError: If
|
|
385
|
+
AuthorizationError: If the requesting user lacks permission to make
|
|
386
|
+
the change or to assign the requested role under the hierarchy.
|
|
387
|
+
ConflictError: If the change would remove the last active admin.
|
|
349
388
|
RequestValidationError: If the input parameters fail client-side validation.
|
|
350
389
|
ValidationError: If the request data is invalid.
|
|
351
390
|
"""
|
|
@@ -38,6 +38,9 @@ AbilityFocus = Literal["JACK_OF_ALL_TRADES", "BALANCED", "SPECIALIST"]
|
|
|
38
38
|
AutoGenExperienceLevel = Literal["NEW", "INTERMEDIATE", "ADVANCED", "ELITE"]
|
|
39
39
|
CharacterClass = Literal["VAMPIRE", "WEREWOLF", "MAGE", "HUNTER", "GHOUL", "MORTAL"]
|
|
40
40
|
CharacterInclude = Literal["traits", "inventory", "notes", "assets"]
|
|
41
|
+
BookInclude = Literal["chapters", "notes", "assets"]
|
|
42
|
+
ChapterInclude = Literal["notes", "assets"]
|
|
43
|
+
UserInclude = Literal["quickrolls", "notes", "assets", "characters"]
|
|
41
44
|
CharacterInventoryType = Literal[
|
|
42
45
|
"BOOK",
|
|
43
46
|
"CONSUMABLE",
|
|
@@ -56,10 +59,11 @@ HunterCreed = Literal["ENTREPRENEURIAL", "FAITHFUL", "INQUISITIVE", "MARTIAL", "
|
|
|
56
59
|
HunterEdgeType = Literal["ASSETS", "APTITUDES", "ENDOWMENTS"]
|
|
57
60
|
ManageCampaignPermission = Literal["UNRESTRICTED", "STORYTELLER"]
|
|
58
61
|
PermissionLevel = Literal["USER", "ADMIN", "OWNER", "REVOKE"]
|
|
62
|
+
RecoupXPPermission = Literal["UNRESTRICTED", "DENIED", "WITHIN_SESSION"]
|
|
59
63
|
RollResultType = Literal["SUCCESS", "FAILURE", "BOTCH", "CRITICAL", "OTHER"]
|
|
60
64
|
AssetType = Literal["image", "text", "audio", "video", "document", "archive", "other"]
|
|
61
65
|
SpecialtyType = Literal["ACTION", "OTHER", "PASSIVE", "RITUAL", "SPELL"]
|
|
62
|
-
UserRole = Literal["ADMIN", "STORYTELLER", "PLAYER", "UNAPPROVED"]
|
|
66
|
+
UserRole = Literal["ADMIN", "STORYTELLER", "PLAYER", "UNAPPROVED", "DEACTIVATED"]
|
|
63
67
|
WerewolfRenown = Literal["HONOR", "GLORY", "WISDOM"]
|
|
64
68
|
BlueprintTraitOrderBy = Literal["NAME", "SHEET"]
|
|
65
69
|
TraitModifyCurrency = Literal["XP", "STARTING_POINTS", "NO_COST"]
|
{valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/__init__.py
RENAMED
|
@@ -5,6 +5,7 @@ from .books import (
|
|
|
5
5
|
BookCreate,
|
|
6
6
|
BookUpdate,
|
|
7
7
|
CampaignBook,
|
|
8
|
+
CampaignBookDetail,
|
|
8
9
|
_BookRenumber as _BookRenumber,
|
|
9
10
|
)
|
|
10
11
|
from .campaigns import (
|
|
@@ -14,6 +15,7 @@ from .campaigns import (
|
|
|
14
15
|
)
|
|
15
16
|
from .chapters import (
|
|
16
17
|
CampaignChapter,
|
|
18
|
+
CampaignChapterDetail,
|
|
17
19
|
ChapterCreate,
|
|
18
20
|
ChapterUpdate,
|
|
19
21
|
_ChapterRenumber as _ChapterRenumber,
|
|
@@ -126,6 +128,7 @@ from .users import (
|
|
|
126
128
|
UserApproveDTO,
|
|
127
129
|
UserCreate,
|
|
128
130
|
UserDenyDTO,
|
|
131
|
+
UserDetail,
|
|
129
132
|
UserMergeDTO,
|
|
130
133
|
UserRegisterDTO,
|
|
131
134
|
UserUpdate,
|
|
@@ -141,7 +144,9 @@ __all__ = [
|
|
|
141
144
|
"BulkAssignTraitSuccess",
|
|
142
145
|
"Campaign",
|
|
143
146
|
"CampaignBook",
|
|
147
|
+
"CampaignBookDetail",
|
|
144
148
|
"CampaignChapter",
|
|
149
|
+
"CampaignChapterDetail",
|
|
145
150
|
"CampaignCreate",
|
|
146
151
|
"CampaignExperience",
|
|
147
152
|
"CampaignUpdate",
|
|
@@ -215,6 +220,7 @@ __all__ = [
|
|
|
215
220
|
"UserApproveDTO",
|
|
216
221
|
"UserCreate",
|
|
217
222
|
"UserDenyDTO",
|
|
223
|
+
"UserDetail",
|
|
218
224
|
"UserMergeDTO",
|
|
219
225
|
"UserRegisterDTO",
|
|
220
226
|
"UserUpdate",
|
{valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/books.py
RENAMED
|
@@ -4,6 +4,9 @@ from datetime import datetime
|
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel, Field
|
|
6
6
|
|
|
7
|
+
from vclient.models.chapters import CampaignChapter
|
|
8
|
+
from vclient.models.shared import Asset, Note
|
|
9
|
+
|
|
7
10
|
|
|
8
11
|
class CampaignBook(BaseModel):
|
|
9
12
|
"""Response model for a campaign book.
|
|
@@ -21,6 +24,25 @@ class CampaignBook(BaseModel):
|
|
|
21
24
|
campaign_id: str = Field(..., description="ID of the parent campaign.")
|
|
22
25
|
|
|
23
26
|
|
|
27
|
+
class CampaignBookDetail(CampaignBook):
|
|
28
|
+
"""Campaign book response with optional embedded child resources.
|
|
29
|
+
|
|
30
|
+
Returned by the single-book endpoint when the ``include`` query parameter
|
|
31
|
+
is used. Absent resources default to ``None``; present resources are full arrays
|
|
32
|
+
of the same DTOs returned by the dedicated child endpoints.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
chapters: list[CampaignChapter] | None = Field(
|
|
36
|
+
default=None, description="Embedded chapters, when requested via include."
|
|
37
|
+
)
|
|
38
|
+
notes: list[Note] | None = Field(
|
|
39
|
+
default=None, description="Embedded notes, when requested via include."
|
|
40
|
+
)
|
|
41
|
+
assets: list[Asset] | None = Field(
|
|
42
|
+
default=None, description="Embedded assets, when requested via include."
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
24
46
|
class BookCreate(BaseModel):
|
|
25
47
|
"""Request body for creating a new campaign book.
|
|
26
48
|
|
|
@@ -60,5 +82,6 @@ __all__ = [
|
|
|
60
82
|
"BookCreate",
|
|
61
83
|
"BookUpdate",
|
|
62
84
|
"CampaignBook",
|
|
85
|
+
"CampaignBookDetail",
|
|
63
86
|
"_BookRenumber",
|
|
64
87
|
]
|
{valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/chapters.py
RENAMED
|
@@ -4,6 +4,8 @@ from datetime import datetime
|
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel, Field
|
|
6
6
|
|
|
7
|
+
from vclient.models.shared import Asset, Note
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
class CampaignChapter(BaseModel):
|
|
9
11
|
"""Response model for a campaign chapter.
|
|
@@ -23,6 +25,22 @@ class CampaignChapter(BaseModel):
|
|
|
23
25
|
book_id: str = Field(..., description="ID of the parent book.")
|
|
24
26
|
|
|
25
27
|
|
|
28
|
+
class CampaignChapterDetail(CampaignChapter):
|
|
29
|
+
"""Campaign chapter response with optional embedded child resources.
|
|
30
|
+
|
|
31
|
+
Returned by the single-chapter endpoint when the ``include`` query parameter
|
|
32
|
+
is used. Absent resources default to ``None``; present resources are full arrays
|
|
33
|
+
of the same DTOs returned by the dedicated child endpoints.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
notes: list[Note] | None = Field(
|
|
37
|
+
default=None, description="Embedded notes, when requested via include."
|
|
38
|
+
)
|
|
39
|
+
assets: list[Asset] | None = Field(
|
|
40
|
+
default=None, description="Embedded assets, when requested via include."
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
26
44
|
class ChapterCreate(BaseModel):
|
|
27
45
|
"""Request body for creating a new campaign chapter."""
|
|
28
46
|
|
|
@@ -45,6 +63,7 @@ class _ChapterRenumber(BaseModel):
|
|
|
45
63
|
|
|
46
64
|
__all__ = [
|
|
47
65
|
"CampaignChapter",
|
|
66
|
+
"CampaignChapterDetail",
|
|
48
67
|
"ChapterCreate",
|
|
49
68
|
"ChapterUpdate",
|
|
50
69
|
"_ChapterRenumber",
|
{valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/characters.py
RENAMED
|
@@ -152,12 +152,8 @@ class Character(BaseModel):
|
|
|
152
152
|
"""
|
|
153
153
|
|
|
154
154
|
id: str = Field(..., description="MongoDB document ObjectID.")
|
|
155
|
-
date_created: datetime
|
|
156
|
-
|
|
157
|
-
)
|
|
158
|
-
date_modified: datetime | None = Field(
|
|
159
|
-
default=None, description="Timestamp when the character was last modified."
|
|
160
|
-
)
|
|
155
|
+
date_created: datetime
|
|
156
|
+
date_modified: datetime
|
|
161
157
|
date_killed: datetime | None = Field(
|
|
162
158
|
default=None, description="Timestamp when the character was killed."
|
|
163
159
|
)
|
{valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/companies.py
RENAMED
|
@@ -10,6 +10,7 @@ from vclient.constants import (
|
|
|
10
10
|
GrantXPPermission,
|
|
11
11
|
ManageCampaignPermission,
|
|
12
12
|
PermissionLevel,
|
|
13
|
+
RecoupXPPermission,
|
|
13
14
|
)
|
|
14
15
|
from vclient.models.users import User
|
|
15
16
|
|
|
@@ -26,6 +27,7 @@ class CompanySettings(BaseModel):
|
|
|
26
27
|
permission_manage_campaign: ManageCampaignPermission | None = None
|
|
27
28
|
permission_grant_xp: GrantXPPermission | None = None
|
|
28
29
|
permission_free_trait_changes: FreeTraitChangesPermission | None = None
|
|
30
|
+
permission_recoup_xp: RecoupXPPermission | None = None
|
|
29
31
|
|
|
30
32
|
|
|
31
33
|
class Company(BaseModel):
|
|
@@ -41,7 +43,7 @@ class Company(BaseModel):
|
|
|
41
43
|
description: str | None
|
|
42
44
|
email: str
|
|
43
45
|
resources_modified_at: datetime
|
|
44
|
-
settings: CompanySettings
|
|
46
|
+
settings: CompanySettings
|
|
45
47
|
|
|
46
48
|
|
|
47
49
|
class CompanyPermissions(BaseModel):
|
{valentina_python_client-1.19.0 → valentina_python_client-1.20.1}/src/vclient/models/users.py
RENAMED
|
@@ -6,6 +6,8 @@ from typing import Annotated
|
|
|
6
6
|
from pydantic import BaseModel, Field
|
|
7
7
|
|
|
8
8
|
from vclient.constants import UserRole
|
|
9
|
+
from vclient.models.characters import Character
|
|
10
|
+
from vclient.models.shared import Asset, Note
|
|
9
11
|
|
|
10
12
|
# -----------------------------------------------------------------------------
|
|
11
13
|
# Nested/Shared Models
|
|
@@ -96,6 +98,30 @@ class User(BaseModel):
|
|
|
96
98
|
lifetime_cool_points: int = 0
|
|
97
99
|
|
|
98
100
|
|
|
101
|
+
class UserDetail(User):
|
|
102
|
+
"""User response with optional embedded child resources.
|
|
103
|
+
|
|
104
|
+
Returned by the single-user endpoint when the ``include`` query parameter
|
|
105
|
+
is used. Absent resources default to ``None``; present resources are full arrays.
|
|
106
|
+
|
|
107
|
+
Note: ``assets`` returns assets attached to the user (not assets the user
|
|
108
|
+
uploaded), and ``characters`` returns only characters the user plays.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
quickrolls: list["Quickroll"] | None = Field(
|
|
112
|
+
default=None, description="Embedded quickrolls, when requested via include."
|
|
113
|
+
)
|
|
114
|
+
notes: list[Note] | None = Field(
|
|
115
|
+
default=None, description="Embedded notes attached to the user."
|
|
116
|
+
)
|
|
117
|
+
assets: list[Asset] | None = Field(
|
|
118
|
+
default=None, description="Embedded assets attached to the user."
|
|
119
|
+
)
|
|
120
|
+
characters: list[Character] | None = Field(
|
|
121
|
+
default=None, description="Embedded characters the user plays."
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
99
125
|
# -----------------------------------------------------------------------------
|
|
100
126
|
# User Request Models
|
|
101
127
|
# -----------------------------------------------------------------------------
|
|
@@ -205,6 +231,9 @@ class Quickroll(BaseModel):
|
|
|
205
231
|
trait_ids: list[str] = Field(default_factory=list)
|
|
206
232
|
|
|
207
233
|
|
|
234
|
+
UserDetail.model_rebuild()
|
|
235
|
+
|
|
236
|
+
|
|
208
237
|
class QuickrollCreate(BaseModel):
|
|
209
238
|
"""Request body for creating a new quickroll.
|
|
210
239
|
|
|
@@ -253,6 +282,7 @@ __all__ = [
|
|
|
253
282
|
"QuickrollUpdate",
|
|
254
283
|
"User",
|
|
255
284
|
"UserCreate",
|
|
285
|
+
"UserDetail",
|
|
256
286
|
"UserMergeDTO",
|
|
257
287
|
"UserRegisterDTO",
|
|
258
288
|
"UserUpdate",
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
"""Service for interacting with the Campaign Books Chapters API."""
|
|
2
2
|
|
|
3
3
|
import mimetypes
|
|
4
|
-
from collections.abc import AsyncIterator
|
|
4
|
+
from collections.abc import AsyncIterator, Sequence
|
|
5
5
|
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
|
-
from vclient.constants import DEFAULT_PAGE_LIMIT
|
|
7
|
+
from vclient.constants import DEFAULT_PAGE_LIMIT, ChapterInclude
|
|
8
8
|
from vclient.endpoints import Endpoints
|
|
9
9
|
from vclient.models import (
|
|
10
10
|
Asset,
|
|
11
11
|
CampaignChapter,
|
|
12
|
+
CampaignChapterDetail,
|
|
12
13
|
ChapterCreate,
|
|
13
14
|
ChapterUpdate,
|
|
14
15
|
Note,
|
|
@@ -80,12 +81,34 @@ class ChaptersService(BaseService):
|
|
|
80
81
|
):
|
|
81
82
|
yield CampaignChapter.model_validate(item)
|
|
82
83
|
|
|
83
|
-
async def get(
|
|
84
|
-
|
|
84
|
+
async def get(
|
|
85
|
+
self,
|
|
86
|
+
chapter_id: str,
|
|
87
|
+
*,
|
|
88
|
+
include: Sequence[ChapterInclude] | None = None,
|
|
89
|
+
) -> CampaignChapterDetail:
|
|
90
|
+
"""Retrieve detailed information about a specific campaign book chapter.
|
|
91
|
+
|
|
92
|
+
Fetches the chapter and optionally embeds child resources directly in the
|
|
93
|
+
response, avoiding follow-up requests.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
chapter_id: The ID of the chapter to retrieve.
|
|
97
|
+
include: Child resources to embed in the response. Valid values are
|
|
98
|
+
``"notes"`` and ``"assets"``.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
The CampaignChapterDetail object with full details and any requested embeds.
|
|
102
|
+
|
|
103
|
+
Raises:
|
|
104
|
+
NotFoundError: If the chapter does not exist.
|
|
105
|
+
AuthorizationError: If you don't have access.
|
|
106
|
+
"""
|
|
85
107
|
response = await self._get(
|
|
86
|
-
self._format_endpoint(Endpoints.BOOK_CHAPTER, chapter_id=chapter_id)
|
|
108
|
+
self._format_endpoint(Endpoints.BOOK_CHAPTER, chapter_id=chapter_id),
|
|
109
|
+
params=self._build_params(include=list(include) if include else None),
|
|
87
110
|
)
|
|
88
|
-
return
|
|
111
|
+
return CampaignChapterDetail.model_validate(response.json())
|
|
89
112
|
|
|
90
113
|
async def create(
|
|
91
114
|
self,
|