36 lines
1.1 KiB
Python
36 lines
1.1 KiB
Python
from __future__ import annotations
|
|
|
|
from urllib.parse import urlparse
|
|
|
|
from app.services.scholars.constants import MAX_IMAGE_URL_LENGTH, SCHOLAR_ID_PATTERN
|
|
from app.services.scholars.exceptions import ScholarServiceError
|
|
|
|
|
|
def validate_scholar_id(value: str) -> str:
|
|
scholar_id = value.strip()
|
|
if not SCHOLAR_ID_PATTERN.fullmatch(scholar_id):
|
|
raise ScholarServiceError("Scholar ID must match [a-zA-Z0-9_-]{12}.")
|
|
return scholar_id
|
|
|
|
|
|
def normalize_display_name(value: str) -> str | None:
|
|
normalized = value.strip()
|
|
return normalized if normalized else None
|
|
|
|
|
|
def normalize_profile_image_url(value: str | None) -> str | None:
|
|
if value is None:
|
|
return None
|
|
|
|
candidate = value.strip()
|
|
if not candidate:
|
|
return None
|
|
|
|
if len(candidate) > MAX_IMAGE_URL_LENGTH:
|
|
raise ScholarServiceError(f"Image URL must be {MAX_IMAGE_URL_LENGTH} characters or fewer.")
|
|
|
|
parsed = urlparse(candidate)
|
|
if parsed.scheme.lower() not in {"http", "https"} or not parsed.netloc:
|
|
raise ScholarServiceError("Image URL must be an absolute http(s) URL.")
|
|
|
|
return candidate
|