Merge pull request #5 from l3ocho/claude/fix-warnings-and-tests-011CUPCzT7Y2KnBovShb7PxU
Claude/fix warnings and tests 011 cup cz t7 y2 kn bov shb7 px u
This commit is contained in:
@@ -52,6 +52,16 @@ class TestJWTAuth:
|
|||||||
with pytest.raises(ValueError, match="JWT token cannot be empty"):
|
with pytest.raises(ValueError, match="JWT token cannot be empty"):
|
||||||
JWTAuth(None, mock_wiki_base_url)
|
JWTAuth(None, mock_wiki_base_url)
|
||||||
|
|
||||||
|
def test_init_with_empty_base_url_raises_error(self, mock_jwt_token):
|
||||||
|
"""Test that empty base URL raises ValueError."""
|
||||||
|
with pytest.raises(ValueError, match="Base URL cannot be empty"):
|
||||||
|
JWTAuth(mock_jwt_token, "")
|
||||||
|
|
||||||
|
def test_init_with_whitespace_base_url_raises_error(self, mock_jwt_token):
|
||||||
|
"""Test that whitespace-only base URL raises ValueError."""
|
||||||
|
with pytest.raises(ValueError, match="Base URL cannot be empty"):
|
||||||
|
JWTAuth(mock_jwt_token, " ")
|
||||||
|
|
||||||
def test_get_headers_returns_bearer_token(self, jwt_auth, mock_jwt_token):
|
def test_get_headers_returns_bearer_token(self, jwt_auth, mock_jwt_token):
|
||||||
"""Test that get_headers returns proper Authorization header."""
|
"""Test that get_headers returns proper Authorization header."""
|
||||||
headers = jwt_auth.get_headers()
|
headers = jwt_auth.get_headers()
|
||||||
|
|||||||
@@ -161,3 +161,347 @@ class TestAssetsEndpoint:
|
|||||||
|
|
||||||
with pytest.raises(ValidationError):
|
with pytest.raises(ValidationError):
|
||||||
endpoint.rename(1, "")
|
endpoint.rename(1, "")
|
||||||
|
|
||||||
|
# Move operations
|
||||||
|
def test_move_asset(self, endpoint):
|
||||||
|
"""Test moving an asset to a different folder."""
|
||||||
|
mock_response = {
|
||||||
|
"data": {
|
||||||
|
"assets": {
|
||||||
|
"moveAsset": {
|
||||||
|
"responseResult": {"succeeded": True},
|
||||||
|
"asset": {
|
||||||
|
"id": 1,
|
||||||
|
"filename": "test.png",
|
||||||
|
"ext": "png",
|
||||||
|
"kind": "image",
|
||||||
|
"mime": "image/png",
|
||||||
|
"fileSize": 1024,
|
||||||
|
"folderId": 5,
|
||||||
|
"authorId": 1,
|
||||||
|
"authorName": "Admin",
|
||||||
|
"createdAt": "2024-01-01T00:00:00Z",
|
||||||
|
"updatedAt": "2024-01-01T00:00:00Z",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endpoint._post = Mock(return_value=mock_response)
|
||||||
|
|
||||||
|
asset = endpoint.move(1, 5)
|
||||||
|
|
||||||
|
assert asset.folder_id == 5
|
||||||
|
|
||||||
|
def test_move_asset_validation_error(self, endpoint):
|
||||||
|
"""Test move asset with invalid inputs."""
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
endpoint.move(0, 1) # Invalid asset ID
|
||||||
|
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
endpoint.move(1, -1) # Invalid folder ID
|
||||||
|
|
||||||
|
# Folder operations
|
||||||
|
def test_create_folder(self, endpoint):
|
||||||
|
"""Test creating a folder."""
|
||||||
|
mock_response = {
|
||||||
|
"data": {
|
||||||
|
"assets": {
|
||||||
|
"createFolder": {
|
||||||
|
"responseResult": {"succeeded": True},
|
||||||
|
"folder": {"id": 1, "slug": "documents", "name": "Documents"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endpoint._post = Mock(return_value=mock_response)
|
||||||
|
|
||||||
|
folder = endpoint.create_folder("documents", "Documents")
|
||||||
|
|
||||||
|
assert isinstance(folder, AssetFolder)
|
||||||
|
assert folder.slug == "documents"
|
||||||
|
assert folder.name == "Documents"
|
||||||
|
|
||||||
|
def test_create_folder_minimal(self, endpoint):
|
||||||
|
"""Test creating a folder with minimal parameters."""
|
||||||
|
mock_response = {
|
||||||
|
"data": {
|
||||||
|
"assets": {
|
||||||
|
"createFolder": {
|
||||||
|
"responseResult": {"succeeded": True},
|
||||||
|
"folder": {"id": 2, "slug": "images", "name": None},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endpoint._post = Mock(return_value=mock_response)
|
||||||
|
|
||||||
|
folder = endpoint.create_folder("images")
|
||||||
|
|
||||||
|
assert folder.slug == "images"
|
||||||
|
assert folder.name is None
|
||||||
|
|
||||||
|
def test_create_folder_validation_error(self, endpoint):
|
||||||
|
"""Test create folder with invalid slug."""
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
endpoint.create_folder("") # Empty slug
|
||||||
|
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
endpoint.create_folder("///") # Just slashes
|
||||||
|
|
||||||
|
def test_delete_folder(self, endpoint):
|
||||||
|
"""Test deleting a folder."""
|
||||||
|
mock_response = {
|
||||||
|
"data": {
|
||||||
|
"assets": {
|
||||||
|
"deleteFolder": {
|
||||||
|
"responseResult": {"succeeded": True}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endpoint._post = Mock(return_value=mock_response)
|
||||||
|
|
||||||
|
result = endpoint.delete_folder(1)
|
||||||
|
|
||||||
|
assert result is True
|
||||||
|
|
||||||
|
def test_delete_folder_validation_error(self, endpoint):
|
||||||
|
"""Test delete folder with invalid ID."""
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
endpoint.delete_folder(0)
|
||||||
|
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
endpoint.delete_folder(-1)
|
||||||
|
|
||||||
|
# List operations with filters
|
||||||
|
def test_list_assets_with_folder_filter(self, endpoint):
|
||||||
|
"""Test listing assets filtered by folder."""
|
||||||
|
mock_response = {
|
||||||
|
"data": {
|
||||||
|
"assets": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"filename": "doc.pdf",
|
||||||
|
"ext": "pdf",
|
||||||
|
"kind": "binary",
|
||||||
|
"mime": "application/pdf",
|
||||||
|
"fileSize": 2048,
|
||||||
|
"folderId": 1,
|
||||||
|
"folder": {"id": 1, "slug": "documents", "name": "Documents"},
|
||||||
|
"authorId": 1,
|
||||||
|
"authorName": "Admin",
|
||||||
|
"createdAt": "2024-01-01T00:00:00Z",
|
||||||
|
"updatedAt": "2024-01-01T00:00:00Z",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endpoint._post = Mock(return_value=mock_response)
|
||||||
|
|
||||||
|
assets = endpoint.list(folder_id=1)
|
||||||
|
|
||||||
|
assert len(assets) == 1
|
||||||
|
assert assets[0].folder_id == 1
|
||||||
|
|
||||||
|
def test_list_assets_with_kind_filter(self, endpoint):
|
||||||
|
"""Test listing assets filtered by kind."""
|
||||||
|
mock_response = {
|
||||||
|
"data": {
|
||||||
|
"assets": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"filename": "photo.jpg",
|
||||||
|
"ext": "jpg",
|
||||||
|
"kind": "image",
|
||||||
|
"mime": "image/jpeg",
|
||||||
|
"fileSize": 5120,
|
||||||
|
"folderId": 0,
|
||||||
|
"authorId": 1,
|
||||||
|
"authorName": "Admin",
|
||||||
|
"createdAt": "2024-01-01T00:00:00Z",
|
||||||
|
"updatedAt": "2024-01-01T00:00:00Z",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endpoint._post = Mock(return_value=mock_response)
|
||||||
|
|
||||||
|
assets = endpoint.list(kind="image")
|
||||||
|
|
||||||
|
assert len(assets) == 1
|
||||||
|
assert assets[0].kind == "image"
|
||||||
|
|
||||||
|
def test_list_assets_empty(self, endpoint):
|
||||||
|
"""Test listing assets when none exist."""
|
||||||
|
mock_response = {"data": {"assets": {"list": []}}}
|
||||||
|
endpoint._post = Mock(return_value=mock_response)
|
||||||
|
|
||||||
|
assets = endpoint.list()
|
||||||
|
|
||||||
|
assert len(assets) == 0
|
||||||
|
|
||||||
|
# Error handling
|
||||||
|
def test_get_asset_not_found(self, endpoint):
|
||||||
|
"""Test getting non-existent asset."""
|
||||||
|
mock_response = {
|
||||||
|
"data": {"assets": {"single": None}},
|
||||||
|
"errors": [{"message": "Asset not found"}],
|
||||||
|
}
|
||||||
|
endpoint._post = Mock(return_value=mock_response)
|
||||||
|
|
||||||
|
with pytest.raises(APIError, match="Asset not found"):
|
||||||
|
endpoint.get(999)
|
||||||
|
|
||||||
|
def test_delete_asset_failure(self, endpoint):
|
||||||
|
"""Test delete asset API failure."""
|
||||||
|
mock_response = {
|
||||||
|
"data": {
|
||||||
|
"assets": {
|
||||||
|
"deleteAsset": {
|
||||||
|
"responseResult": {"succeeded": False, "message": "Permission denied"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endpoint._post = Mock(return_value=mock_response)
|
||||||
|
|
||||||
|
with pytest.raises(APIError, match="Permission denied"):
|
||||||
|
endpoint.delete(1)
|
||||||
|
|
||||||
|
def test_rename_asset_failure(self, endpoint):
|
||||||
|
"""Test rename asset API failure."""
|
||||||
|
mock_response = {
|
||||||
|
"data": {
|
||||||
|
"assets": {
|
||||||
|
"renameAsset": {
|
||||||
|
"responseResult": {"succeeded": False, "message": "Name already exists"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endpoint._post = Mock(return_value=mock_response)
|
||||||
|
|
||||||
|
with pytest.raises(APIError, match="Name already exists"):
|
||||||
|
endpoint.rename(1, "duplicate.png")
|
||||||
|
|
||||||
|
def test_move_asset_failure(self, endpoint):
|
||||||
|
"""Test move asset API failure."""
|
||||||
|
mock_response = {
|
||||||
|
"data": {
|
||||||
|
"assets": {
|
||||||
|
"moveAsset": {
|
||||||
|
"responseResult": {"succeeded": False, "message": "Folder not found"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endpoint._post = Mock(return_value=mock_response)
|
||||||
|
|
||||||
|
with pytest.raises(APIError, match="Folder not found"):
|
||||||
|
endpoint.move(1, 999)
|
||||||
|
|
||||||
|
def test_create_folder_failure(self, endpoint):
|
||||||
|
"""Test create folder API failure."""
|
||||||
|
mock_response = {
|
||||||
|
"data": {
|
||||||
|
"assets": {
|
||||||
|
"createFolder": {
|
||||||
|
"responseResult": {"succeeded": False, "message": "Folder already exists"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endpoint._post = Mock(return_value=mock_response)
|
||||||
|
|
||||||
|
with pytest.raises(APIError, match="Folder already exists"):
|
||||||
|
endpoint.create_folder("existing")
|
||||||
|
|
||||||
|
def test_delete_folder_failure(self, endpoint):
|
||||||
|
"""Test delete folder API failure."""
|
||||||
|
mock_response = {
|
||||||
|
"data": {
|
||||||
|
"assets": {
|
||||||
|
"deleteFolder": {
|
||||||
|
"responseResult": {"succeeded": False, "message": "Folder not empty"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endpoint._post = Mock(return_value=mock_response)
|
||||||
|
|
||||||
|
with pytest.raises(APIError, match="Folder not empty"):
|
||||||
|
endpoint.delete_folder(1)
|
||||||
|
|
||||||
|
# Pagination
|
||||||
|
def test_iter_all_assets(self, endpoint):
|
||||||
|
"""Test iterating over all assets with pagination."""
|
||||||
|
# First page (smaller batch to ensure pagination works)
|
||||||
|
mock_response_page1 = {
|
||||||
|
"data": {
|
||||||
|
"assets": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"id": i,
|
||||||
|
"filename": f"file{i}.png",
|
||||||
|
"ext": "png",
|
||||||
|
"kind": "image",
|
||||||
|
"mime": "image/png",
|
||||||
|
"fileSize": 1024,
|
||||||
|
"folderId": 0,
|
||||||
|
"authorId": 1,
|
||||||
|
"authorName": "Admin",
|
||||||
|
"createdAt": "2024-01-01T00:00:00Z",
|
||||||
|
"updatedAt": "2024-01-01T00:00:00Z",
|
||||||
|
}
|
||||||
|
for i in range(1, 6) # 5 items
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Second page (empty - pagination stops)
|
||||||
|
mock_response_page2 = {"data": {"assets": {"list": []}}}
|
||||||
|
|
||||||
|
endpoint._post = Mock(
|
||||||
|
side_effect=[mock_response_page1, mock_response_page2]
|
||||||
|
)
|
||||||
|
|
||||||
|
all_assets = list(endpoint.iter_all(batch_size=5))
|
||||||
|
|
||||||
|
assert len(all_assets) == 5
|
||||||
|
assert all_assets[0].id == 1
|
||||||
|
assert all_assets[4].id == 5
|
||||||
|
|
||||||
|
# Normalization edge cases
|
||||||
|
def test_normalize_asset_data_minimal(self, endpoint):
|
||||||
|
"""Test normalizing asset data with minimal fields."""
|
||||||
|
data = {
|
||||||
|
"id": 1,
|
||||||
|
"filename": "test.png",
|
||||||
|
"ext": "png",
|
||||||
|
"kind": "image",
|
||||||
|
"mime": "image/png",
|
||||||
|
"fileSize": 1024,
|
||||||
|
}
|
||||||
|
|
||||||
|
normalized = endpoint._normalize_asset_data(data)
|
||||||
|
|
||||||
|
assert normalized["id"] == 1
|
||||||
|
assert normalized["filename"] == "test.png"
|
||||||
|
# Check that snake_case fields are present
|
||||||
|
assert "file_size" in normalized
|
||||||
|
assert normalized["file_size"] == 1024
|
||||||
|
|
||||||
|
def test_list_folders_empty(self, endpoint):
|
||||||
|
"""Test listing folders when none exist."""
|
||||||
|
mock_response = {"data": {"assets": {"folders": []}}}
|
||||||
|
endpoint._post = Mock(return_value=mock_response)
|
||||||
|
|
||||||
|
folders = endpoint.list_folders()
|
||||||
|
|
||||||
|
assert len(folders) == 0
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import Field, field_validator
|
from pydantic import ConfigDict, Field, field_validator
|
||||||
|
|
||||||
from .base import BaseModel, TimestampedModel
|
from .base import BaseModel, TimestampedModel
|
||||||
|
|
||||||
@@ -10,15 +10,12 @@ from .base import BaseModel, TimestampedModel
|
|||||||
class AssetFolder(BaseModel):
|
class AssetFolder(BaseModel):
|
||||||
"""Asset folder model."""
|
"""Asset folder model."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(populate_by_name=True)
|
||||||
|
|
||||||
id: int = Field(..., description="Folder ID")
|
id: int = Field(..., description="Folder ID")
|
||||||
slug: str = Field(..., description="Folder slug/path")
|
slug: str = Field(..., description="Folder slug/path")
|
||||||
name: Optional[str] = Field(None, description="Folder name")
|
name: Optional[str] = Field(None, description="Folder name")
|
||||||
|
|
||||||
class Config:
|
|
||||||
"""Pydantic configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
|
|
||||||
|
|
||||||
class Asset(TimestampedModel):
|
class Asset(TimestampedModel):
|
||||||
"""Wiki.js asset model.
|
"""Wiki.js asset model.
|
||||||
@@ -75,10 +72,7 @@ class Asset(TimestampedModel):
|
|||||||
"""Get file size in kilobytes."""
|
"""Get file size in kilobytes."""
|
||||||
return self.file_size / 1024
|
return self.file_size / 1024
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(populate_by_name=True)
|
||||||
"""Pydantic configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
|
|
||||||
|
|
||||||
class AssetUpload(BaseModel):
|
class AssetUpload(BaseModel):
|
||||||
@@ -102,10 +96,7 @@ class AssetUpload(BaseModel):
|
|||||||
raise ValueError("File path cannot be empty")
|
raise ValueError("File path cannot be empty")
|
||||||
return v.strip()
|
return v.strip()
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(populate_by_name=True)
|
||||||
"""Pydantic configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
|
|
||||||
|
|
||||||
class AssetRename(BaseModel):
|
class AssetRename(BaseModel):
|
||||||
@@ -137,10 +128,7 @@ class AssetRename(BaseModel):
|
|||||||
raise ValueError("Filename cannot be empty")
|
raise ValueError("Filename cannot be empty")
|
||||||
return v.strip()
|
return v.strip()
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(populate_by_name=True)
|
||||||
"""Pydantic configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
|
|
||||||
|
|
||||||
class AssetMove(BaseModel):
|
class AssetMove(BaseModel):
|
||||||
@@ -170,10 +158,7 @@ class AssetMove(BaseModel):
|
|||||||
raise ValueError("Folder ID must be non-negative")
|
raise ValueError("Folder ID must be non-negative")
|
||||||
return v
|
return v
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(populate_by_name=True)
|
||||||
"""Pydantic configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
|
|
||||||
|
|
||||||
class FolderCreate(BaseModel):
|
class FolderCreate(BaseModel):
|
||||||
@@ -199,7 +184,4 @@ class FolderCreate(BaseModel):
|
|||||||
raise ValueError("Slug cannot be just slashes")
|
raise ValueError("Slug cannot be just slashes")
|
||||||
return v
|
return v
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(populate_by_name=True)
|
||||||
"""Pydantic configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from pydantic import Field, field_validator
|
from pydantic import ConfigDict, Field, field_validator
|
||||||
|
|
||||||
from .base import BaseModel, TimestampedModel
|
from .base import BaseModel, TimestampedModel
|
||||||
|
|
||||||
@@ -10,18 +10,17 @@ from .base import BaseModel, TimestampedModel
|
|||||||
class GroupPermission(BaseModel):
|
class GroupPermission(BaseModel):
|
||||||
"""Group permission model."""
|
"""Group permission model."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(populate_by_name=True)
|
||||||
|
|
||||||
id: str = Field(..., description="Permission identifier")
|
id: str = Field(..., description="Permission identifier")
|
||||||
name: Optional[str] = Field(None, description="Permission name")
|
name: Optional[str] = Field(None, description="Permission name")
|
||||||
|
|
||||||
class Config:
|
|
||||||
"""Pydantic configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
|
|
||||||
|
|
||||||
class GroupPageRule(BaseModel):
|
class GroupPageRule(BaseModel):
|
||||||
"""Group page access rule model."""
|
"""Group page access rule model."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(populate_by_name=True)
|
||||||
|
|
||||||
id: str = Field(..., description="Rule identifier")
|
id: str = Field(..., description="Rule identifier")
|
||||||
path: str = Field(..., description="Page path pattern")
|
path: str = Field(..., description="Page path pattern")
|
||||||
roles: List[str] = Field(default_factory=list, description="Allowed roles")
|
roles: List[str] = Field(default_factory=list, description="Allowed roles")
|
||||||
@@ -29,24 +28,16 @@ class GroupPageRule(BaseModel):
|
|||||||
deny: bool = Field(default=False, description="Whether this is a deny rule")
|
deny: bool = Field(default=False, description="Whether this is a deny rule")
|
||||||
locales: List[str] = Field(default_factory=list, description="Allowed locales")
|
locales: List[str] = Field(default_factory=list, description="Allowed locales")
|
||||||
|
|
||||||
class Config:
|
|
||||||
"""Pydantic configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
|
|
||||||
|
|
||||||
class GroupUser(BaseModel):
|
class GroupUser(BaseModel):
|
||||||
"""User member of a group (minimal representation)."""
|
"""User member of a group (minimal representation)."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(populate_by_name=True)
|
||||||
|
|
||||||
id: int = Field(..., description="User ID")
|
id: int = Field(..., description="User ID")
|
||||||
name: str = Field(..., description="User name")
|
name: str = Field(..., description="User name")
|
||||||
email: str = Field(..., description="User email")
|
email: str = Field(..., description="User email")
|
||||||
|
|
||||||
class Config:
|
|
||||||
"""Pydantic configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
|
|
||||||
|
|
||||||
class Group(TimestampedModel):
|
class Group(TimestampedModel):
|
||||||
"""Wiki.js group model.
|
"""Wiki.js group model.
|
||||||
@@ -95,10 +86,7 @@ class Group(TimestampedModel):
|
|||||||
raise ValueError("Group name cannot exceed 255 characters")
|
raise ValueError("Group name cannot exceed 255 characters")
|
||||||
return v.strip()
|
return v.strip()
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(populate_by_name=True)
|
||||||
"""Pydantic configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
|
|
||||||
|
|
||||||
class GroupCreate(BaseModel):
|
class GroupCreate(BaseModel):
|
||||||
@@ -111,6 +99,8 @@ class GroupCreate(BaseModel):
|
|||||||
page_rules: List of page access rule configurations
|
page_rules: List of page access rule configurations
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(populate_by_name=True)
|
||||||
|
|
||||||
name: str = Field(..., min_length=1, max_length=255, description="Group name")
|
name: str = Field(..., min_length=1, max_length=255, description="Group name")
|
||||||
redirect_on_login: Optional[str] = Field(
|
redirect_on_login: Optional[str] = Field(
|
||||||
None, alias="redirectOnLogin", description="Redirect path on login"
|
None, alias="redirectOnLogin", description="Redirect path on login"
|
||||||
@@ -134,11 +124,6 @@ class GroupCreate(BaseModel):
|
|||||||
raise ValueError("Group name cannot exceed 255 characters")
|
raise ValueError("Group name cannot exceed 255 characters")
|
||||||
return v.strip()
|
return v.strip()
|
||||||
|
|
||||||
class Config:
|
|
||||||
"""Pydantic configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
|
|
||||||
|
|
||||||
class GroupUpdate(BaseModel):
|
class GroupUpdate(BaseModel):
|
||||||
"""Model for updating an existing group.
|
"""Model for updating an existing group.
|
||||||
@@ -152,6 +137,8 @@ class GroupUpdate(BaseModel):
|
|||||||
page_rules: Updated page access rules
|
page_rules: Updated page access rules
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(populate_by_name=True)
|
||||||
|
|
||||||
name: Optional[str] = Field(
|
name: Optional[str] = Field(
|
||||||
None, min_length=1, max_length=255, description="Group name"
|
None, min_length=1, max_length=255, description="Group name"
|
||||||
)
|
)
|
||||||
@@ -177,11 +164,6 @@ class GroupUpdate(BaseModel):
|
|||||||
raise ValueError("Group name cannot exceed 255 characters")
|
raise ValueError("Group name cannot exceed 255 characters")
|
||||||
return v.strip()
|
return v.strip()
|
||||||
|
|
||||||
class Config:
|
|
||||||
"""Pydantic configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
|
|
||||||
|
|
||||||
class GroupAssignUser(BaseModel):
|
class GroupAssignUser(BaseModel):
|
||||||
"""Model for assigning a user to a group.
|
"""Model for assigning a user to a group.
|
||||||
@@ -191,14 +173,11 @@ class GroupAssignUser(BaseModel):
|
|||||||
user_id: User ID
|
user_id: User ID
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(populate_by_name=True)
|
||||||
|
|
||||||
group_id: int = Field(..., alias="groupId", description="Group ID")
|
group_id: int = Field(..., alias="groupId", description="Group ID")
|
||||||
user_id: int = Field(..., alias="userId", description="User ID")
|
user_id: int = Field(..., alias="userId", description="User ID")
|
||||||
|
|
||||||
class Config:
|
|
||||||
"""Pydantic configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
|
|
||||||
|
|
||||||
class GroupUnassignUser(BaseModel):
|
class GroupUnassignUser(BaseModel):
|
||||||
"""Model for removing a user from a group.
|
"""Model for removing a user from a group.
|
||||||
@@ -208,10 +187,7 @@ class GroupUnassignUser(BaseModel):
|
|||||||
user_id: User ID
|
user_id: User ID
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(populate_by_name=True)
|
||||||
|
|
||||||
group_id: int = Field(..., alias="groupId", description="Group ID")
|
group_id: int = Field(..., alias="groupId", description="Group ID")
|
||||||
user_id: int = Field(..., alias="userId", description="User ID")
|
user_id: int = Field(..., alias="userId", description="User ID")
|
||||||
|
|
||||||
class Config:
|
|
||||||
"""Pydantic configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import re
|
import re
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from pydantic import EmailStr, Field, field_validator
|
from pydantic import ConfigDict, EmailStr, Field, field_validator
|
||||||
|
|
||||||
from .base import BaseModel, TimestampedModel
|
from .base import BaseModel, TimestampedModel
|
||||||
|
|
||||||
@@ -63,11 +63,7 @@ class User(TimestampedModel):
|
|||||||
|
|
||||||
return v.strip()
|
return v.strip()
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(populate_by_name=True, str_strip_whitespace=True)
|
||||||
"""Pydantic model configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
str_strip_whitespace = True
|
|
||||||
|
|
||||||
|
|
||||||
class UserCreate(BaseModel):
|
class UserCreate(BaseModel):
|
||||||
@@ -122,11 +118,7 @@ class UserCreate(BaseModel):
|
|||||||
|
|
||||||
return v
|
return v
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(populate_by_name=True, str_strip_whitespace=True)
|
||||||
"""Pydantic model configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
str_strip_whitespace = True
|
|
||||||
|
|
||||||
|
|
||||||
class UserUpdate(BaseModel):
|
class UserUpdate(BaseModel):
|
||||||
@@ -185,8 +177,4 @@ class UserUpdate(BaseModel):
|
|||||||
|
|
||||||
return v
|
return v
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(populate_by_name=True, str_strip_whitespace=True)
|
||||||
"""Pydantic model configuration."""
|
|
||||||
|
|
||||||
populate_by_name = True
|
|
||||||
str_strip_whitespace = True
|
|
||||||
|
|||||||
Reference in New Issue
Block a user