677 lines
29 KiB
Python
677 lines
29 KiB
Python
from fastapi import HTTPException
|
|
import requests
|
|
from sqlalchemy import text
|
|
from core.config import GEONETWORK_PASS, GEONETWORK_URL, GEONETWORK_USER
|
|
from database.connection import engine
|
|
from datetime import datetime
|
|
from uuid import uuid4
|
|
import re
|
|
|
|
|
|
|
|
def create_gn_session():
|
|
session = requests.Session()
|
|
session.auth = (GEONETWORK_USER, GEONETWORK_PASS)
|
|
|
|
session.get(f"{GEONETWORK_URL}/srv/eng/info?type=me")
|
|
xsrf_token = session.cookies.get("XSRF-TOKEN")
|
|
|
|
if not xsrf_token:
|
|
raise Exception("XSRF token missing")
|
|
|
|
return session, xsrf_token
|
|
|
|
|
|
|
|
def escape_url_params(url: str) -> str:
|
|
"""
|
|
Escape karakter berbahaya di dalam URL agar valid dalam XML.
|
|
Khususnya mengganti '&' menjadi '&' kecuali jika sudah '&'.
|
|
"""
|
|
# Ganti semua & yang bukan bagian dari &
|
|
url = re.sub(r'&(?!amp;)', '&', url)
|
|
return url
|
|
|
|
|
|
def fix_xml_urls(xml: str) -> str:
|
|
"""
|
|
Temukan semua <gmd:URL> ... </gmd:URL> dalam XML dan escape URL-nya.
|
|
"""
|
|
def replacer(match):
|
|
original = match.group(1).strip()
|
|
fixed = escape_url_params(original)
|
|
return f"<gmd:URL>{fixed}</gmd:URL>"
|
|
|
|
# Replace semua <gmd:URL> ... </gmd:URL>
|
|
xml_fixed = re.sub(
|
|
r"<gmd:URL>(.*?)</gmd:URL>",
|
|
replacer,
|
|
xml,
|
|
flags=re.DOTALL
|
|
)
|
|
|
|
return xml_fixed
|
|
|
|
|
|
|
|
async def get_extent(table_name: str):
|
|
|
|
sql = f"""
|
|
SELECT
|
|
ST_XMin(extent), ST_YMin(extent),
|
|
ST_XMax(extent), ST_YMax(extent)
|
|
FROM (
|
|
SELECT ST_Extent(geom) AS extent
|
|
FROM public."{table_name}"
|
|
) AS box;
|
|
"""
|
|
|
|
async with engine.connect() as conn:
|
|
result = await conn.execute(sql)
|
|
row = result.fetchone()
|
|
|
|
if not row or row[0] is None:
|
|
return None
|
|
|
|
# return {
|
|
# "xmin": row[0],
|
|
# "ymin": row[1],
|
|
# "xmax": row[2],
|
|
# "ymax": row[3]
|
|
# }
|
|
|
|
return {
|
|
"xmin": 110.1372, # west
|
|
"ymin": -9.3029, # south
|
|
"xmax": 114.5287, # east
|
|
"ymax": -5.4819 # north
|
|
}
|
|
|
|
async def get_author_metadata(table_name: str):
|
|
|
|
sql = """
|
|
SELECT am.table_title, am.dataset_title, am.dataset_abstract, am.keywords, am.date_created,
|
|
am.organization_name, am.contact_person_name, am.created_at,
|
|
am.contact_email, am.contact_phone, am.geom_type,
|
|
u.organization_id,
|
|
o.address AS organization_address,
|
|
o.email AS organization_email,
|
|
o.phone_number AS organization_phone
|
|
FROM backend.author_metadata AS am
|
|
LEFT JOIN backend.users u ON am.user_id = u.id
|
|
LEFT JOIN backend.organizations o ON u.organization_id = o.id
|
|
WHERE am.table_title = :table
|
|
LIMIT 1
|
|
"""
|
|
|
|
async with engine.connect() as conn:
|
|
result = await conn.execute(sql, {"table": table_name})
|
|
row = result.fetchone()
|
|
|
|
if not row:
|
|
raise Exception(f"Tidak ada metadata untuk tabel: {table_name}")
|
|
|
|
# SQLAlchemy Async row support ._mapping untuk convert ke dict
|
|
return dict(row._mapping)
|
|
|
|
|
|
def map_geom_type(gtype):
|
|
|
|
if gtype is None:
|
|
return "surface"
|
|
|
|
# Jika LIST → ambil elemen pertama
|
|
if isinstance(gtype, list):
|
|
if len(gtype) > 0:
|
|
gtype = gtype[0]
|
|
else:
|
|
return "surface"
|
|
|
|
# Setelah pasti string
|
|
gtype = str(gtype).lower()
|
|
|
|
if "polygon" in gtype or "multi" in gtype:
|
|
return "surface"
|
|
if "line" in gtype:
|
|
return "curve"
|
|
if "point" in gtype:
|
|
return "point"
|
|
|
|
return "surface"
|
|
|
|
|
|
def generate_metadata_xml(table_name, meta, extent, geoserver_links):
|
|
|
|
keywords_xml = "".join([
|
|
f"""
|
|
<gmd:keyword><gco:CharacterString>{kw.strip()}</gco:CharacterString></gmd:keyword>
|
|
""" for kw in meta["keywords"].split(",")
|
|
])
|
|
|
|
geom_type_code = map_geom_type(meta["geom_type"])
|
|
print('type', geom_type_code)
|
|
uuid = str(uuid4())
|
|
|
|
return f"""
|
|
<gmd:MD_Metadata
|
|
xmlns:gmd="http://www.isotc211.org/2005/gmd"
|
|
xmlns:gco="http://www.isotc211.org/2005/gco"
|
|
xmlns:srv="http://www.isotc211.org/2005/srv"
|
|
xmlns:gmx="http://www.isotc211.org/2005/gmx"
|
|
xmlns:gts="http://www.isotc211.org/2005/gts"
|
|
xmlns:gsr="http://www.isotc211.org/2005/gsr"
|
|
xmlns:gmi="http://www.isotc211.org/2005/gmi"
|
|
xmlns:gml="http://www.opengis.net/gml/3.2"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.isotc211.org/2005/gmd http://schemas.opengis.net/csw/2.0.2/profiles/apiso/1.0.0/apiso.xsd">
|
|
<gmd:fileIdentifier>
|
|
<gco:CharacterString>{uuid}</gco:CharacterString>
|
|
</gmd:fileIdentifier>
|
|
<gmd:language>
|
|
<gmd:LanguageCode codeList="http://www.loc.gov/standards/iso639-2/" codeListValue="eng"/>
|
|
</gmd:language>
|
|
<gmd:characterSet>
|
|
<gmd:MD_CharacterSetCode codeListValue="utf8" codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_CharacterSetCode"/>
|
|
</gmd:characterSet>
|
|
<gmd:hierarchyLevel>
|
|
<gmd:MD_ScopeCode codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_ScopeCode" codeListValue="feature"/>
|
|
</gmd:hierarchyLevel>
|
|
<gmd:contact>
|
|
<gmd:CI_ResponsibleParty>
|
|
<gmd:individualName>
|
|
<gco:CharacterString>{meta['contact_person_name']}</gco:CharacterString>
|
|
</gmd:individualName>
|
|
<gmd:organisationName>
|
|
<gco:CharacterString>{meta['organization_name']}</gco:CharacterString>
|
|
</gmd:organisationName>
|
|
<gmd:contactInfo>
|
|
<gmd:CI_Contact>
|
|
<gmd:phone>
|
|
<gmd:CI_Telephone>
|
|
<gmd:voice>
|
|
<gco:CharacterString>{meta['organization_phone']}</gco:CharacterString>
|
|
</gmd:voice>
|
|
<gmd:facsimile>
|
|
<gco:CharacterString>{meta['organization_phone']}</gco:CharacterString>
|
|
</gmd:facsimile>
|
|
</gmd:CI_Telephone>
|
|
</gmd:phone>
|
|
<gmd:address>
|
|
<gmd:CI_Address>
|
|
<gmd:deliveryPoint>
|
|
<gco:CharacterString>{meta['organization_address']}</gco:CharacterString>
|
|
</gmd:deliveryPoint>
|
|
<gmd:city>
|
|
<gco:CharacterString>Surabaya</gco:CharacterString>
|
|
</gmd:city>
|
|
<gmd:administrativeArea>
|
|
<gco:CharacterString>Jawa Timur</gco:CharacterString>
|
|
</gmd:administrativeArea>
|
|
<gmd:country>
|
|
<gco:CharacterString>Indonesia</gco:CharacterString>
|
|
</gmd:country>
|
|
<gmd:electronicMailAddress>
|
|
<gco:CharacterString>{meta['organization_email']}</gco:CharacterString>
|
|
</gmd:electronicMailAddress>
|
|
</gmd:CI_Address>
|
|
</gmd:address>
|
|
<gmd:hoursOfService>
|
|
<gco:CharacterString>08.00-16.00</gco:CharacterString>
|
|
</gmd:hoursOfService>
|
|
</gmd:CI_Contact>
|
|
</gmd:contactInfo>
|
|
<gmd:role>
|
|
<gmd:CI_RoleCode codeListValue="pointOfContact" codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#CI_RoleCode"/>
|
|
</gmd:role>
|
|
</gmd:CI_ResponsibleParty>
|
|
</gmd:contact>
|
|
<gmd:dateStamp>
|
|
<gco:DateTime>{datetime.utcnow().isoformat()}+07:00</gco:DateTime>
|
|
</gmd:dateStamp>
|
|
<gmd:metadataStandardName>
|
|
<gco:CharacterString>ISO 19115:2003/19139</gco:CharacterString>
|
|
</gmd:metadataStandardName>
|
|
<gmd:metadataStandardVersion>
|
|
<gco:CharacterString>1.0</gco:CharacterString>
|
|
</gmd:metadataStandardVersion>
|
|
<gmd:spatialRepresentationInfo>
|
|
<gmd:MD_VectorSpatialRepresentation>
|
|
<gmd:geometricObjects>
|
|
<gmd:MD_GeometricObjects>
|
|
<gmd:geometricObjectType>
|
|
<gmd:MD_GeometricObjectTypeCode codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_GeometricObjectTypeCode" codeListValue="{geom_type_code}"/>
|
|
</gmd:geometricObjectType>
|
|
<gmd:geometricObjectCount>
|
|
<gco:Integer>38</gco:Integer>
|
|
</gmd:geometricObjectCount>
|
|
</gmd:MD_GeometricObjects>
|
|
</gmd:geometricObjects>
|
|
</gmd:MD_VectorSpatialRepresentation>
|
|
</gmd:spatialRepresentationInfo>
|
|
<gmd:referenceSystemInfo>
|
|
<gmd:MD_ReferenceSystem>
|
|
<gmd:referenceSystemIdentifier>
|
|
<gmd:RS_Identifier>
|
|
<gmd:code>
|
|
<gco:CharacterString>4326</gco:CharacterString>
|
|
</gmd:code>
|
|
<gmd:codeSpace>
|
|
<gco:CharacterString>EPSG</gco:CharacterString>
|
|
</gmd:codeSpace>
|
|
</gmd:RS_Identifier>
|
|
</gmd:referenceSystemIdentifier>
|
|
</gmd:MD_ReferenceSystem>
|
|
</gmd:referenceSystemInfo>
|
|
<gmd:identificationInfo>
|
|
<gmd:MD_DataIdentification>
|
|
<gmd:citation>
|
|
<gmd:CI_Citation>
|
|
<gmd:title>
|
|
<gco:CharacterString>{meta['dataset_title']}</gco:CharacterString>
|
|
</gmd:title>
|
|
<gmd:date>
|
|
<gmd:CI_Date>
|
|
<gmd:date>
|
|
<gco:DateTime>{meta['created_at'].isoformat()}+07:00</gco:DateTime>
|
|
</gmd:date>
|
|
<gmd:dateType>
|
|
<gmd:CI_DateTypeCode codeListValue="publication" codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#CI_DateTypeCode"/>
|
|
</gmd:dateType>
|
|
</gmd:CI_Date>
|
|
</gmd:date>
|
|
<gmd:edition>
|
|
<gco:CharacterString>{meta['date_created'].year}</gco:CharacterString>
|
|
</gmd:edition>
|
|
<gmd:citedResponsibleParty>
|
|
<gmd:CI_ResponsibleParty>
|
|
<gmd:individualName>
|
|
<gco:CharacterString>{meta['contact_person_name']}</gco:CharacterString>
|
|
</gmd:individualName>
|
|
<gmd:organisationName>
|
|
<gco:CharacterString>{meta['organization_name']}</gco:CharacterString>
|
|
</gmd:organisationName>
|
|
<gmd:contactInfo>
|
|
<gmd:CI_Contact>
|
|
<gmd:phone>
|
|
<gmd:CI_Telephone>
|
|
<gmd:voice>
|
|
<gco:CharacterString>{meta['organization_phone']}</gco:CharacterString>
|
|
</gmd:voice>
|
|
<gmd:facsimile>
|
|
<gco:CharacterString>{meta['organization_phone']}</gco:CharacterString>
|
|
</gmd:facsimile>
|
|
</gmd:CI_Telephone>
|
|
</gmd:phone>
|
|
<gmd:address>
|
|
<gmd:CI_Address>
|
|
<gmd:deliveryPoint>
|
|
<gco:CharacterString>{meta['organization_address']}</gco:CharacterString>
|
|
</gmd:deliveryPoint>
|
|
<gmd:city>
|
|
<gco:CharacterString>Surabaya</gco:CharacterString>
|
|
</gmd:city>
|
|
<gmd:country>
|
|
<gco:CharacterString>Indonesia</gco:CharacterString>
|
|
</gmd:country>
|
|
<gmd:electronicMailAddress>
|
|
<gco:CharacterString>{meta['organization_email']}</gco:CharacterString>
|
|
</gmd:electronicMailAddress>
|
|
</gmd:CI_Address>
|
|
</gmd:address>
|
|
<gmd:hoursOfService>
|
|
<gco:CharacterString>08.00-16.00</gco:CharacterString>
|
|
</gmd:hoursOfService>
|
|
</gmd:CI_Contact>
|
|
</gmd:contactInfo>
|
|
<gmd:role>
|
|
<gmd:CI_RoleCode codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian"/>
|
|
</gmd:role>
|
|
</gmd:CI_ResponsibleParty>
|
|
</gmd:citedResponsibleParty>
|
|
<gmd:otherCitationDetails>
|
|
<gco:CharacterString>Timezone: UTC+7 (Asia/Jakarta)</gco:CharacterString>
|
|
</gmd:otherCitationDetails>
|
|
</gmd:CI_Citation>
|
|
</gmd:citation>
|
|
<gmd:abstract>
|
|
<gco:CharacterString>{meta['dataset_abstract']}</gco:CharacterString>
|
|
</gmd:abstract>
|
|
<gmd:purpose>
|
|
<gco:CharacterString>{meta['dataset_abstract']}</gco:CharacterString>
|
|
</gmd:purpose>
|
|
<gmd:status>
|
|
<gmd:MD_ProgressCode codeListValue="completed" codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_ProgressCode"/>
|
|
</gmd:status>
|
|
<gmd:pointOfContact>
|
|
<gmd:CI_ResponsibleParty>
|
|
<gmd:individualName>
|
|
<gco:CharacterString>Dinas Tenaga Kerja dan Transmigrasi Provinsi Jawa Timur</gco:CharacterString>
|
|
</gmd:individualName>
|
|
<gmd:organisationName>
|
|
<gco:CharacterString>Dinas Tenaga Kerja dan Transmigrasi Provinsi Jawa Timur</gco:CharacterString>
|
|
</gmd:organisationName>
|
|
<gmd:positionName gco:nilReason="missing"/>
|
|
<gmd:contactInfo>
|
|
<gmd:CI_Contact>
|
|
<gmd:phone>
|
|
<gmd:CI_Telephone>
|
|
<gmd:voice>
|
|
<gco:CharacterString>{meta['organization_phone']}</gco:CharacterString>
|
|
</gmd:voice>
|
|
<gmd:facsimile>
|
|
<gco:CharacterString>{meta['organization_phone']}</gco:CharacterString>
|
|
</gmd:facsimile>
|
|
</gmd:CI_Telephone>
|
|
</gmd:phone>
|
|
<gmd:address>
|
|
<gmd:CI_Address>
|
|
<gmd:deliveryPoint>
|
|
<gco:CharacterString>{meta['organization_address']}</gco:CharacterString>
|
|
</gmd:deliveryPoint>
|
|
<gmd:city>
|
|
<gco:CharacterString>Surabaya</gco:CharacterString>
|
|
</gmd:city>
|
|
<gmd:administrativeArea>
|
|
<gco:CharacterString>Jawa Timur</gco:CharacterString>
|
|
</gmd:administrativeArea>
|
|
<gmd:country>
|
|
<gco:CharacterString>Indonesia</gco:CharacterString>
|
|
</gmd:country>
|
|
<gmd:electronicMailAddress>
|
|
<gco:CharacterString>{meta['organization_email']}</gco:CharacterString>
|
|
</gmd:electronicMailAddress>
|
|
</gmd:CI_Address>
|
|
</gmd:address>
|
|
</gmd:CI_Contact>
|
|
</gmd:contactInfo>
|
|
<gmd:role>
|
|
<gmd:CI_RoleCode codeListValue="owner" codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#CI_RoleCode"/>
|
|
</gmd:role>
|
|
</gmd:CI_ResponsibleParty>
|
|
</gmd:pointOfContact>
|
|
<gmd:resourceMaintenance>
|
|
<gmd:MD_MaintenanceInformation>
|
|
<gmd:maintenanceAndUpdateFrequency>
|
|
<gmd:MD_MaintenanceFrequencyCode codeListValue="annually" codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_MaintenanceFrequencyCode"/>
|
|
</gmd:maintenanceAndUpdateFrequency>
|
|
</gmd:MD_MaintenanceInformation>
|
|
</gmd:resourceMaintenance>
|
|
<gmd:descriptiveKeywords>
|
|
<gmd:MD_Keywords>
|
|
{keywords_xml}
|
|
</gmd:MD_Keywords>
|
|
</gmd:descriptiveKeywords>
|
|
<gmd:resourceConstraints>
|
|
<gmd:MD_LegalConstraints>
|
|
<gmd:accessConstraints>
|
|
<gmd:MD_RestrictionCode codeListValue="copyright" codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_RestrictionCode"/>
|
|
</gmd:accessConstraints>
|
|
<gmd:useConstraints>
|
|
<gmd:MD_RestrictionCode codeListValue="otherRestrictions" codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_RestrictionCode"/>
|
|
</gmd:useConstraints>
|
|
<gmd:otherConstraints>
|
|
<gco:CharacterString>Penggunaan data harus mencantumkan sumber: {meta['organization_name']}.</gco:CharacterString>
|
|
</gmd:otherConstraints>
|
|
</gmd:MD_LegalConstraints>
|
|
</gmd:resourceConstraints>
|
|
<gmd:spatialRepresentationType>
|
|
<gmd:MD_SpatialRepresentationTypeCode codeListValue="vector" codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_SpatialRepresentationTypeCode"/>
|
|
</gmd:spatialRepresentationType>
|
|
<gmd:spatialResolution>
|
|
<gmd:MD_Resolution>
|
|
<gmd:equivalentScale>
|
|
<gmd:MD_RepresentativeFraction>
|
|
<gmd:denominator>
|
|
<gco:Integer>25000</gco:Integer>
|
|
</gmd:denominator>
|
|
</gmd:MD_RepresentativeFraction>
|
|
</gmd:equivalentScale>
|
|
</gmd:MD_Resolution>
|
|
</gmd:spatialResolution>
|
|
<gmd:language>
|
|
<gmd:LanguageCode codeList="http://www.loc.gov/standards/iso639-2/" codeListValue="eng"/>
|
|
</gmd:language>
|
|
<gmd:characterSet>
|
|
<gmd:MD_CharacterSetCode codeListValue="utf8" codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_CharacterSetCode"/>
|
|
</gmd:characterSet>
|
|
<gmd:extent>
|
|
<gmd:EX_Extent>
|
|
<gmd:geographicElement>
|
|
<gmd:EX_GeographicBoundingBox>
|
|
<gmd:westBoundLongitude><gco:Decimal>{extent['xmin']}</gco:Decimal></gmd:westBoundLongitude>
|
|
<gmd:eastBoundLongitude><gco:Decimal>{extent['xmax']}</gco:Decimal></gmd:eastBoundLongitude>
|
|
<gmd:southBoundLatitude><gco:Decimal>{extent['ymin']}</gco:Decimal></gmd:southBoundLatitude>
|
|
<gmd:northBoundLatitude><gco:Decimal>{extent['ymax']}</gco:Decimal></gmd:northBoundLatitude>
|
|
</gmd:EX_GeographicBoundingBox>
|
|
</gmd:geographicElement>
|
|
</gmd:EX_Extent>
|
|
</gmd:extent>
|
|
</gmd:MD_DataIdentification>
|
|
</gmd:identificationInfo>
|
|
<gmd:contentInfo>
|
|
<gmd:MD_FeatureCatalogueDescription>
|
|
<gmd:complianceCode>
|
|
<gco:Boolean>true</gco:Boolean>
|
|
</gmd:complianceCode>
|
|
<gmd:includedWithDataset gco:nilReason="unknown"/>
|
|
<gmd:featureCatalogueCitation>
|
|
<gmd:CI_Citation>
|
|
<gmd:title>
|
|
<gco:CharacterString>{meta['dataset_title']}</gco:CharacterString>
|
|
</gmd:title>
|
|
<gmd:date>
|
|
<gmd:CI_Date>
|
|
<gmd:date>
|
|
<gco:DateTime>{meta['created_at'].isoformat()}+07:00</gco:DateTime>
|
|
</gmd:date>
|
|
<gmd:dateType>
|
|
<gmd:CI_DateTypeCode codeListValue="publication" codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#CI_DateTypeCode"/>
|
|
</gmd:dateType>
|
|
</gmd:CI_Date>
|
|
</gmd:date>
|
|
<gmd:edition>
|
|
<gco:CharacterString>{meta['date_created'].year}</gco:CharacterString>
|
|
</gmd:edition>
|
|
</gmd:CI_Citation>
|
|
</gmd:featureCatalogueCitation>
|
|
</gmd:MD_FeatureCatalogueDescription>
|
|
</gmd:contentInfo>
|
|
<gmd:distributionInfo>
|
|
<gmd:MD_Distribution>
|
|
<gmd:transferOptions>
|
|
<gmd:MD_DigitalTransferOptions>
|
|
<gmd:onLine>
|
|
<gmd:CI_OnlineResource>
|
|
<gmd:linkage>
|
|
<gmd:URL>{geoserver_links["wms_url"]}</gmd:URL>
|
|
</gmd:linkage>
|
|
<gmd:protocol>
|
|
<gco:CharacterString>DB:POSTGIS</gco:CharacterString>
|
|
</gmd:protocol>
|
|
<gmd:name>
|
|
<gco:CharacterString>{meta["dataset_title"]}</gco:CharacterString>
|
|
</gmd:name>
|
|
<gmd:description>
|
|
<gco:CharacterString>{meta["dataset_title"]}</gco:CharacterString>
|
|
</gmd:description>
|
|
</gmd:CI_OnlineResource>
|
|
</gmd:onLine>
|
|
<gmd:onLine>
|
|
<gmd:CI_OnlineResource>
|
|
<gmd:linkage>
|
|
<gmd:URL>{geoserver_links["wms_url"]}</gmd:URL>
|
|
</gmd:linkage>
|
|
<gmd:protocol>
|
|
<gco:CharacterString>WWW:LINK-1.0-http--link</gco:CharacterString>
|
|
</gmd:protocol>
|
|
<gmd:name>
|
|
<gco:CharacterString>{meta["dataset_title"]}</gco:CharacterString>
|
|
</gmd:name>
|
|
<gmd:description>
|
|
<gco:CharacterString>{meta["dataset_title"]}</gco:CharacterString>
|
|
</gmd:description>
|
|
</gmd:CI_OnlineResource>
|
|
</gmd:onLine>
|
|
<gmd:onLine>
|
|
<gmd:CI_OnlineResource>
|
|
<gmd:linkage>
|
|
<gmd:URL>{geoserver_links["wms_url"]}</gmd:URL>
|
|
</gmd:linkage>
|
|
<gmd:protocol>
|
|
<gco:CharacterString>OGC:WMS</gco:CharacterString>
|
|
</gmd:protocol>
|
|
<gmd:name>
|
|
<gco:CharacterString>{meta["dataset_title"]}</gco:CharacterString>
|
|
</gmd:name>
|
|
</gmd:CI_OnlineResource>
|
|
</gmd:onLine>
|
|
|
|
<gmd:onLine>
|
|
<gmd:CI_OnlineResource>
|
|
<gmd:linkage>
|
|
<gmd:URL>{geoserver_links["wfs_url"]}</gmd:URL>
|
|
</gmd:linkage>
|
|
<gmd:protocol>
|
|
<gco:CharacterString>OGC:WFS</gco:CharacterString>
|
|
</gmd:protocol>
|
|
<gmd:name>
|
|
<gco:CharacterString>{meta["dataset_title"]}</gco:CharacterString>
|
|
</gmd:name>
|
|
</gmd:CI_OnlineResource>
|
|
</gmd:onLine>
|
|
</gmd:MD_DigitalTransferOptions>
|
|
</gmd:transferOptions>
|
|
</gmd:MD_Distribution>
|
|
</gmd:distributionInfo>
|
|
<gmd:dataQualityInfo>
|
|
<gmd:DQ_DataQuality>
|
|
<gmd:scope>
|
|
<gmd:DQ_Scope>
|
|
<gmd:level>
|
|
<gmd:MD_ScopeCode codeListValue="dataset" codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_ScopeCode"/>
|
|
</gmd:level>
|
|
</gmd:DQ_Scope>
|
|
</gmd:scope>
|
|
<gmd:lineage>
|
|
<gmd:LI_Lineage>
|
|
<gmd:statement>
|
|
<gco:CharacterString>Data dihasilkan dari digitasi peta dasar skala 1:25000 menggunakan QGIS.</gco:CharacterString>
|
|
</gmd:statement>
|
|
</gmd:LI_Lineage>
|
|
</gmd:lineage>
|
|
</gmd:DQ_DataQuality>
|
|
</gmd:dataQualityInfo>
|
|
</gmd:MD_Metadata>
|
|
"""
|
|
|
|
|
|
# Geonetwork version 4.4.9.0
|
|
def upload_metadata_to_geonetwork(xml_metadata: str):
|
|
# session = requests.Session()
|
|
# session.auth = (GEONETWORK_USER, GEONETWORK_PASS)
|
|
|
|
# # 1. Get XSRF token
|
|
# try:
|
|
# info_url = f"{GEONETWORK_URL}/srv/eng/info?type=me"
|
|
# session.get(info_url)
|
|
# except requests.exceptions.RequestException as e:
|
|
# raise HTTPException(status_code=503, detail=f"Failed to connect to GeoNetwork: {e}")
|
|
|
|
# xsrf_token = session.cookies.get('XSRF-TOKEN')
|
|
# if not xsrf_token:
|
|
# raise HTTPException(status_code=500, detail="Could not retrieve XSRF-TOKEN from GeoNetwork.")
|
|
|
|
session, xsrf_token = create_gn_session()
|
|
|
|
headers = {
|
|
'X-XSRF-TOKEN': xsrf_token,
|
|
'Accept': 'application/json'
|
|
}
|
|
|
|
GN_API_RECORDS_URL = f"{GEONETWORK_URL}/srv/api/records"
|
|
|
|
# 2. GeoNetwork requires a multipart/form-data upload
|
|
files = {
|
|
'file': ('metadata.xml', xml_metadata, 'application/xml')
|
|
}
|
|
|
|
params = {
|
|
"ownerGroup": 1, # all
|
|
"ownerUser": 1 # admin
|
|
}
|
|
|
|
response = session.post(
|
|
GN_API_RECORDS_URL,
|
|
params=params,
|
|
files=files,
|
|
headers=headers,
|
|
cookies=session.cookies.get_dict()
|
|
)
|
|
|
|
metadata_infos = response.json().get("metadataInfos", {})
|
|
uuid = None
|
|
for records in metadata_infos.values():
|
|
if records and isinstance(records, list):
|
|
uuid = records[0].get("uuid")
|
|
break
|
|
if not uuid:
|
|
raise ValueError("UUID not found in GeoNetwork response")
|
|
|
|
record = publish_record(session, uuid)
|
|
print('[record]', record)
|
|
|
|
# print("response", response.json())
|
|
return response.json()
|
|
|
|
|
|
|
|
async def publish_metadata(table_name: str, geoserver_links: dict):
|
|
|
|
extent = await get_extent(table_name)
|
|
meta = await get_author_metadata(table_name)
|
|
xml = generate_metadata_xml(
|
|
table_name=meta["dataset_title"],
|
|
meta=meta,
|
|
extent=extent,
|
|
geoserver_links=geoserver_links
|
|
)
|
|
|
|
xml_clean = fix_xml_urls(xml)
|
|
response = upload_metadata_to_geonetwork(xml_clean)
|
|
|
|
uuid = response.get("uuid")
|
|
print(f"[GeoNetwork] Metadata uploaded. UUID = {uuid}")
|
|
|
|
return uuid
|
|
|
|
|
|
|
|
def publish_record(session, uuid):
|
|
print('[uuid]', uuid)
|
|
xsrf_token = session.cookies.get('XSRF-TOKEN')
|
|
|
|
headers = {
|
|
"X-XSRF-TOKEN": xsrf_token,
|
|
"Accept": "application/json",
|
|
"Content-Type": "application/json"
|
|
}
|
|
|
|
url = f"{GEONETWORK_URL}/srv/api/records/{uuid}/sharing"
|
|
|
|
payload = {
|
|
"clear": True,
|
|
"privileges": [
|
|
{
|
|
"group": 1,
|
|
"operations": {
|
|
"view": True
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
response = session.put(url, json=payload, headers=headers)
|
|
response.raise_for_status()
|
|
return response.json()
|
|
|