99 lines
3.4 KiB
Python
99 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
"""批量:上传本地图到文件服务,并把完整URL写回CMS记录的 image 字段。
|
|
用法: python3 cms_fill_image.py <mapping.json> <result.json>
|
|
mapping.json: [{"module":"cms-article","id":10570,"file":"/path/to/img.png"}, ...]
|
|
"""
|
|
import os, json, sys, subprocess, time, urllib.request, urllib.error
|
|
|
|
TOKEN = os.environ.get("TOKEN", "")
|
|
UPLOAD = "https://server.websoft.top/api/file/upload"
|
|
CMS = "https://hjc-api.websoft.top/api"
|
|
FILE_BASE = "https://file.websoft.top/api/file/"
|
|
HDR = {"TenantId": "10626", "Authorization": "Bearer " + TOKEN}
|
|
|
|
|
|
def _retry(fn, tries=4, sleep=2):
|
|
last = None
|
|
for i in range(tries):
|
|
try:
|
|
return fn()
|
|
except Exception as e:
|
|
last = e
|
|
time.sleep(sleep * (i + 1))
|
|
raise last
|
|
|
|
|
|
def upload(local_path: str) -> str:
|
|
def _do():
|
|
out = subprocess.run(
|
|
["curl", "-s", "-m", "60", "-X", "POST", UPLOAD,
|
|
"-H", "TenantId: 10626", "-H", f"Authorization: Bearer {TOKEN}",
|
|
"-F", f"file=@{local_path}"],
|
|
capture_output=True, text=True,
|
|
)
|
|
try:
|
|
d = json.loads(out.stdout)
|
|
except Exception:
|
|
raise RuntimeError(f"upload non-json: {out.stdout[:200]}")
|
|
if d.get("code") != 0:
|
|
raise RuntimeError(f"upload code={d.get('code')} msg={d.get('message')} err={str(d.get('error'))[:120]}")
|
|
p = (d.get("data") or {}).get("path", "").lstrip("/")
|
|
if not p:
|
|
raise RuntimeError("upload returned empty path")
|
|
return FILE_BASE + p
|
|
return _retry(_do)
|
|
|
|
|
|
def get_item(module: str, id_: int):
|
|
def _do():
|
|
url = f"{CMS}/cms/{module}/{id_}"
|
|
req = urllib.request.Request(url, headers=HDR)
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=30) as r:
|
|
return json.loads(r.read())["data"]
|
|
except urllib.error.HTTPError as e:
|
|
body = e.read()[:300]
|
|
raise RuntimeError(f"GET {url} -> HTTP {e.code}: {body}")
|
|
return _retry(_do)
|
|
|
|
|
|
def put_item(module: str, obj: dict):
|
|
def _do():
|
|
url = f"{CMS}/cms/{module}"
|
|
req = urllib.request.Request(
|
|
url, data=json.dumps(obj).encode(),
|
|
headers={**HDR, "Content-Type": "application/json"}, method="PUT",
|
|
)
|
|
with urllib.request.urlopen(req, timeout=30) as r:
|
|
return json.loads(r.read())
|
|
return _retry(_do)
|
|
|
|
|
|
def main():
|
|
mapping = json.load(open(sys.argv[1]))
|
|
result_path = sys.argv[2] if len(sys.argv) > 2 else "/tmp/fill_result.json"
|
|
results = []
|
|
for it in mapping:
|
|
mod, iid, fpath = it["module"], it["id"], it["file"]
|
|
rec = {"module": mod, "id": iid}
|
|
try:
|
|
url = upload(fpath)
|
|
obj = get_item(mod, iid)
|
|
obj["image"] = url
|
|
out = put_item(mod, obj)
|
|
rec["url"] = url
|
|
rec["put_code"] = out.get("code")
|
|
rec["ok"] = out.get("code") == 0
|
|
print(f"[{mod} {iid}] upload OK -> PUT code={out.get('code')} {'OK' if rec['ok'] else 'FAIL'} | {url[:70]}")
|
|
except Exception as e:
|
|
rec["error"] = str(e)[:300]
|
|
print(f"[{mod} {iid}] ERROR: {e}")
|
|
results.append(rec)
|
|
time.sleep(1)
|
|
json.dump(results, open(result_path, "w"), ensure_ascii=False, indent=2)
|
|
print(f"\n=== done {len(results)} items, saved {result_path} ===")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|