first deployment of kikomiko with url photos

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
shayan khoshrou
2026-10-19 19:10:57 +02:00
co-authored by Cursor
parent 8d98304137
commit ae3ed7c7b7
159 changed files with 59509 additions and 0 deletions
+52
View File
@@ -0,0 +1,52 @@
"""Pluggable product fetch / stock-sync scripts for the admin CMS.
Each fetcher module must expose:
NAME: str
DESCRIPTION: str
fetch_products(config: dict) -> list[dict]
sync_stocks(config: dict, products: list[dict]) -> list[dict]
Product dict keys (camelCase or snake_case accepted by importer):
id, slug, name, nameFa/name_fa, price, compareAtPrice/compare_at_price,
stock, heroImage/hero_image, category, categoryFa/category_fa,
description, sku, externalId/external_id, colorVariants/color_variants,
source
Each colorVariants item may include:
id, slug, name, shade, colorHex, price, compareAtPrice, stock,
heroImage, sku, externalId, images[]
"""
from __future__ import annotations
import importlib
import pkgutil
from pathlib import Path
_PACKAGE = Path(__file__).resolve().parent
def list_fetchers():
items = []
for mod in pkgutil.iter_modules([str(_PACKAGE)]):
if mod.name.startswith("_"):
continue
module = importlib.import_module(f"fetchers.{mod.name}")
if not hasattr(module, "NAME"):
continue
items.append(
{
"id": mod.name,
"name": getattr(module, "NAME"),
"description": getattr(module, "DESCRIPTION", ""),
"supports_fetch": callable(getattr(module, "fetch_products", None)),
"supports_sync": callable(getattr(module, "sync_stocks", None)),
}
)
return sorted(items, key=lambda x: x["id"])
def get_fetcher(fetcher_id: str):
if not fetcher_id or "/" in fetcher_id or ".." in fetcher_id:
raise ValueError("invalid fetcher id")
return importlib.import_module(f"fetchers.{fetcher_id}")