refactor: translate all docstrings and comments to English (STRICT ENGLISH POLICY complete)

This commit is contained in:
Daniel Bedeleanu
2026-04-11 14:26:55 +03:00
parent 54b40c9d37
commit 9dbe0f8b6c
6 changed files with 37 additions and 37 deletions

View File

@@ -1,6 +1,6 @@
""" """
[C-01] JWT Authentication Module [C-01] JWT Authentication Module
Implementare Bearer token authentication pentru API endpoints. Implement Bearer token authentication for API endpoints.
""" """
import os import os
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
@@ -13,7 +13,7 @@ from pydantic import BaseModel
# Configuration # Configuration
SECRET_KEY = os.environ.get("JWT_SECRET_KEY") SECRET_KEY = os.environ.get("JWT_SECRET_KEY")
if not SECRET_KEY: if not SECRET_KEY:
# Genereaza o cheie de fallback pentru dev (NU PENTRU PRODUCȚIE) # Generate fallback key for dev (NOT FOR PRODUCTION)
import secrets import secrets
SECRET_KEY = secrets.token_urlsafe(32) SECRET_KEY = secrets.token_urlsafe(32)
import sys import sys
@@ -60,8 +60,8 @@ def create_access_token(user_id: int, username: str, role: str, expires_delta: O
async def get_current_user(credentials: HTTPAuthCredentials = Depends(security)): async def get_current_user(credentials: HTTPAuthCredentials = Depends(security)):
""" """
Dependency que valideaza JWT token din Authorization header. Dependency that validates JWT token from Authorization header.
Returneaza TokenData cu user_id, username, role. Returns TokenData with user_id, username, role.
""" """
token = credentials.credentials token = credentials.credentials
try: try:
@@ -91,7 +91,7 @@ async def get_current_user(credentials: HTTPAuthCredentials = Depends(security))
async def get_current_admin(current_user: TokenData = Depends(get_current_user)): async def get_current_admin(current_user: TokenData = Depends(get_current_user)):
"""Dependency que verifica daca user-ul are rol 'admin'.""" """Dependency that checks if user has 'admin' role."""
if current_user.role != "admin": if current_user.role != "admin":
raise HTTPException( raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, status_code=status.HTTP_403_FORBIDDEN,

View File

@@ -21,8 +21,8 @@ app.state.limiter = limiter
app.add_exception_handler = limiter.add_exception_handler app.add_exception_handler = limiter.add_exception_handler
# [SECURITY FIX M-01] CORS: allow_origins=["*"] + allow_credentials=True is invalid per spec. # [SECURITY FIX M-01] CORS: allow_origins=["*"] + allow_credentials=True is invalid per spec.
# Originile permise se configurează via variabila de mediu ALLOWED_ORIGINS (comma-separated). # Allowed origins are configured via ALLOWED_ORIGINS environment variable (comma-separated).
# Fallback sigur: doar localhost pentru development. # Secure fallback: localhost only for development.
_raw_origins = os.environ.get( _raw_origins = os.environ.get(
"ALLOWED_ORIGINS", "ALLOWED_ORIGINS",
"http://localhost:3000,http://localhost:3002" "http://localhost:3000,http://localhost:3002"

View File

@@ -17,7 +17,7 @@ def get_categories(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Lista categoriidoar utilizatori autentificati.""" """[C-01] List of categoriesonly for authenticated users."""
categories = db.query(models.Category).all() categories = db.query(models.Category).all()
# Auto-seed if empty with defaults mentioned by user # Auto-seed if empty with defaults mentioned by user
if not categories: if not categories:
@@ -40,7 +40,7 @@ def create_category(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Creare categoriedoar utilizatori autentificati.""" """[C-01] Create categoryonly for authenticated users."""
existing = db.query(models.Category).filter(models.Category.name == category.name).first() existing = db.query(models.Category).filter(models.Category.name == category.name).first()
if existing: if existing:
raise HTTPException(status_code=400, detail="Category already exists") raise HTTPException(status_code=400, detail="Category already exists")
@@ -58,7 +58,7 @@ def update_category(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Actualizare categoriedoar utilizatori autentificati.""" """[C-01] Update categoryonly for authenticated users."""
db_cat = db.query(models.Category).filter(models.Category.id == cat_id).first() db_cat = db.query(models.Category).filter(models.Category.id == cat_id).first()
if not db_cat: if not db_cat:
raise HTTPException(status_code=404, detail="Category not found") raise HTTPException(status_code=404, detail="Category not found")
@@ -77,7 +77,7 @@ def delete_category(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Ștergere categoriedoar utilizatori autentificati.""" """[C-01] Delete categoryonly for authenticated users."""
cat = db.query(models.Category).filter(models.Category.id == cat_id).first() cat = db.query(models.Category).filter(models.Category.id == cat_id).first()
if not cat: if not cat:
raise HTTPException(status_code=404, detail="Category not found") raise HTTPException(status_code=404, detail="Category not found")

View File

@@ -7,7 +7,7 @@ from slowapi.util import get_remote_address
from .. import models, schemas, auth from .. import models, schemas, auth
from ..database import get_db from ..database import get_db
# [H-02] Rate limiter pentru extract-label endpoint # [H-02] Rate limiter for extract-label endpoint
limiter = Limiter(key_func=get_remote_address) limiter = Limiter(key_func=get_remote_address)
router = APIRouter( router = APIRouter(
@@ -20,7 +20,7 @@ def read_item_stats(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Statistici iteme — doar utilizatori autentificati.""" """[C-01] Item statistics — only for authenticated users."""
total_categories = db.query(models.Category).count() total_categories = db.query(models.Category).count()
total_items = db.query(models.Item).count() total_items = db.query(models.Item).count()
@@ -41,7 +41,7 @@ def read_items(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Lista itemedoar utilizatori autentificati.""" """[C-01] List of itemsonly for authenticated users."""
items = db.query(models.Item).offset(skip).limit(limit).all() items = db.query(models.Item).offset(skip).limit(limit).all()
return items return items
@@ -51,7 +51,7 @@ def read_item(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Obține item — doar utilizatori autentificati.""" """[C-01] Get item — only for authenticated users."""
item = db.query(models.Item).filter(models.Item.id == item_id).first() item = db.query(models.Item).filter(models.Item.id == item_id).first()
if item is None: if item is None:
raise HTTPException(status_code=404, detail="Item not found") raise HTTPException(status_code=404, detail="Item not found")
@@ -66,14 +66,14 @@ async def extract_label(
file: UploadFile = File(...), file: UploadFile = File(...),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Extragere etichetă din imagine — doar utilizatori autentificati. [H-02] Rate limit: 10 req/min per IP.""" """[C-01] Extract label from image — only for authenticated users. [H-02] Rate limit: 10 req/min per IP."""
from ..ai_vision import extract_label_info from ..ai_vision import extract_label_info
# [SECURITY FIX H-03] Validare tip MIME și dimensiune maximă # [SECURITY FIX H-03] Validare tip MIME și dimensiune maximă
if file.content_type not in _ALLOWED_IMAGE_TYPES: if file.content_type not in _ALLOWED_IMAGE_TYPES:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE, status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
detail=f"Tip fișier nepermis: {file.content_type}. Acceptat: {', '.join(_ALLOWED_IMAGE_TYPES)}" detail=f"File type not allowed: {file.content_type}. Accepted: {', '.join(_ALLOWED_IMAGE_TYPES)}"
) )
contents = await file.read() contents = await file.read()
@@ -81,7 +81,7 @@ async def extract_label(
if len(contents) > _MAX_IMAGE_SIZE: if len(contents) > _MAX_IMAGE_SIZE:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
detail="Fișierul depășește limita de 10MB." detail="File exceeds 10MB limit."
) )
result = extract_label_info(contents) result = extract_label_info(contents)
@@ -93,7 +93,7 @@ def create_item(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Creare item — doar utilizatori autentificati. [M-02] user_id din token.""" """[C-01] Create item — only for authenticated users. [M-02] user_id from token."""
# Check if barcode exists # Check if barcode exists
db_item = db.query(models.Item).filter(models.Item.barcode == item.barcode).first() db_item = db.query(models.Item).filter(models.Item.barcode == item.barcode).first()
if db_item: if db_item:
@@ -104,7 +104,7 @@ def create_item(
db.commit() db.commit()
db.refresh(db_item) db.refresh(db_item)
# Audit log the creation — [M-02] user_id din token, nu din body # Audit log the creation — [M-02] user_id from token, not from body
audit = models.AuditLog( audit = models.AuditLog(
user_id=current_user.sub, user_id=current_user.sub,
action="CREATE_ITEM", action="CREATE_ITEM",
@@ -123,7 +123,7 @@ def update_item(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Actualizare item — doar utilizatori autentificati.""" """[C-01] Update item — only for authenticated users."""
db_item = db.query(models.Item).filter(models.Item.id == item_id).first() db_item = db.query(models.Item).filter(models.Item.id == item_id).first()
if not db_item: if not db_item:
raise HTTPException(status_code=404, detail="Item not found") raise HTTPException(status_code=404, detail="Item not found")
@@ -142,7 +142,7 @@ def delete_item(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Ștergere item — doar utilizatori autentificati.""" """[C-01] Delete item — only for authenticated users."""
db_item = db.query(models.Item).filter(models.Item.id == item_id).first() db_item = db.query(models.Item).filter(models.Item.id == item_id).first()
if not db_item: if not db_item:
raise HTTPException(status_code=404, detail="Item not found") raise HTTPException(status_code=404, detail="Item not found")

View File

@@ -15,7 +15,7 @@ def check_in_item(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Check-in item — doar utilizatori autentificati. [M-02] user_id din token.""" """[C-01] Check-in item — only for authenticated users. [M-02] user_id from token."""
if op.quantity <= 0: if op.quantity <= 0:
raise HTTPException(status_code=400, detail="Quantity must be greater than zero") raise HTTPException(status_code=400, detail="Quantity must be greater than zero")
@@ -26,7 +26,7 @@ def check_in_item(
# Update quantity # Update quantity
item.quantity += op.quantity item.quantity += op.quantity
# Create Mandatory Audit Log — [M-02] user_id din token # Create Mandatory Audit Log — [M-02] user_id from token
audit = models.AuditLog( audit = models.AuditLog(
user_id=current_user.sub, user_id=current_user.sub,
action="CHECK_IN", action="CHECK_IN",
@@ -45,7 +45,7 @@ def check_out_item(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Check-out item — doar utilizatori autentificati.""" """[C-01] Check-out item — only for authenticated users."""
if op.quantity <= 0: if op.quantity <= 0:
raise HTTPException(status_code=400, detail="Quantity must be greater than zero") raise HTTPException(status_code=400, detail="Quantity must be greater than zero")
@@ -78,7 +78,7 @@ def trash_item(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Trash item — doar utilizatori autentificati.""" """[C-01] Trash item — only for authenticated users."""
if op.quantity <= 0: if op.quantity <= 0:
raise HTTPException(status_code=400, detail="Quantity must be greater than zero") raise HTTPException(status_code=400, detail="Quantity must be greater than zero")
@@ -112,7 +112,7 @@ def bulk_check_out(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Bulk check-out — doar utilizatori autentificati.""" """[C-01] Bulk check-out — only for authenticated users."""
results = {"success": [], "errors": []} results = {"success": [], "errors": []}
for op in bulk_op.items: for op in bulk_op.items:
@@ -151,7 +151,7 @@ def bulk_sync(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Bulk sync offline operations — doar utilizatori autentificati.""" """[C-01] Bulk sync offline operations — only for authenticated users."""
results = {"success": [], "errors": []} results = {"success": [], "errors": []}
for op in payload.operations: for op in payload.operations:
@@ -206,7 +206,7 @@ def get_logs(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user) current_user: auth.TokenData = Depends(auth.get_current_user)
): ):
"""[C-01] Lista audit logs — doar utilizatori autentificati.""" """[C-01] Audit logs list — only for authenticated users."""
# Join with User to get the username directly # Join with User to get the username directly
logs_with_users = db.query( logs_with_users = db.query(
models.AuditLog.id, models.AuditLog.id,

View File

@@ -129,7 +129,7 @@ def get_users(
db.add(new_user) db.add(new_user)
db.commit() db.commit()
db.refresh(new_user) db.refresh(new_user)
log.warning(f"[SECURITY] Admin initial seeded. Temporary password: {initial_password}SCHIMBAȚI IMEDIAT!") log.warning(f"[SECURITY] Admin initial seeded. Temporary password: {initial_password} — CHANGE IMMEDIATELY!")
return [new_user] return [new_user]
return users return users
@@ -139,7 +139,7 @@ def create_user(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_admin) current_user: auth.TokenData = Depends(auth.get_current_admin)
): ):
"""[C-01] Creare utilizator — doar admin.""" """[C-01] Create user — admin only."""
existing = db.query(models.User).filter(models.User.username == user.username).first() existing = db.query(models.User).filter(models.User.username == user.username).first()
if existing: if existing:
raise HTTPException(status_code=400, detail="Username already exists") raise HTTPException(status_code=400, detail="Username already exists")
@@ -154,7 +154,7 @@ def create_user(
@router.post("/login", response_model=schemas.TokenResponse) @router.post("/login", response_model=schemas.TokenResponse)
def login(form_data: schemas.UserLogin, db: Session = Depends(get_db)): def login(form_data: schemas.UserLogin, db: Session = Depends(get_db)):
""" """
[C-01] Login endpoint: validează credențiale și returnează JWT token Bearer. [C-01] Login endpoint: validates credentials and returns JWT Bearer token.
""" """
user = db.query(models.User).filter(models.User.username == form_data.username).first() user = db.query(models.User).filter(models.User.username == form_data.username).first()
@@ -199,7 +199,7 @@ def login(form_data: schemas.UserLogin, db: Session = Depends(get_db)):
if not authenticated or not user: if not authenticated or not user:
raise HTTPException(status_code=401, detail="Invalid username or password") raise HTTPException(status_code=401, detail="Invalid username or password")
# [C-01] Generare JWT token # [C-01] Generate JWT token
token = auth.create_access_token( token = auth.create_access_token(
user_id=user.id, user_id=user.id,
username=user.username, username=user.username,
@@ -221,7 +221,7 @@ def update_user(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_admin) current_user: auth.TokenData = Depends(auth.get_current_admin)
): ):
"""[C-01] Actualizare utilizator — doar admin.""" """[C-01] Update user — admin only."""
db_user = db.query(models.User).filter(models.User.id == user_id).first() db_user = db.query(models.User).filter(models.User.id == user_id).first()
if not db_user: if not db_user:
raise HTTPException(status_code=404, detail="User not found") raise HTTPException(status_code=404, detail="User not found")
@@ -248,7 +248,7 @@ def update_user(
@router.get("/ldap-config") @router.get("/ldap-config")
def get_ldap_settings(current_user: auth.TokenData = Depends(auth.get_current_admin)): def get_ldap_settings(current_user: auth.TokenData = Depends(auth.get_current_admin)):
"""[C-01] Obține config LDAP — doar admin.""" """[C-01] Get LDAP config — admin only."""
return get_ldap_config() return get_ldap_config()
@router.post("/ldap-config") @router.post("/ldap-config")
@@ -256,7 +256,7 @@ def update_ldap_settings(
config: dict, config: dict,
current_user: auth.TokenData = Depends(auth.get_current_admin) current_user: auth.TokenData = Depends(auth.get_current_admin)
): ):
"""[C-01] Actualizează config LDAP — doar admin.""" """[C-01] Update LDAP config — admin only."""
config_path = os.path.join(database.DATA_DIR, "ldap_config.json") config_path = os.path.join(database.DATA_DIR, "ldap_config.json")
with open(config_path, "w") as f: with open(config_path, "w") as f:
json.dump(config, f) json.dump(config, f)
@@ -320,7 +320,7 @@ def delete_user(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_admin) current_user: auth.TokenData = Depends(auth.get_current_admin)
): ):
"""[C-01] Ștergere utilizator — doar admin.""" """[C-01] Delete user — admin only."""
user = db.query(models.User).filter(models.User.id == user_id).first() user = db.query(models.User).filter(models.User.id == user_id).first()
if not user: if not user:
raise HTTPException(status_code=404, detail="User not found") raise HTTPException(status_code=404, detail="User not found")