Implementare completă a autentificării Bearer token:
- Creiez backend/auth.py: funcții JWT (create_access_token, get_current_user, get_current_admin)
- Modific /users/login: returnează TokenResponse cu JWT token și expirare 8h
- Adaug Depends(get_current_user) pe toate endpoint-urile API
- [M-02] user_id extras din JWT token, nu din request body
- [L-01] Token cu exp claim pentru sesiuni frontend
Acces endpoints-uri:
- GET/POST /users/: authenticated users
- POST /users/: admin only
- PUT /users/{id}, DELETE /users/{id}, /ldap-config, /test-ldap: admin only
- Toți routers (items, operations, categories): authenticated users minimum
Modificări dependențe:
- Adaug: python-jose[cryptography]>=3.3.0, slowapi>=0.1.9 (pentru H-02 rate limiting)
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
119 lines
2.4 KiB
Python
119 lines
2.4 KiB
Python
from pydantic import BaseModel
|
|
from typing import Optional, List
|
|
from datetime import datetime
|
|
|
|
# --- Users ---
|
|
class UserBase(BaseModel):
|
|
username: str
|
|
role: str = "user"
|
|
origin: str = "local"
|
|
|
|
class UserCreate(UserBase):
|
|
password: Optional[str] = None
|
|
|
|
class User(UserBase):
|
|
id: int
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
class UserUpdate(BaseModel):
|
|
username: Optional[str] = None
|
|
password: Optional[str] = None
|
|
role: Optional[str] = None
|
|
|
|
class UserLogin(BaseModel):
|
|
username: str
|
|
password: str
|
|
|
|
class UserPasswordUpdate(BaseModel):
|
|
old_password: Optional[str] = None
|
|
new_password: str
|
|
|
|
class TokenResponse(BaseModel):
|
|
access_token: str
|
|
token_type: str = "bearer"
|
|
user_id: int
|
|
username: str
|
|
role: str
|
|
|
|
# --- Categories ---
|
|
class CategoryBase(BaseModel):
|
|
name: str
|
|
description: Optional[str] = None
|
|
|
|
class CategoryCreate(CategoryBase):
|
|
pass
|
|
|
|
class Category(CategoryBase):
|
|
id: int
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
# --- Items ---
|
|
class ItemBase(BaseModel):
|
|
name: str
|
|
category: str
|
|
category_id: Optional[int] = None
|
|
type: Optional[str] = None
|
|
barcode: str
|
|
part_number: Optional[str] = None
|
|
color: Optional[str] = None
|
|
specs: Optional[str] = None
|
|
quantity: float = 0.0
|
|
min_quantity: float = 1.0
|
|
image_url: Optional[str] = None
|
|
labels_data: Optional[str] = None
|
|
|
|
class ItemCreate(ItemBase):
|
|
pass
|
|
|
|
class Item(ItemBase):
|
|
id: int
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
# --- Operations (Check-in/Check-out Validation) ---
|
|
class OperationCreate(BaseModel):
|
|
barcode: str
|
|
quantity: float
|
|
user_id: int
|
|
|
|
class BulkOperationCreate(BaseModel):
|
|
user_id: int
|
|
items: List[OperationCreate]
|
|
|
|
class TrashOperationCreate(BaseModel):
|
|
barcode: str
|
|
quantity: float
|
|
user_id: int
|
|
reason: Optional[str] = "unspecified"
|
|
|
|
# --- Sync ---
|
|
class SyncOperation(BaseModel):
|
|
type: str # 'CHECK_IN', 'CHECK_OUT'
|
|
barcode: str
|
|
quantity: float
|
|
uuid: Optional[str] = None
|
|
timestamp: datetime
|
|
|
|
class SyncPayload(BaseModel):
|
|
user_id: int
|
|
operations: List[SyncOperation]
|
|
|
|
# --- Audit Logs ---
|
|
class AuditLogResponse(BaseModel):
|
|
id: int
|
|
timestamp: datetime
|
|
user_id: int
|
|
username: Optional[str] = None
|
|
action: str
|
|
target_item_id: Optional[int]
|
|
quantity_change: Optional[float]
|
|
details: Optional[str] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|