Files
py-wikijs/wikijs/models/user.py
Claude 59cdf5ee01 refactor: Rename package from wikijs-python-sdk to py-wikijs and migrate to GitHub
Complete package renaming and platform migration:

Package Name Changes:
- Rename package from 'wikijs-python-sdk' to 'py-wikijs'
- Update setup.py package name
- Update pyproject.toml package name
- Users can now install with: pip install py-wikijs

URL Migration (Gitea → GitHub):
- Replace all Gitea URLs with GitHub URLs
- Update repository: github.com/l3ocho/py-wikijs
- Update issue tracker: github.com/l3ocho/py-wikijs/issues
- Update documentation links
- Fix URL path format (/src/branch/main/ → /blob/main/)

Documentation Updates:
- Update README.md badges (PyPI, GitHub)
- Update installation instructions (pip install py-wikijs)
- Update all doc references to new package name
- Update all examples with GitHub URLs
- Update DEPLOYMENT_READY.md with new package name
- Update deployment.md with new package name

Testing:
- Successfully built py_wikijs-0.1.0.tar.gz (138 KB)
- Successfully built py_wikijs-0.1.0-py3-none-any.whl (66 KB)
- Package installs correctly: pip install py-wikijs
- Imports work: from wikijs import WikiJSClient
- Package metadata correct (Home-page: github.com/l3ocho/py-wikijs)

Breaking Changes:
- Package name changed from wikijs-python-sdk to py-wikijs
- Repository migrated from Gitea to GitHub
- All URLs updated to GitHub

Users should now:
pip install py-wikijs  # Instead of wikijs-python-sdk

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-23 20:23:50 +00:00

181 lines
6.3 KiB
Python

"""User-related data models for py-wikijs."""
import re
from typing import List, Optional
from pydantic import ConfigDict, EmailStr, Field, field_validator
from .base import BaseModel, TimestampedModel
class UserGroup(BaseModel):
"""Represents a user's group membership.
This model contains information about a user's membership
in a specific group.
"""
id: int = Field(..., description="Group ID")
name: str = Field(..., description="Group name")
class User(TimestampedModel):
"""Represents a Wiki.js user.
This model contains all user data including profile information,
authentication details, and group memberships.
"""
id: int = Field(..., description="Unique user identifier")
name: str = Field(..., description="User's full name")
email: EmailStr = Field(..., description="User's email address")
# Authentication and status
provider_key: Optional[str] = Field(None, alias="providerKey", description="Auth provider key")
is_system: bool = Field(False, alias="isSystem", description="Whether user is system user")
is_active: bool = Field(True, alias="isActive", description="Whether user is active")
is_verified: bool = Field(False, alias="isVerified", description="Whether email is verified")
# Profile information
location: Optional[str] = Field(None, description="User's location")
job_title: Optional[str] = Field(None, alias="jobTitle", description="User's job title")
timezone: Optional[str] = Field(None, description="User's timezone")
# Permissions and groups
groups: List[UserGroup] = Field(default_factory=list, description="User's groups")
# Timestamps handled by TimestampedModel
last_login_at: Optional[str] = Field(None, alias="lastLoginAt", description="Last login timestamp")
@field_validator("name")
@classmethod
def validate_name(cls, v: str) -> str:
"""Validate user name."""
if not v or not v.strip():
raise ValueError("Name cannot be empty")
# Check length
if len(v) < 2:
raise ValueError("Name must be at least 2 characters long")
if len(v) > 255:
raise ValueError("Name cannot exceed 255 characters")
return v.strip()
model_config = ConfigDict(populate_by_name=True, str_strip_whitespace=True)
class UserCreate(BaseModel):
"""Model for creating a new user.
This model contains all required and optional fields
for creating a new Wiki.js user.
"""
email: EmailStr = Field(..., description="User's email address")
name: str = Field(..., description="User's full name")
password_raw: str = Field(..., alias="passwordRaw", description="User's password")
# Optional fields
provider_key: str = Field("local", alias="providerKey", description="Auth provider key")
groups: List[int] = Field(default_factory=list, description="Group IDs to assign")
must_change_password: bool = Field(False, alias="mustChangePassword", description="Force password change")
send_welcome_email: bool = Field(True, alias="sendWelcomeEmail", description="Send welcome email")
# Profile information
location: Optional[str] = Field(None, description="User's location")
job_title: Optional[str] = Field(None, alias="jobTitle", description="User's job title")
timezone: Optional[str] = Field(None, description="User's timezone")
@field_validator("name")
@classmethod
def validate_name(cls, v: str) -> str:
"""Validate user name."""
if not v or not v.strip():
raise ValueError("Name cannot be empty")
if len(v) < 2:
raise ValueError("Name must be at least 2 characters long")
if len(v) > 255:
raise ValueError("Name cannot exceed 255 characters")
return v.strip()
@field_validator("password_raw")
@classmethod
def validate_password(cls, v: str) -> str:
"""Validate password strength."""
if not v:
raise ValueError("Password cannot be empty")
if len(v) < 6:
raise ValueError("Password must be at least 6 characters long")
if len(v) > 255:
raise ValueError("Password cannot exceed 255 characters")
return v
model_config = ConfigDict(populate_by_name=True, str_strip_whitespace=True)
class UserUpdate(BaseModel):
"""Model for updating an existing user.
This model contains optional fields that can be updated
for an existing Wiki.js user. All fields are optional.
"""
name: Optional[str] = Field(None, description="User's full name")
email: Optional[EmailStr] = Field(None, description="User's email address")
password_raw: Optional[str] = Field(None, alias="passwordRaw", description="New password")
# Profile information
location: Optional[str] = Field(None, description="User's location")
job_title: Optional[str] = Field(None, alias="jobTitle", description="User's job title")
timezone: Optional[str] = Field(None, description="User's timezone")
# Group assignments
groups: Optional[List[int]] = Field(None, description="Group IDs to assign")
# Status flags
is_active: Optional[bool] = Field(None, alias="isActive", description="Whether user is active")
is_verified: Optional[bool] = Field(None, alias="isVerified", description="Whether email is verified")
@field_validator("name")
@classmethod
def validate_name(cls, v: Optional[str]) -> Optional[str]:
"""Validate user name if provided."""
if v is None:
return v
if not v.strip():
raise ValueError("Name cannot be empty")
if len(v) < 2:
raise ValueError("Name must be at least 2 characters long")
if len(v) > 255:
raise ValueError("Name cannot exceed 255 characters")
return v.strip()
@field_validator("password_raw")
@classmethod
def validate_password(cls, v: Optional[str]) -> Optional[str]:
"""Validate password strength if provided."""
if v is None:
return v
if len(v) < 6:
raise ValueError("Password must be at least 6 characters long")
if len(v) > 255:
raise ValueError("Password cannot exceed 255 characters")
return v
model_config = ConfigDict(populate_by_name=True, str_strip_whitespace=True)