Prepare ERP source for Gitea deployment

This commit is contained in:
A R R R Associates
2026-06-20 15:01:44 +05:30
commit 5c75eb6bd9
450 changed files with 67698 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
from __future__ import annotations
import imghdr
import re
from pathlib import Path
from uuid import uuid4
from fastapi import HTTPException, UploadFile
from sqlalchemy.orm import Session
from app.modules.core.iam.models import User
STATIC_ROOT = Path("app/ui/static")
PROFILE_UPLOAD_DIR = STATIC_ROOT / "uploads" / "user_profiles"
MAX_IMAGE_BYTES = 2 * 1024 * 1024
ALLOWED_IMAGE_TYPES = {"jpeg": ".jpg", "png": ".png", "gif": ".gif", "webp": ".webp"}
def _blank_to_none(value: object) -> str | None:
value = (str(value).strip() if value is not None else "")
return value or None
def _safe_static_path(path: str | None) -> str | None:
path = (path or "").strip()
if not path:
return None
if path.startswith("/static/"):
return path
if path.startswith("app/ui/static/"):
return "/static/" + path.split("app/ui/static/", 1)[1].replace("\\", "/")
return path
def profile_photo_url(user: User | None) -> str | None:
if not user:
return None
return _safe_static_path(getattr(user, "profile_photo_path", None))
def user_initials(user: User | None) -> str:
if not user:
return "U"
name = (getattr(user, "full_name", None) or getattr(user, "email", "") or "User").strip()
if "@" in name and not getattr(user, "full_name", None):
name = name.split("@", 1)[0]
parts = [p for p in re.split(r"\s+", name) if p]
if not parts:
return "U"
if len(parts) == 1:
return parts[0][:2].upper()
return (parts[0][0] + parts[-1][0]).upper()
async def save_user_profile_photo(user: User, upload: UploadFile | None) -> str | None:
"""Persist a profile photo and return a static path, or current path if nothing uploaded."""
if not upload or not getattr(upload, "filename", None):
return getattr(user, "profile_photo_path", None)
raw = await upload.read()
if not raw:
return getattr(user, "profile_photo_path", None)
if len(raw) > MAX_IMAGE_BYTES:
raise HTTPException(status_code=400, detail="Profile photo must be 2 MB or smaller.")
detected = imghdr.what(None, raw)
suffix = ALLOWED_IMAGE_TYPES.get(detected or "")
if not suffix:
raise HTTPException(status_code=400, detail="Upload a valid JPG, PNG, GIF or WebP profile photo.")
PROFILE_UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
filename = f"user_{user.id}_{uuid4().hex}{suffix}"
target = PROFILE_UPLOAD_DIR / filename
target.write_bytes(raw)
return f"app/ui/static/uploads/user_profiles/{filename}"
def update_user_public_profile(
db: Session,
user: User,
*,
qualification: object = None,
designation: object = None,
mobile: object = None,
bio: object = None,
profile_photo_path: str | None = None,
) -> User:
user.qualification = _blank_to_none(qualification)
user.designation = _blank_to_none(designation)
user.mobile = _blank_to_none(mobile)
user.bio = _blank_to_none(bio)
if profile_photo_path is not None:
user.profile_photo_path = profile_photo_path
db.add(user)
return user