valentina-python-client 2.8.0__tar.gz → 2.9.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.
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/PKG-INFO +1 -1
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/pyproject.toml +1 -1
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/__init__.py +1 -1
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/base.py +28 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/campaign_book_chapters.py +10 -2
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/campaign_books.py +10 -2
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/campaigns.py +10 -2
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/characters.py +10 -2
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/users.py +54 -2
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/endpoints.py +1 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/users.py +4 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/base.py +33 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/campaign_book_chapters.py +10 -2
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/campaign_books.py +10 -2
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/campaigns.py +10 -2
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/characters.py +10 -2
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/users.py +63 -2
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/testing/_routes.py +4 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/LICENSE +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/README.md +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_codegen.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/__init__.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/client.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/registry.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/__init__.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/_audit_params.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/character_autogen.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/character_blueprint.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/character_traits.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/companies.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/developers.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/dicerolls.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/dictionary.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/global_admin.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/identity.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/options.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/system.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/user_lookup.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/testing/__init__.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/testing/_client.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/client.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/config.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/constants.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/exceptions.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/__init__.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/audit_logs.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/books.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/campaigns.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/chapters.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/character_autogen.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/character_blueprint.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/character_trait.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/characters.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/companies.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/developers.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/diceroll.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/dictionary.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/full_sheet.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/global_admin.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/pagination.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/shared.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/system.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/user_lookup.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/py.typed +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/registry.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/__init__.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/_audit_params.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/character_autogen.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/character_blueprint.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/character_traits.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/companies.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/developers.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/dicerolls.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/dictionary.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/global_admin.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/identity.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/options.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/system.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/user_lookup.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/testing/__init__.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/testing/_client.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/testing/_factories.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/testing/_router.py +0 -0
- {valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/validate_constants.py +0 -0
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/base.py
RENAMED
|
@@ -592,6 +592,34 @@ class SyncBaseService:
|
|
|
592
592
|
headers=self._build_idempotency_headers(idempotency_key),
|
|
593
593
|
)
|
|
594
594
|
|
|
595
|
+
def _put_file(
|
|
596
|
+
self, path: str, *, file: tuple[str, bytes, str], idempotency_key: str | None = None
|
|
597
|
+
) -> httpx.Response:
|
|
598
|
+
"""Make a PUT request with a file upload (multipart/form-data).
|
|
599
|
+
|
|
600
|
+
Mirrors ``_post_file``: an idempotency key is sent only when supplied.
|
|
601
|
+
|
|
602
|
+
Args:
|
|
603
|
+
path: API endpoint path.
|
|
604
|
+
file: Tuple of (filename, content, content_type) for the file to upload.
|
|
605
|
+
idempotency_key: Optional idempotency key for safe retries.
|
|
606
|
+
|
|
607
|
+
Returns:
|
|
608
|
+
The HTTP response.
|
|
609
|
+
|
|
610
|
+
Raises:
|
|
611
|
+
ServerError: When server error occurs and max retries are exhausted.
|
|
612
|
+
RateLimitError: When rate limit is exceeded and max retries are exhausted.
|
|
613
|
+
APIError: For other API error responses.
|
|
614
|
+
"""
|
|
615
|
+
filename, content, content_type = file
|
|
616
|
+
return self._request(
|
|
617
|
+
"PUT",
|
|
618
|
+
path,
|
|
619
|
+
files={"data": (filename, content, content_type)},
|
|
620
|
+
headers=self._build_idempotency_headers(idempotency_key),
|
|
621
|
+
)
|
|
622
|
+
|
|
595
623
|
def _get_paginated(
|
|
596
624
|
self,
|
|
597
625
|
path: str,
|
|
@@ -406,9 +406,17 @@ class SyncChaptersService(SyncBaseService):
|
|
|
406
406
|
def upload_asset(
|
|
407
407
|
self, chapter_id: str, filename: str, content: bytes, content_type: str | None = None
|
|
408
408
|
) -> Asset:
|
|
409
|
-
"""Upload a new asset for a chapter.
|
|
409
|
+
"""Upload a new image asset for a chapter.
|
|
410
410
|
|
|
411
|
-
Uploads
|
|
411
|
+
Uploads an image to S3 storage and associates it with the chapter.
|
|
412
|
+
|
|
413
|
+
Only image files are accepted: PNG, JPEG, GIF, and WEBP. Any other
|
|
414
|
+
upload (documents, audio, video, archives, SVG, or a non-image payload
|
|
415
|
+
mislabeled as an image) is rejected with 400 Bad Request, as are
|
|
416
|
+
oversized images that trip the decompression-bomb guard. The stored
|
|
417
|
+
``mime_type`` is detected from the file's bytes; the ``content_type``
|
|
418
|
+
argument is ignored server-side and cannot change or bypass the stored
|
|
419
|
+
type. Uploaded assets therefore always have ``asset_type == "image"``.
|
|
412
420
|
|
|
413
421
|
Args:
|
|
414
422
|
chapter_id: The ID of the chapter to upload the asset for.
|
|
@@ -470,9 +470,17 @@ class SyncBooksService(SyncBaseService):
|
|
|
470
470
|
def upload_asset(
|
|
471
471
|
self, book_id: str, filename: str, content: bytes, content_type: str | None = None
|
|
472
472
|
) -> Asset:
|
|
473
|
-
"""Upload a new asset for a book.
|
|
473
|
+
"""Upload a new image asset for a book.
|
|
474
474
|
|
|
475
|
-
Uploads
|
|
475
|
+
Uploads an image to S3 storage and associates it with the book.
|
|
476
|
+
|
|
477
|
+
Only image files are accepted: PNG, JPEG, GIF, and WEBP. Any other
|
|
478
|
+
upload (documents, audio, video, archives, SVG, or a non-image payload
|
|
479
|
+
mislabeled as an image) is rejected with 400 Bad Request, as are
|
|
480
|
+
oversized images that trip the decompression-bomb guard. The stored
|
|
481
|
+
``mime_type`` is detected from the file's bytes; the ``content_type``
|
|
482
|
+
argument is ignored server-side and cannot change or bypass the stored
|
|
483
|
+
type. Uploaded assets therefore always have ``asset_type == "image"``.
|
|
476
484
|
|
|
477
485
|
Args:
|
|
478
486
|
book_id: The ID of the book to upload the asset for.
|
|
@@ -316,9 +316,17 @@ class SyncCampaignsService(SyncBaseService):
|
|
|
316
316
|
def upload_asset(
|
|
317
317
|
self, campaign_id: str, filename: str, content: bytes, content_type: str | None = None
|
|
318
318
|
) -> Asset:
|
|
319
|
-
"""Upload a new asset for a campaign.
|
|
319
|
+
"""Upload a new image asset for a campaign.
|
|
320
320
|
|
|
321
|
-
Uploads
|
|
321
|
+
Uploads an image to S3 storage and associates it with the campaign.
|
|
322
|
+
|
|
323
|
+
Only image files are accepted: PNG, JPEG, GIF, and WEBP. Any other
|
|
324
|
+
upload (documents, audio, video, archives, SVG, or a non-image payload
|
|
325
|
+
mislabeled as an image) is rejected with 400 Bad Request, as are
|
|
326
|
+
oversized images that trip the decompression-bomb guard. The stored
|
|
327
|
+
``mime_type`` is detected from the file's bytes; the ``content_type``
|
|
328
|
+
argument is ignored server-side and cannot change or bypass the stored
|
|
329
|
+
type. Uploaded assets therefore always have ``asset_type == "image"``.
|
|
322
330
|
|
|
323
331
|
Args:
|
|
324
332
|
campaign_id: The ID of the campaign to upload the asset for.
|
|
@@ -499,9 +499,17 @@ class SyncCharactersService(SyncBaseService):
|
|
|
499
499
|
def upload_asset(
|
|
500
500
|
self, character_id: str, filename: str, content: bytes, content_type: str | None = None
|
|
501
501
|
) -> Asset:
|
|
502
|
-
"""Upload a new asset for a
|
|
502
|
+
"""Upload a new image asset for a character.
|
|
503
503
|
|
|
504
|
-
Uploads
|
|
504
|
+
Uploads an image to S3 storage and associates it with the character.
|
|
505
|
+
|
|
506
|
+
Only image files are accepted: PNG, JPEG, GIF, and WEBP. Any other
|
|
507
|
+
upload (documents, audio, video, archives, SVG, or a non-image payload
|
|
508
|
+
mislabeled as an image) is rejected with 400 Bad Request, as are
|
|
509
|
+
oversized images that trip the decompression-bomb guard. The stored
|
|
510
|
+
``mime_type`` is detected from the file's bytes; the ``content_type``
|
|
511
|
+
argument is ignored server-side and cannot change or bypass the stored
|
|
512
|
+
type. Uploaded assets therefore always have ``asset_type == "image"``.
|
|
505
513
|
|
|
506
514
|
Args:
|
|
507
515
|
character_id: The ID of the character to upload the asset for.
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/users.py
RENAMED
|
@@ -557,9 +557,17 @@ class SyncUsersService(SyncBaseService):
|
|
|
557
557
|
def upload_asset(
|
|
558
558
|
self, user_id: str, filename: str, content: bytes, content_type: str | None = None
|
|
559
559
|
) -> Asset:
|
|
560
|
-
"""Upload a new asset for a user.
|
|
560
|
+
"""Upload a new image asset for a user.
|
|
561
561
|
|
|
562
|
-
Uploads
|
|
562
|
+
Uploads an image to S3 storage and associates it with the user.
|
|
563
|
+
|
|
564
|
+
Only image files are accepted: PNG, JPEG, GIF, and WEBP. Any other
|
|
565
|
+
upload (documents, audio, video, archives, SVG, or a non-image payload
|
|
566
|
+
mislabeled as an image) is rejected with 400 Bad Request, as are
|
|
567
|
+
oversized images that trip the decompression-bomb guard. The stored
|
|
568
|
+
``mime_type`` is detected from the file's bytes; the ``content_type``
|
|
569
|
+
argument is ignored server-side and cannot change or bypass the stored
|
|
570
|
+
type. Uploaded assets therefore always have ``asset_type == "image"``.
|
|
563
571
|
|
|
564
572
|
Args:
|
|
565
573
|
user_id: The ID of the user to upload the asset for.
|
|
@@ -583,6 +591,50 @@ class SyncUsersService(SyncBaseService):
|
|
|
583
591
|
)
|
|
584
592
|
return Asset.model_validate(response.json())
|
|
585
593
|
|
|
594
|
+
def upload_avatar(
|
|
595
|
+
self, user_id: str, filename: str, content: bytes, content_type: str | None = None
|
|
596
|
+
) -> User:
|
|
597
|
+
"""Upload a custom avatar for a user, replacing any existing one.
|
|
598
|
+
|
|
599
|
+
Accepts PNG, JPEG, WEBP, or GIF (first frame) up to 5 MB. The server
|
|
600
|
+
normalizes the image to a 512x512 WebP and it overrides any
|
|
601
|
+
identity-provider-derived avatar. Requires the ``On-Behalf-Of`` header
|
|
602
|
+
(permitted for the user themselves or an admin).
|
|
603
|
+
|
|
604
|
+
Args:
|
|
605
|
+
user_id: The ID of the user to set the avatar for.
|
|
606
|
+
filename: The original filename of the image.
|
|
607
|
+
content: The raw bytes of the image to upload.
|
|
608
|
+
content_type: The MIME type. If not provided, inferred from filename.
|
|
609
|
+
|
|
610
|
+
Returns:
|
|
611
|
+
The updated User object with the new ``avatar_url``.
|
|
612
|
+
"""
|
|
613
|
+
if content_type is None:
|
|
614
|
+
content_type = mimetypes.guess_type(filename)[0] or "application/octet-stream"
|
|
615
|
+
response = self._put_file(
|
|
616
|
+
self._format_endpoint(Endpoints.USER_AVATAR, user_id=user_id),
|
|
617
|
+
file=(filename, content, content_type),
|
|
618
|
+
)
|
|
619
|
+
return User.model_validate(response.json())
|
|
620
|
+
|
|
621
|
+
def delete_avatar(self, user_id: str) -> User:
|
|
622
|
+
"""Remove a user's custom avatar.
|
|
623
|
+
|
|
624
|
+
The avatar falls back to the identity-provider avatar, or ``None`` if
|
|
625
|
+
none exists. Requires the ``On-Behalf-Of`` header (permitted for the
|
|
626
|
+
user themselves or an admin). Responds 200 OK with the updated user
|
|
627
|
+
body (not 204).
|
|
628
|
+
|
|
629
|
+
Args:
|
|
630
|
+
user_id: The ID of the user whose custom avatar to remove.
|
|
631
|
+
|
|
632
|
+
Returns:
|
|
633
|
+
The updated User object with the resolved ``avatar_url``.
|
|
634
|
+
"""
|
|
635
|
+
response = self._delete(self._format_endpoint(Endpoints.USER_AVATAR, user_id=user_id))
|
|
636
|
+
return User.model_validate(response.json())
|
|
637
|
+
|
|
586
638
|
def get_experience(self, user_id: str, campaign_id: str) -> CampaignExperience:
|
|
587
639
|
"""Retrieve a user's experience points and cool points for a specific campaign.
|
|
588
640
|
|
|
@@ -56,6 +56,7 @@ class Endpoints:
|
|
|
56
56
|
USER_ASSETS = f"{USER}/assets"
|
|
57
57
|
USER_ASSET = f"{USER_ASSETS}/{{asset_id}}"
|
|
58
58
|
USER_ASSET_UPLOAD = f"{USER_ASSETS}/upload"
|
|
59
|
+
USER_AVATAR = f"{USER}/avatar"
|
|
59
60
|
USER_EXPERIENCE_CAMPAIGN = f"{USER}/experience/{{campaign_id}}"
|
|
60
61
|
USER_EXPERIENCE_XP_ADD = f"{USER}/experience/xp/add"
|
|
61
62
|
USER_EXPERIENCE_XP_REMOVE = f"{USER}/experience/xp/remove"
|
|
@@ -101,6 +101,10 @@ class User(BaseModel):
|
|
|
101
101
|
google_profile: GoogleProfile | None = None
|
|
102
102
|
github_profile: GitHubProfile | None = None
|
|
103
103
|
apple_profile: AppleProfile | None = None
|
|
104
|
+
avatar_url: str | None = None
|
|
105
|
+
"""Resolved avatar URL. Precedence: custom uploaded avatar (CloudFront URL),
|
|
106
|
+
then the identity-provider-derived avatar (currently Discord), else ``None``.
|
|
107
|
+
Prefer this over ``discord_profile.avatar_url`` for display."""
|
|
104
108
|
campaign_experience: list[CampaignExperience] = Field(default_factory=list)
|
|
105
109
|
asset_ids: list[str] = Field(default_factory=list)
|
|
106
110
|
lifetime_xp: int = 0
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/base.py
RENAMED
|
@@ -667,6 +667,39 @@ class BaseService:
|
|
|
667
667
|
headers=self._build_idempotency_headers(idempotency_key),
|
|
668
668
|
)
|
|
669
669
|
|
|
670
|
+
async def _put_file(
|
|
671
|
+
self,
|
|
672
|
+
path: str,
|
|
673
|
+
*,
|
|
674
|
+
file: tuple[str, bytes, str],
|
|
675
|
+
idempotency_key: str | None = None,
|
|
676
|
+
) -> httpx.Response:
|
|
677
|
+
"""Make a PUT request with a file upload (multipart/form-data).
|
|
678
|
+
|
|
679
|
+
Mirrors ``_post_file``: an idempotency key is sent only when supplied.
|
|
680
|
+
|
|
681
|
+
Args:
|
|
682
|
+
path: API endpoint path.
|
|
683
|
+
file: Tuple of (filename, content, content_type) for the file to upload.
|
|
684
|
+
idempotency_key: Optional idempotency key for safe retries.
|
|
685
|
+
|
|
686
|
+
Returns:
|
|
687
|
+
The HTTP response.
|
|
688
|
+
|
|
689
|
+
Raises:
|
|
690
|
+
ServerError: When server error occurs and max retries are exhausted.
|
|
691
|
+
RateLimitError: When rate limit is exceeded and max retries are exhausted.
|
|
692
|
+
APIError: For other API error responses.
|
|
693
|
+
"""
|
|
694
|
+
filename, content, content_type = file
|
|
695
|
+
|
|
696
|
+
return await self._request(
|
|
697
|
+
"PUT",
|
|
698
|
+
path,
|
|
699
|
+
files={"data": (filename, content, content_type)},
|
|
700
|
+
headers=self._build_idempotency_headers(idempotency_key),
|
|
701
|
+
)
|
|
702
|
+
|
|
670
703
|
# -------------------------------------------------------------------------
|
|
671
704
|
# Pagination Methods
|
|
672
705
|
# -------------------------------------------------------------------------
|
|
@@ -486,9 +486,17 @@ class ChaptersService(BaseService):
|
|
|
486
486
|
content: bytes,
|
|
487
487
|
content_type: str | None = None,
|
|
488
488
|
) -> Asset:
|
|
489
|
-
"""Upload a new asset for a chapter.
|
|
489
|
+
"""Upload a new image asset for a chapter.
|
|
490
490
|
|
|
491
|
-
Uploads
|
|
491
|
+
Uploads an image to S3 storage and associates it with the chapter.
|
|
492
|
+
|
|
493
|
+
Only image files are accepted: PNG, JPEG, GIF, and WEBP. Any other
|
|
494
|
+
upload (documents, audio, video, archives, SVG, or a non-image payload
|
|
495
|
+
mislabeled as an image) is rejected with 400 Bad Request, as are
|
|
496
|
+
oversized images that trip the decompression-bomb guard. The stored
|
|
497
|
+
``mime_type`` is detected from the file's bytes; the ``content_type``
|
|
498
|
+
argument is ignored server-side and cannot change or bypass the stored
|
|
499
|
+
type. Uploaded assets therefore always have ``asset_type == "image"``.
|
|
492
500
|
|
|
493
501
|
Args:
|
|
494
502
|
chapter_id: The ID of the chapter to upload the asset for.
|
|
@@ -562,9 +562,17 @@ class BooksService(BaseService):
|
|
|
562
562
|
content: bytes,
|
|
563
563
|
content_type: str | None = None,
|
|
564
564
|
) -> Asset:
|
|
565
|
-
"""Upload a new asset for a book.
|
|
565
|
+
"""Upload a new image asset for a book.
|
|
566
566
|
|
|
567
|
-
Uploads
|
|
567
|
+
Uploads an image to S3 storage and associates it with the book.
|
|
568
|
+
|
|
569
|
+
Only image files are accepted: PNG, JPEG, GIF, and WEBP. Any other
|
|
570
|
+
upload (documents, audio, video, archives, SVG, or a non-image payload
|
|
571
|
+
mislabeled as an image) is rejected with 400 Bad Request, as are
|
|
572
|
+
oversized images that trip the decompression-bomb guard. The stored
|
|
573
|
+
``mime_type`` is detected from the file's bytes; the ``content_type``
|
|
574
|
+
argument is ignored server-side and cannot change or bypass the stored
|
|
575
|
+
type. Uploaded assets therefore always have ``asset_type == "image"``.
|
|
568
576
|
|
|
569
577
|
Args:
|
|
570
578
|
book_id: The ID of the book to upload the asset for.
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/campaigns.py
RENAMED
|
@@ -380,9 +380,17 @@ class CampaignsService(BaseService):
|
|
|
380
380
|
content: bytes,
|
|
381
381
|
content_type: str | None = None,
|
|
382
382
|
) -> Asset:
|
|
383
|
-
"""Upload a new asset for a campaign.
|
|
383
|
+
"""Upload a new image asset for a campaign.
|
|
384
384
|
|
|
385
|
-
Uploads
|
|
385
|
+
Uploads an image to S3 storage and associates it with the campaign.
|
|
386
|
+
|
|
387
|
+
Only image files are accepted: PNG, JPEG, GIF, and WEBP. Any other
|
|
388
|
+
upload (documents, audio, video, archives, SVG, or a non-image payload
|
|
389
|
+
mislabeled as an image) is rejected with 400 Bad Request, as are
|
|
390
|
+
oversized images that trip the decompression-bomb guard. The stored
|
|
391
|
+
``mime_type`` is detected from the file's bytes; the ``content_type``
|
|
392
|
+
argument is ignored server-side and cannot change or bypass the stored
|
|
393
|
+
type. Uploaded assets therefore always have ``asset_type == "image"``.
|
|
386
394
|
|
|
387
395
|
Args:
|
|
388
396
|
campaign_id: The ID of the campaign to upload the asset for.
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/characters.py
RENAMED
|
@@ -555,9 +555,17 @@ class CharactersService(BaseService):
|
|
|
555
555
|
content: bytes,
|
|
556
556
|
content_type: str | None = None,
|
|
557
557
|
) -> Asset:
|
|
558
|
-
"""Upload a new asset for a
|
|
558
|
+
"""Upload a new image asset for a character.
|
|
559
559
|
|
|
560
|
-
Uploads
|
|
560
|
+
Uploads an image to S3 storage and associates it with the character.
|
|
561
|
+
|
|
562
|
+
Only image files are accepted: PNG, JPEG, GIF, and WEBP. Any other
|
|
563
|
+
upload (documents, audio, video, archives, SVG, or a non-image payload
|
|
564
|
+
mislabeled as an image) is rejected with 400 Bad Request, as are
|
|
565
|
+
oversized images that trip the decompression-bomb guard. The stored
|
|
566
|
+
``mime_type`` is detected from the file's bytes; the ``content_type``
|
|
567
|
+
argument is ignored server-side and cannot change or bypass the stored
|
|
568
|
+
type. Uploaded assets therefore always have ``asset_type == "image"``.
|
|
561
569
|
|
|
562
570
|
Args:
|
|
563
571
|
character_id: The ID of the character to upload the asset for.
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/users.py
RENAMED
|
@@ -656,9 +656,17 @@ class UsersService(BaseService):
|
|
|
656
656
|
content: bytes,
|
|
657
657
|
content_type: str | None = None,
|
|
658
658
|
) -> Asset:
|
|
659
|
-
"""Upload a new asset for a user.
|
|
659
|
+
"""Upload a new image asset for a user.
|
|
660
660
|
|
|
661
|
-
Uploads
|
|
661
|
+
Uploads an image to S3 storage and associates it with the user.
|
|
662
|
+
|
|
663
|
+
Only image files are accepted: PNG, JPEG, GIF, and WEBP. Any other
|
|
664
|
+
upload (documents, audio, video, archives, SVG, or a non-image payload
|
|
665
|
+
mislabeled as an image) is rejected with 400 Bad Request, as are
|
|
666
|
+
oversized images that trip the decompression-bomb guard. The stored
|
|
667
|
+
``mime_type`` is detected from the file's bytes; the ``content_type``
|
|
668
|
+
argument is ignored server-side and cannot change or bypass the stored
|
|
669
|
+
type. Uploaded assets therefore always have ``asset_type == "image"``.
|
|
662
670
|
|
|
663
671
|
Args:
|
|
664
672
|
user_id: The ID of the user to upload the asset for.
|
|
@@ -683,6 +691,59 @@ class UsersService(BaseService):
|
|
|
683
691
|
)
|
|
684
692
|
return Asset.model_validate(response.json())
|
|
685
693
|
|
|
694
|
+
# Avatar Methods
|
|
695
|
+
|
|
696
|
+
async def upload_avatar(
|
|
697
|
+
self,
|
|
698
|
+
user_id: str,
|
|
699
|
+
filename: str,
|
|
700
|
+
content: bytes,
|
|
701
|
+
content_type: str | None = None,
|
|
702
|
+
) -> User:
|
|
703
|
+
"""Upload a custom avatar for a user, replacing any existing one.
|
|
704
|
+
|
|
705
|
+
Accepts PNG, JPEG, WEBP, or GIF (first frame) up to 5 MB. The server
|
|
706
|
+
normalizes the image to a 512x512 WebP and it overrides any
|
|
707
|
+
identity-provider-derived avatar. Requires the ``On-Behalf-Of`` header
|
|
708
|
+
(permitted for the user themselves or an admin).
|
|
709
|
+
|
|
710
|
+
Args:
|
|
711
|
+
user_id: The ID of the user to set the avatar for.
|
|
712
|
+
filename: The original filename of the image.
|
|
713
|
+
content: The raw bytes of the image to upload.
|
|
714
|
+
content_type: The MIME type. If not provided, inferred from filename.
|
|
715
|
+
|
|
716
|
+
Returns:
|
|
717
|
+
The updated User object with the new ``avatar_url``.
|
|
718
|
+
"""
|
|
719
|
+
if content_type is None:
|
|
720
|
+
content_type = mimetypes.guess_type(filename)[0] or "application/octet-stream"
|
|
721
|
+
|
|
722
|
+
response = await self._put_file(
|
|
723
|
+
self._format_endpoint(Endpoints.USER_AVATAR, user_id=user_id),
|
|
724
|
+
file=(filename, content, content_type),
|
|
725
|
+
)
|
|
726
|
+
return User.model_validate(response.json())
|
|
727
|
+
|
|
728
|
+
async def delete_avatar(self, user_id: str) -> User:
|
|
729
|
+
"""Remove a user's custom avatar.
|
|
730
|
+
|
|
731
|
+
The avatar falls back to the identity-provider avatar, or ``None`` if
|
|
732
|
+
none exists. Requires the ``On-Behalf-Of`` header (permitted for the
|
|
733
|
+
user themselves or an admin). Responds 200 OK with the updated user
|
|
734
|
+
body (not 204).
|
|
735
|
+
|
|
736
|
+
Args:
|
|
737
|
+
user_id: The ID of the user whose custom avatar to remove.
|
|
738
|
+
|
|
739
|
+
Returns:
|
|
740
|
+
The updated User object with the resolved ``avatar_url``.
|
|
741
|
+
"""
|
|
742
|
+
response = await self._delete(
|
|
743
|
+
self._format_endpoint(Endpoints.USER_AVATAR, user_id=user_id),
|
|
744
|
+
)
|
|
745
|
+
return User.model_validate(response.json())
|
|
746
|
+
|
|
686
747
|
# Experience Methods
|
|
687
748
|
|
|
688
749
|
async def get_experience(
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/testing/_routes.py
RENAMED
|
@@ -164,6 +164,10 @@ class Routes:
|
|
|
164
164
|
USERS_ASSETS_DELETE = RouteSpec("DELETE", Endpoints.USER_ASSET, NO_CONTENT, None)
|
|
165
165
|
USERS_ASSETS_UPLOAD = RouteSpec("POST", Endpoints.USER_ASSET_UPLOAD, SINGLE, Asset)
|
|
166
166
|
|
|
167
|
+
# User avatar
|
|
168
|
+
USERS_AVATAR_UPLOAD = RouteSpec("PUT", Endpoints.USER_AVATAR, SINGLE, User)
|
|
169
|
+
USERS_AVATAR_DELETE = RouteSpec("DELETE", Endpoints.USER_AVATAR, SINGLE, User)
|
|
170
|
+
|
|
167
171
|
# User experience
|
|
168
172
|
USERS_EXPERIENCE_GET = RouteSpec(
|
|
169
173
|
"GET", Endpoints.USER_EXPERIENCE_CAMPAIGN, SINGLE, CampaignExperience
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/services/system.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/_sync/testing/_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/__init__.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/audit_logs.py
RENAMED
|
File without changes
|
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/campaigns.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/chapters.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/characters.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/companies.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/developers.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/diceroll.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/dictionary.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/full_sheet.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/global_admin.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/pagination.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/shared.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/system.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/models/user_lookup.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/companies.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/developers.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/dicerolls.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/dictionary.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/global_admin.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/identity.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/options.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/system.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/services/user_lookup.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/testing/__init__.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/testing/_client.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/testing/_factories.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/testing/_router.py
RENAMED
|
File without changes
|
{valentina_python_client-2.8.0 → valentina_python_client-2.9.0}/src/vclient/validate_constants.py
RENAMED
|
File without changes
|