This commit is contained in:
+34
-4
@@ -1311,8 +1311,24 @@ class ApiHandler(BaseHTTPRequestHandler):
|
||||
else:seen.add(key);accepted.append(b)
|
||||
return self.send_json(200,{"accepted":len(accepted),"duplicates":len(rows)-len(normalized)+len(normalized)-len(accepted)-suppressed,"suppressed":suppressed,"rows":accepted})
|
||||
def list_sources(self,db,org):
|
||||
cols='id,organization_id,name,kind,source_code,display_name,enabled,approved,policy_json,quota_json,health_status,consecutive_failures,circuit_open,last_success_at,last_failure_at,last_error,created_at,updated_at'
|
||||
return self.send_json(200,{"organization_id":org,"items":[row_json(r) for r in db.execute(f"SELECT {cols} FROM sources WHERE organization_id=? ORDER BY id",(org,))]})
|
||||
cols='id,organization_id,name,kind,source_code,display_name,enabled,approved,config_json,policy_json,quota_json,health_status,consecutive_failures,circuit_open,last_success_at,last_failure_at,last_error,created_at,updated_at'
|
||||
items=[]
|
||||
adapter_meta={a["source_code"]:a for a in available_adapters()}
|
||||
for raw in db.execute(f"SELECT {cols} FROM sources WHERE organization_id=? ORDER BY id",(org,)):
|
||||
item=row_json(raw); meta=adapter_meta.get(item.get("source_code") or item.get("kind"), {})
|
||||
try: config=json.loads(raw["config_json"] or "{}")
|
||||
except (TypeError,ValueError): config={}
|
||||
try: policy=json.loads(raw["policy_json"] or "{}")
|
||||
except (TypeError,ValueError): policy={}
|
||||
item.update({"available": bool(meta.get("available", False)), "optional": bool(meta.get("optional", False)),
|
||||
"configured": bool(meta.get("available", False) and (config.get("csv") or config.get("rows") is not None or raw["approved"])),
|
||||
"credential_status": "Not required" if not meta.get("requires_credentials") else "Required / not configured",
|
||||
"terms_status": "Provided" if policy.get("terms_url") or config.get("terms_url") else "Not reviewed",
|
||||
"owner": policy.get("owner") or config.get("owner") or "Not assigned",
|
||||
"rate_limit": policy.get("rate_limit") or config.get("rate_limit") or "Not set"})
|
||||
item.pop("config_json", None)
|
||||
items.append(item)
|
||||
return self.send_json(200,{"organization_id":org,"items":items})
|
||||
def list_queries(self,db,org):
|
||||
return self.send_json(200,{"organization_id":org,"items":[row_json(r) for r in db.execute("SELECT * FROM discovery_queries WHERE organization_id=? ORDER BY id",(org,))]})
|
||||
def list_source_records(self,db,org,q):
|
||||
@@ -1342,9 +1358,23 @@ class ApiHandler(BaseHTTPRequestHandler):
|
||||
except sqlite3.IntegrityError:return self.send_json(409,{"error":"duplicate_source"})
|
||||
self.audit(db,user,'source.created',str(cur.lastrowid));db.commit();return self.send_json(201,row_json(db.execute("SELECT id,organization_id,name,kind,source_code,display_name,enabled,approved,policy_json,quota_json,health_status,consecutive_failures,circuit_open,last_success_at,last_failure_at,last_error,created_at,updated_at FROM sources WHERE id=?",(cur.lastrowid,)).fetchone()))
|
||||
def update_source(self,sid,payload,db,user):
|
||||
if not db.execute("SELECT id FROM sources WHERE id=? AND organization_id=?",(sid,user['organization_id'])).fetchone():return self.send_json(404,{"error":"not_found"})
|
||||
source=db.execute("SELECT * FROM sources WHERE id=? AND organization_id=?",(sid,user['organization_id'])).fetchone()
|
||||
if not source:return self.send_json(404,{"error":"not_found"})
|
||||
if 'enabled' not in payload:return self.send_json(400,{"error":"enabled_required"})
|
||||
value=int(bool(payload['enabled']));db.execute("UPDATE sources SET enabled=?,updated_at=CURRENT_TIMESTAMP WHERE id=?",(value,sid));self.audit(db,user,'source.enabled' if value else 'source.disabled',str(sid));db.commit();return self.send_json(200,row_json(db.execute("SELECT * FROM sources WHERE id=?",(sid,)).fetchone()))
|
||||
value=int(bool(payload['enabled']))
|
||||
if value:
|
||||
adapter=adapter_for(source['kind'])
|
||||
try: config=json.loads(source['config_json'] or '{}')
|
||||
except (TypeError,ValueError): config={}
|
||||
metadata=next((item for item in available_adapters() if item['source_code']==source['kind']), {})
|
||||
if not metadata.get('available', False): return self.send_json(409,{"error":"source_unavailable"})
|
||||
validation=adapter.validate_config(config)
|
||||
# A blank manual source is a deliberate staging point: the query or
|
||||
# ingest payload can provide rows later. Other adapters must be ready
|
||||
# before they are enabled.
|
||||
if not validation.valid and not (source['kind'] == 'manual' and not config):
|
||||
return self.send_json(409,{"error":"source_not_configured","details":validation.errors})
|
||||
db.execute("UPDATE sources SET enabled=?,updated_at=CURRENT_TIMESTAMP WHERE id=?",(value,sid));self.audit(db,user,'source.enabled' if value else 'source.disabled',str(sid));db.commit();return self.send_json(200,row_json(db.execute("SELECT * FROM sources WHERE id=?",(sid,)).fetchone()))
|
||||
def create_query(self,payload,db,user):
|
||||
sid=payload.get('source_id');name=str(payload.get('name','')).strip();query=payload.get('query',{})
|
||||
selected=payload.get('selected_adapters',payload.get('sources',[])); location=str(payload.get('location','')).strip(); category=str(payload.get('category','')).strip(); schedule=str(payload.get('schedule','')).strip()
|
||||
|
||||
Reference in New Issue
Block a user