From 5e06b11c78a5657f570fe2edf76803a6e1008511 Mon Sep 17 00:00:00 2001 From: DmsAnhr Date: Mon, 22 Dec 2025 15:17:39 +0700 Subject: [PATCH] update router for endpoint --- api/routers/datasets_router.py | 155 +++++++++++++++++++++++++----- api/routers/system_router.py | 72 +++++++++++++- api/routers/upload_file_router.py | 7 +- 3 files changed, 207 insertions(+), 27 deletions(-) diff --git a/api/routers/datasets_router.py b/api/routers/datasets_router.py index 8c462f1..a86fa57 100644 --- a/api/routers/datasets_router.py +++ b/api/routers/datasets_router.py @@ -1,8 +1,16 @@ -from fastapi import APIRouter +import asyncio +from uuid import uuid4 +from fastapi import APIRouter, HTTPException +import requests from sqlalchemy import text from database.connection import engine from services.datasets.delete import delete_dataset_from_partition # import fungsi di atas from response import successRes, errorRes +from services.datasets.publish_geonetwork import publish_metadata +from services.datasets.publish_geoserver import publish_layer_to_geoserver +from services.datasets.metadata import update_job_status +from services.upload_file.upload_ws import report_progress +from core.config import GEOSERVER_URL, GEOSERVER_USER, GEOSERVER_PASS, QGIS_URL router = APIRouter() @@ -30,29 +38,16 @@ async def get_author_metadata( try: async with engine.begin() as conn: - # if user.role == "admin": - # query = text(""" - # SELECT * - # FROM backend.author_metadata - # ORDER BY created_at DESC - # """) - # result = await conn.execute(query) - - # else: - # query = text(""" - # SELECT * - # FROM backend.author_metadata - # WHERE user_id = :uid - # ORDER BY created_at DESC - # """) - # result = await conn.execute(query, {"uid": user.id}) - - # rows = result.fetchall() query = text(""" SELECT * FROM backend.author_metadata - ORDER BY created_at DESC + ORDER BY CASE process + WHEN 'CLEANSING' THEN 1 + WHEN 'ERROR' THEN 2 + WHEN 'FINISHED' THEN 3 + WHEN 'TESTING' THEN 4 + END; """) result = await conn.execute(query) rows = result.fetchall() @@ -92,7 +87,123 @@ async def delete_dataset(user_id: int, metadata_id: int, title: str): +# @router.post("/cleansing/{table_name}") +def cleansing_data(table_name: str, job_id: str): + payload = { + "table_name": table_name, + "job_id": job_id + } + print("cleansing_data runn") + # response = requests.post( + # f"{QGIS_URL}/process/{table_name}", + # ) + response = requests.post( + f"{QGIS_URL}/process", + json=payload, + ) + return response -# @router.get("/upload/geoserver") -# async def \ No newline at end of file +@router.post("/jobs/callback") +async def job_callback(payload: dict): + table = payload["table"] + job_id = payload["job_id"] + # await asyncio.sleep(10) + + await report_progress(job_id, "cleansing", 50, "Cleansing data selesai") + # await asyncio.sleep(5) + + geos_link = publish_layer_to_geoserver(table, job_id) + await report_progress(job_id, "publish_geoserver", 80, "Publish GeoServer selesai") + # await asyncio.sleep(3) + + uuid = publish_metadata(table_name=table, geoserver_links=geos_link) + await report_progress(job_id, "done", 100, "Publish GeoNetwork selesai") + + update_job_status(table, "FINISHED", job_id) + return { + "ok": True, + "uuid": uuid + } + + + +@router.get("/styles") +def get_style_list(workspace: str = None): + """ + Mengambil daftar style yang ada di GeoServer. + - Jika workspace = None → ambil style global + - Jika workspace diisi → ambil style milik workspace tersebut + """ + + # Tentukan URL sesuai workspace + if workspace: + url = f"{GEOSERVER_URL}/rest/workspaces/{workspace}/styles" + else: + url = f"{GEOSERVER_URL}/rest/styles" + + headers = {"Accept": "application/json"} + + try: + response = requests.get( + url, + auth=(GEOSERVER_USER, GEOSERVER_PASS), + headers=headers, + timeout=15 + ) + + if response.status_code == 200: + data = response.json() + + styles = data.get("styles", {}).get("style", []) + + return { + "status": "success", + "workspace": workspace, + "count": len(styles), + "styles": styles + } + + else: + raise HTTPException(status_code=response.status_code, detail=response.text) + + except requests.exceptions.RequestException as e: + raise HTTPException(status_code=500, detail=f"Request error: {str(e)}") + + + +@router.get("/styles/{style_name}") +def get_style(style_name: str, workspace: str = None): + """ + Mengambil file SLD style dari GeoServer. + - Jika workspace tidak diisi → ambil style global + - Jika workspace diisi → ambil dari workspace + """ + + # Tentukan endpoint sesuai workspace + url = f"{GEOSERVER_URL}/rest/styles/{style_name}.sld" + + try: + response = requests.get( + url, + auth=(GEOSERVER_USER, GEOSERVER_PASS), + timeout=15 + ) + + if response.status_code == 200: + # Return isi SLD sebagai text + return { + "status": "success", + "style_name": style_name, + "workspace": workspace, + "sld": response.text + } + + elif response.status_code == 404: + raise HTTPException(status_code=404, detail="Style tidak ditemukan di GeoServer") + + else: + raise HTTPException(status_code=500, detail=f"GeoServer error: {response.text}") + + except requests.exceptions.RequestException as e: + raise HTTPException(status_code=500, detail=f"Request error: {str(e)}") \ No newline at end of file diff --git a/api/routers/system_router.py b/api/routers/system_router.py index ca291e4..d950bec 100644 --- a/api/routers/system_router.py +++ b/api/routers/system_router.py @@ -1,7 +1,8 @@ import httpx from fastapi import APIRouter from datetime import datetime, timedelta -from core.config import API_VERSION, GEOSERVER_URL +import requests +from core.config import API_VERSION, GEOSERVER_URL, GEOSERVER_USER, GEOSERVER_PASS, GEONETWORK_URL, GEONETWORK_USER, GEONETWORK_PASS router = APIRouter() @@ -24,8 +25,8 @@ async def server_status(): @router.get("/status/geoserver") async def check_geoserver_auth(): - url = f"{GEOSERVER_URL}/geoserver/rest/about/version." - auth = ("admin", "geoserver") + url = f"{GEOSERVER_URL}/rest/about/version." + auth = (GEOSERVER_USER, GEOSERVER_PASS) try: async with httpx.AsyncClient() as client: @@ -37,6 +38,71 @@ async def check_geoserver_auth(): } except Exception as e: return {"status": "FAILED", "error": str(e)} + + +@router.get("/status/geonetwork") +def test_geonetwork_connection(): + + url = f"{GEONETWORK_URL}/srv/api/site" + + headers = { + "Accept": "application/json", + "X-Requested-With": "XMLHttpRequest" + } + + try: + response = requests.get( + url, + auth=(GEONETWORK_USER, GEONETWORK_PASS), + headers=headers, + timeout=10 + ) + + if response.status_code == 401: + return { + "status": "ERROR", + "message": "Unauthorized — cek username/password GeoNetwork." + } + + if response.status_code == 403: + return { + "status": "ERROR", + "message": "Forbidden — akun tidak punya akses ke API." + } + + if response.status_code != 200: + return { + "status": "ERROR", + "message": "GeoNetwork merespon dengan error.", + "code": response.status_code, + "detail": response.text + } + + return { + "status": "OK", + "code": response.status_code, + "message": "Terhubung ke GeoNetwork.", + "geonetwork_info": response.json() + } + + except requests.exceptions.ConnectionError: + return { + "status": "ERROR", + "message": "Tidak dapat terhubung ke GeoNetwork (server offline / URL salah)" + } + + except requests.exceptions.Timeout: + return { + "status": "ERROR", + "message": "Timeout menghubungi GeoNetwork." + } + + except Exception as e: + return { + "status": "ERROR", + "message": "Unexpected error", + "detail": str(e) + } diff --git a/api/routers/upload_file_router.py b/api/routers/upload_file_router.py index 6924278..e7b8ede 100644 --- a/api/routers/upload_file_router.py +++ b/api/routers/upload_file_router.py @@ -10,8 +10,8 @@ router = APIRouter() @router.post("/file") # async def upload_file(file: UploadFile = File(...), page: Optional[str] = Form(""), sheet: Optional[str] = Form(""), user = Depends(require_role("admin"))): -async def upload_file(file: UploadFile = File(...), page: Optional[str] = Form(""), sheet: Optional[str] = Form("")): - return await handle_upload_file(file, page, sheet) +async def upload_file(file: UploadFile = File(...), page: Optional[str] = Form(""), sheet: Optional[str] = Form(""), file_desc: Optional[str] = Form("")): + return await handle_upload_file(file, page, sheet, file_desc) @@ -19,6 +19,8 @@ class PdfRequest(BaseModel): title: str columns: List[str] rows: List[List] + fileName: str + fileDesc: str @router.post("/process-pdf") async def upload_file(payload: PdfRequest): @@ -31,6 +33,7 @@ class UploadRequest(BaseModel): rows: List[dict] columns: List[str] author: Dict[str, Any] + style: str @router.post("/to-postgis") async def upload_to_postgis(payload: UploadRequest):