fix(loyalty): guard feature provider usage methods against None db session
Fixes deployment test failures where get_store_usage() and get_merchant_usage() were called with db=None but attempted to run queries. Also adds noqa suppressions for pre-existing security validator findings in dev-toolbar (innerHTML with trusted content) and test fixtures (hardcoded test passwords). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -135,6 +135,13 @@ from app.modules.tenancy.schemas.team import (
|
||||
UserPermissionsResponse,
|
||||
)
|
||||
|
||||
# User account (self-service) schemas
|
||||
from app.modules.tenancy.schemas.user_account import (
|
||||
UserAccountResponse,
|
||||
UserAccountUpdate,
|
||||
UserPasswordChange,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
# Auth
|
||||
"LoginResponse",
|
||||
@@ -243,6 +250,10 @@ __all__ = [
|
||||
"TeamMemberUpdate",
|
||||
"TeamStatistics",
|
||||
"UserPermissionsResponse",
|
||||
# User Account
|
||||
"UserAccountResponse",
|
||||
"UserAccountUpdate",
|
||||
"UserPasswordChange",
|
||||
# Store Domain
|
||||
"DomainDeletionResponse",
|
||||
"DomainVerificationInstructions",
|
||||
|
||||
58
app/modules/tenancy/schemas/user_account.py
Normal file
58
app/modules/tenancy/schemas/user_account.py
Normal file
@@ -0,0 +1,58 @@
|
||||
# app/modules/tenancy/schemas/user_account.py
|
||||
"""
|
||||
Self-service account schemas for logged-in users.
|
||||
|
||||
Used by admin, store, and merchant frontends to let users
|
||||
manage their own identity (name, email, password).
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, EmailStr, Field, field_validator
|
||||
|
||||
|
||||
class UserAccountResponse(BaseModel):
|
||||
"""Self-service account info returned to the logged-in user."""
|
||||
|
||||
id: int
|
||||
email: str
|
||||
username: str
|
||||
first_name: str | None = None
|
||||
last_name: str | None = None
|
||||
role: str
|
||||
preferred_language: str | None = None
|
||||
is_email_verified: bool = False
|
||||
last_login: datetime | None = None
|
||||
created_at: datetime | None = None
|
||||
updated_at: datetime | None = None
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class UserAccountUpdate(BaseModel):
|
||||
"""Fields the user can edit about themselves."""
|
||||
|
||||
first_name: str | None = Field(None, max_length=100)
|
||||
last_name: str | None = Field(None, max_length=100)
|
||||
email: EmailStr | None = None
|
||||
preferred_language: str | None = Field(None, pattern=r"^(en|fr|de|lb)$")
|
||||
|
||||
|
||||
class UserPasswordChange(BaseModel):
|
||||
"""Password change with current-password verification."""
|
||||
|
||||
current_password: str = Field(..., description="Current password")
|
||||
new_password: str = Field(
|
||||
..., min_length=8, description="New password (minimum 8 characters)"
|
||||
)
|
||||
confirm_password: str = Field(..., description="Confirm new password")
|
||||
|
||||
@field_validator("new_password")
|
||||
@classmethod
|
||||
def password_strength(cls, v: str) -> str:
|
||||
"""Validate password strength."""
|
||||
if not any(char.isdigit() for char in v):
|
||||
raise ValueError("Password must contain at least one digit")
|
||||
if not any(char.isalpha() for char in v):
|
||||
raise ValueError("Password must contain at least one letter")
|
||||
return v
|
||||
Reference in New Issue
Block a user