feat(dash): connection testing — Discogs / Woo / DealGod
POST /settings/test/{service} validates stored creds against the live service
(Discogs identity, Woo orders, DealGod /api/me) so "connected" means connected.
Dash gets per-service Test buttons with green/amber status.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
834c549d5e
commit
0e8c84b0e7
@ -1,3 +1,6 @@
|
|||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
import httpx
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
@ -46,3 +49,45 @@ async def save_secret(body: SecretIn, ident=Depends(require_token), db=Depends(g
|
|||||||
except vault.SecretsUnconfigured as e:
|
except vault.SecretsUnconfigured as e:
|
||||||
raise HTTPException(503, str(e))
|
raise HTTPException(503, str(e))
|
||||||
return {"ok": True, "name": body.name, "set": True}
|
return {"ok": True, "name": body.name, "set": True}
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/test/{service}")
|
||||||
|
async def test_connection(service: str, ident=Depends(require_token), db=Depends(get_db)):
|
||||||
|
"""Validate stored credentials against the live service — so 'connected' means connected."""
|
||||||
|
async with httpx.AsyncClient(timeout=15, follow_redirects=True) as c:
|
||||||
|
if service == "discogs":
|
||||||
|
tok = await vault.get_secret(db, "discogs_token")
|
||||||
|
if not tok:
|
||||||
|
raise HTTPException(400, "save a Discogs personal access token first")
|
||||||
|
r = await c.get("https://api.discogs.com/oauth/identity",
|
||||||
|
headers={"Authorization": f"Discogs token={tok}",
|
||||||
|
"User-Agent": "RecordGod/0.1"})
|
||||||
|
if r.status_code == 200:
|
||||||
|
return {"ok": True, "connected": True, "as": r.json().get("username")}
|
||||||
|
return {"ok": True, "connected": False, "detail": f"HTTP {r.status_code}"}
|
||||||
|
|
||||||
|
if service == "woo":
|
||||||
|
base = await vault.get_secret(db, "woo_base_url")
|
||||||
|
ck = await vault.get_secret(db, "woo_consumer_key")
|
||||||
|
cs = await vault.get_secret(db, "woo_consumer_secret")
|
||||||
|
if not (base and ck and cs):
|
||||||
|
raise HTTPException(400, "save Woo store URL + consumer key + secret first")
|
||||||
|
r = await c.get(base.rstrip("/") + "/wp-json/wc/v3/orders",
|
||||||
|
params={"per_page": 1}, auth=(ck, cs))
|
||||||
|
if r.status_code == 200:
|
||||||
|
return {"ok": True, "connected": True, "as": urlparse(base).netloc}
|
||||||
|
return {"ok": True, "connected": False, "detail": f"HTTP {r.status_code}"}
|
||||||
|
|
||||||
|
if service == "dealgod":
|
||||||
|
key = await vault.get_secret(db, "dealgod_api_key")
|
||||||
|
if not key:
|
||||||
|
raise HTTPException(400, "save a DealGod API key first")
|
||||||
|
r = await c.get("https://api.dealgod.pro/api/me", headers={"X-Api-Key": key})
|
||||||
|
if r.status_code == 200:
|
||||||
|
j = r.json()
|
||||||
|
return {"ok": True, "connected": True, "as": f"{j.get('user')} · {j.get('plan')}"}
|
||||||
|
if r.status_code == 404:
|
||||||
|
return {"ok": True, "connected": False, "detail": "DealGod /api/me not deployed yet"}
|
||||||
|
return {"ok": True, "connected": False, "detail": f"HTTP {r.status_code}"}
|
||||||
|
|
||||||
|
raise HTTPException(400, "unknown service")
|
||||||
|
|||||||
@ -48,13 +48,17 @@
|
|||||||
<div id="secrets"></div>
|
<div id="secrets"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h2>Orders (WooCommerce)</h2>
|
<h2>Connections <span class="soon">— save the keys above, then test</span></h2>
|
||||||
<p class="soon">Save your Woo store URL + consumer key/secret above, then live orders land here —
|
<div style="display:flex;gap:10px;align-items:center;margin:9px 0">
|
||||||
managed without wp-admin. (Coming next.)</p>
|
<button class="ghost" onclick="testConn('discogs')">Test Discogs</button><span id="c-discogs" class="soon"></span></div>
|
||||||
|
<div style="display:flex;gap:10px;align-items:center;margin:9px 0">
|
||||||
|
<button class="ghost" onclick="testConn('woo')">Test WooCommerce</button><span id="c-woo" class="soon"></span></div>
|
||||||
|
<div style="display:flex;gap:10px;align-items:center;margin:9px 0">
|
||||||
|
<button class="ghost" onclick="testConn('dealgod')">Test DealGod</button><span id="c-dealgod" class="soon"></span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h2>Discogs</h2>
|
<h2>Orders (WooCommerce)</h2>
|
||||||
<p class="soon">Save your Discogs OAuth/token above to enrich intake from the live API and your wantlist.</p>
|
<p class="soon">Once WooCommerce tests green, live orders land here — managed without wp-admin. (Next build.)</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -100,6 +104,16 @@ async function save(name, btn){
|
|||||||
btn.previousElementSibling; setTimeout(()=>btn.textContent='Save', 1500); }
|
btn.previousElementSibling; setTimeout(()=>btn.textContent='Save', 1500); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function testConn(svc){
|
||||||
|
const el = document.getElementById('c-'+svc); el.textContent='testing…'; el.style.color='#9a9aa6';
|
||||||
|
let r, d;
|
||||||
|
try { r = await fetch('/settings/test/'+svc, {method:'POST', headers:hdr()}); d = await r.json(); }
|
||||||
|
catch(e){ el.textContent='✕ network error'; el.style.color='#e66'; return; }
|
||||||
|
if(!r.ok){ el.textContent='✕ '+(d.detail||r.status); el.style.color='#e6a046'; return; }
|
||||||
|
if(d.connected){ el.textContent='✓ connected'+(d.as?(' as '+d.as):''); el.style.color='#46d18a'; }
|
||||||
|
else { el.textContent='✕ '+(d.detail||('HTTP '+d.status)); el.style.color='#e6a046'; }
|
||||||
|
}
|
||||||
|
|
||||||
// auto-resume if a token is already stored
|
// auto-resume if a token is already stored
|
||||||
if(TOKEN){ $('#tok').value = TOKEN; signin(); }
|
if(TOKEN){ $('#tok').value = TOKEN; signin(); }
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user