LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/ngw - ngw_api.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 5 481 1.0 %
Date: 2025-02-20 10:14:44 Functions: 1 38 2.6 %

          Line data    Source code
       1             : /*******************************************************************************
       2             :  *  Project: NextGIS Web Driver
       3             :  *  Purpose: Implements NextGIS Web Driver
       4             :  *  Author: Dmitry Baryshnikov, dmitry.baryshnikov@nextgis.com
       5             :  *  Language: C++
       6             :  *******************************************************************************
       7             :  *  The MIT License (MIT)
       8             :  *
       9             :  *  Copyright (c) 2018-2025, NextGIS
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  *******************************************************************************/
      13             : 
      14             : #include "ogr_ngw.h"
      15             : 
      16             : #include "cpl_http.h"
      17             : 
      18             : #include <limits>
      19             : 
      20             : namespace NGWAPI
      21             : {
      22             : 
      23           0 : static std::string GetErrorMessage(const CPLJSONObject &oRoot,
      24             :                                    const std::string &osErrorMessage)
      25             : {
      26           0 :     if (oRoot.IsValid())
      27             :     {
      28             :         std::string osErrorMessageInt =
      29           0 :             oRoot.GetString("message", osErrorMessage);
      30           0 :         if (!osErrorMessageInt.empty())
      31             :         {
      32           0 :             return osErrorMessageInt;
      33             :         }
      34             :     }
      35           0 :     return osErrorMessage;
      36             : }
      37             : 
      38           0 : bool CheckRequestResult(bool bResult, const CPLJSONObject &oRoot,
      39             :                         const std::string &osErrorMessage)
      40             : {
      41           0 :     if (!bResult)
      42             :     {
      43           0 :         auto osMsg = GetErrorMessage(oRoot, osErrorMessage);
      44             : 
      45           0 :         CPLError(CE_Failure, CPLE_AppDefined,
      46             :                  "NGW driver failed to fetch data with error: %s",
      47             :                  osMsg.c_str());
      48           0 :         return false;
      49             :     }
      50             : 
      51           0 :     return true;
      52             : }
      53             : 
      54           0 : static void ReportError(const GByte *pabyData, int nDataLen,
      55             :                         const std::string &osErrorMessage)
      56             : {
      57           0 :     CPLJSONDocument oResult;
      58           0 :     if (oResult.LoadMemory(pabyData, nDataLen))
      59             :     {
      60           0 :         CPLJSONObject oRoot = oResult.GetRoot();
      61           0 :         auto osMsg = GetErrorMessage(oRoot, osErrorMessage);
      62           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", osMsg.c_str());
      63             :     }
      64             :     else
      65             :     {
      66           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", osErrorMessage.c_str());
      67             :     }
      68           0 : }
      69             : 
      70           0 : bool CheckSupportedType(bool bIsRaster, const std::string &osType)
      71             : {
      72             :     //TODO: Add "raster_mosaic", "tileset", "wfsserver_service" and "wmsserver_service"
      73           0 :     if (bIsRaster)
      74             :     {
      75           0 :         if (osType == "mapserver_style" || osType == "qgis_vector_style" ||
      76           0 :             osType == "raster_style" || osType == "qgis_raster_style" ||
      77           0 :             osType == "basemap_layer" || osType == "webmap" ||
      78           0 :             osType == "wmsclient_layer" || osType == "raster_layer")
      79             :         {
      80           0 :             return true;
      81             :         }
      82             :     }
      83             :     else
      84             :     {
      85           0 :         if (osType == "vector_layer" || osType == "postgis_layer")
      86             :         {
      87           0 :             return true;
      88             :         }
      89             :     }
      90           0 :     return false;
      91             : }
      92             : 
      93           0 : std::string GetPermissionsURL(const std::string &osUrl,
      94             :                               const std::string &osResourceId)
      95             : {
      96           0 :     return osUrl + "/api/resource/" + osResourceId + "/permission";
      97             : }
      98             : 
      99           0 : std::string GetResourceURL(const std::string &osUrl,
     100             :                            const std::string &osResourceId)
     101             : {
     102           0 :     return osUrl + "/api/resource/" + osResourceId;
     103             : }
     104             : 
     105           0 : std::string GetChildrenURL(const std::string &osUrl,
     106             :                            const std::string &osResourceId)
     107             : {
     108           0 :     return osUrl + "/api/resource/?parent=" + osResourceId;
     109             : }
     110             : 
     111           0 : std::string GetFeatureURL(const std::string &osUrl,
     112             :                           const std::string &osResourceId)
     113             : {
     114           0 :     return osUrl + "/api/resource/" + osResourceId + "/feature/";
     115             : }
     116             : 
     117           0 : std::string GetTMSURL(const std::string &osUrl, const std::string &osResourceId)
     118             : {
     119           0 :     return osUrl +
     120             :            "/api/component/render/"
     121             :            "tile?z=${z}&amp;x=${x}&amp;y=${y}&amp;resource=" +
     122           0 :            osResourceId;
     123             : }
     124             : 
     125           0 : std::string GetSearchURL(const std::string &osUrl, const std::string &osKey,
     126             :                          const std::string &osValue)
     127             : {
     128           0 :     return osUrl + "/api/resource/search/?" + osKey + "=" + osValue;
     129             : }
     130             : 
     131             : std::string
     132           0 : GetFeaturePageURL(const std::string &osUrl, const std::string &osResourceId,
     133             :                   GIntBig nStart, int nCount, const std::string &osFields,
     134             :                   const std::string &osWhere, const std::string &osSpatialWhere,
     135             :                   const std::string &osExtensions, bool IsGeometryIgnored)
     136             : {
     137           0 :     std::string osFeatureUrl = GetFeatureURL(osUrl, osResourceId);
     138           0 :     bool bParamAdd = false;
     139           0 :     if (nCount > 0)
     140             :     {
     141           0 :         osFeatureUrl += "?offset=" + std::to_string(nStart) +
     142           0 :                         "&limit=" + std::to_string(nCount);
     143           0 :         bParamAdd = true;
     144             :     }
     145             : 
     146           0 :     if (!osFields.empty())
     147             :     {
     148           0 :         if (bParamAdd)
     149             :         {
     150           0 :             osFeatureUrl += "&fields=" + osFields;
     151             :         }
     152             :         else
     153             :         {
     154           0 :             osFeatureUrl += "?fields=" + osFields;
     155           0 :             bParamAdd = true;
     156             :         }
     157             :     }
     158             : 
     159           0 :     if (!osWhere.empty())
     160             :     {
     161           0 :         if (bParamAdd)
     162             :         {
     163           0 :             osFeatureUrl += "&" + osWhere;
     164             :         }
     165             :         else
     166             :         {
     167           0 :             osFeatureUrl += "?" + osWhere;
     168           0 :             bParamAdd = true;
     169             :         }
     170             :     }
     171             : 
     172           0 :     if (!osSpatialWhere.empty())
     173             :     {
     174           0 :         if (bParamAdd)
     175             :         {
     176           0 :             osFeatureUrl += "&intersects=" + osSpatialWhere;
     177             :         }
     178             :         else
     179             :         {
     180           0 :             osFeatureUrl += "?intersects=" + osSpatialWhere;
     181           0 :             bParamAdd = true;
     182             :         }
     183             :     }
     184             : 
     185           0 :     if (IsGeometryIgnored)
     186             :     {
     187           0 :         if (bParamAdd)
     188             :         {
     189           0 :             osFeatureUrl += "&geom=no";
     190             :         }
     191             :         else
     192             :         {
     193           0 :             osFeatureUrl += "?geom=no";
     194           0 :             bParamAdd = true;
     195             :         }
     196             :     }
     197             : 
     198           0 :     if (bParamAdd)
     199             :     {
     200           0 :         osFeatureUrl += "&extensions=" + osExtensions;
     201             :     }
     202             :     else
     203             :     {
     204           0 :         osFeatureUrl += "?extensions=" + osExtensions;
     205             :     }
     206             : 
     207           0 :     return osFeatureUrl;
     208             : }
     209             : 
     210           0 : std::string GetRouteURL(const std::string &osUrl)
     211             : {
     212           0 :     return osUrl + "/api/component/pyramid/route";
     213             : }
     214             : 
     215           0 : std::string GetUploadURL(const std::string &osUrl)
     216             : {
     217           0 :     return osUrl + "/api/component/file_upload/upload";
     218             : }
     219             : 
     220           0 : std::string GetVersionURL(const std::string &osUrl)
     221             : {
     222           0 :     return osUrl + "/api/component/pyramid/pkg_version";
     223             : }
     224             : 
     225           0 : std::string GetCOGURL(const std::string &osUrl, const std::string &osResourceId)
     226             : {
     227           0 :     return osUrl + "/api/resource/" + osResourceId + "/cog";
     228             : }
     229             : 
     230           0 : bool CheckVersion(const std::string &osVersion, int nMajor, int nMinor,
     231             :                   int nPatch)
     232             : {
     233           0 :     int nCurrentMajor(0);
     234           0 :     int nCurrentMinor(0);
     235           0 :     int nCurrentPatch(0);
     236             : 
     237           0 :     CPLStringList aosList(CSLTokenizeString2(osVersion.c_str(), ".", 0));
     238           0 :     if (aosList.size() > 2)
     239             :     {
     240           0 :         nCurrentMajor = atoi(aosList[0]);
     241           0 :         nCurrentMinor = atoi(aosList[1]);
     242           0 :         nCurrentPatch = atoi(aosList[2]);
     243             :     }
     244           0 :     else if (aosList.size() > 1)
     245             :     {
     246           0 :         nCurrentMajor = atoi(aosList[0]);
     247           0 :         nCurrentMinor = atoi(aosList[1]);
     248             :     }
     249           0 :     else if (aosList.size() > 0)
     250             :     {
     251           0 :         nCurrentMajor = atoi(aosList[0]);
     252             :     }
     253             : 
     254           0 :     int nCheckVersion = nMajor * 1000 + nMinor * 100 + nPatch;
     255           0 :     int nCurrentVersion =
     256           0 :         nCurrentMajor * 1000 + nCurrentMinor * 100 + nCurrentPatch;
     257           0 :     return nCurrentVersion >= nCheckVersion;
     258             : }
     259             : 
     260          50 : Uri ParseUri(const std::string &osUrl)
     261             : {
     262          50 :     Uri stOut;
     263          50 :     std::size_t nFound = osUrl.find(":");
     264          50 :     if (nFound == std::string::npos)
     265             :     {
     266          50 :         return stOut;
     267             :     }
     268             : 
     269           0 :     stOut.osPrefix = osUrl.substr(0, nFound);
     270           0 :     std::string osUrlInt = CPLString(osUrl.substr(nFound + 1)).tolower();
     271             : 
     272           0 :     nFound = osUrlInt.find("/resource/");
     273           0 :     if (nFound == std::string::npos)
     274             :     {
     275           0 :         return stOut;
     276             :     }
     277             : 
     278           0 :     stOut.osAddress = osUrlInt.substr(0, nFound);
     279             : 
     280             :     std::string osResourceId =
     281           0 :         CPLString(osUrlInt.substr(nFound + strlen("/resource/"))).Trim();
     282             : 
     283           0 :     nFound = osResourceId.find('/');
     284           0 :     if (nFound != std::string::npos)
     285             :     {
     286           0 :         stOut.osResourceId = osResourceId.substr(0, nFound);
     287           0 :         stOut.osNewResourceName = osResourceId.substr(nFound + 1);
     288             :     }
     289             :     else
     290             :     {
     291           0 :         stOut.osResourceId = std::move(osResourceId);
     292             :     }
     293             : 
     294           0 :     return stOut;
     295             : }
     296             : 
     297           0 : std::string CreateResource(const std::string &osUrl,
     298             :                            const std::string &osPayload,
     299             :                            const CPLStringList &aosHTTPOptions)
     300             : {
     301           0 :     CPLErrorReset();
     302           0 :     std::string osPayloadInt = "POSTFIELDS=" + osPayload;
     303             : 
     304           0 :     CPLStringList aosHTTPOptionsInt(aosHTTPOptions);
     305             : 
     306           0 :     aosHTTPOptionsInt.AddString("CUSTOMREQUEST=POST");
     307           0 :     aosHTTPOptionsInt.AddString(osPayloadInt.c_str());
     308             :     aosHTTPOptionsInt.AddString(
     309           0 :         "HEADERS=Content-Type: application/json\r\nAccept: */*");
     310             : 
     311           0 :     CPLDebug("NGW", "CreateResource request payload: %s", osPayload.c_str());
     312             : 
     313           0 :     CPLJSONDocument oCreateReq;
     314             :     bool bResult =
     315           0 :         oCreateReq.LoadUrl(GetResourceURL(osUrl, ""), aosHTTPOptionsInt);
     316           0 :     std::string osResourceId("-1");
     317           0 :     CPLJSONObject oRoot = oCreateReq.GetRoot();
     318           0 :     if (CheckRequestResult(bResult, oRoot, "CreateResource request failed"))
     319             :     {
     320           0 :         osResourceId = oRoot.GetString("id", "-1");
     321             :     }
     322           0 :     return osResourceId;
     323             : }
     324             : 
     325           0 : bool UpdateResource(const std::string &osUrl, const std::string &osResourceId,
     326             :                     const std::string &osPayload,
     327             :                     const CPLStringList &aosHTTPOptions)
     328             : {
     329           0 :     CPLErrorReset();
     330           0 :     std::string osPayloadInt = "POSTFIELDS=" + osPayload;
     331             : 
     332           0 :     CPLStringList aosHTTPOptionsInt(aosHTTPOptions);
     333           0 :     aosHTTPOptionsInt.AddString("CUSTOMREQUEST=PUT");
     334           0 :     aosHTTPOptionsInt.AddString(osPayloadInt.c_str());
     335             :     aosHTTPOptionsInt.AddString(
     336           0 :         "HEADERS=Content-Type: application/json\r\nAccept: */*");
     337             : 
     338           0 :     CPLDebug("NGW", "UpdateResource request payload: %s", osPayload.c_str());
     339             : 
     340           0 :     CPLHTTPResult *psResult = CPLHTTPFetch(
     341           0 :         GetResourceURL(osUrl, osResourceId).c_str(), aosHTTPOptionsInt);
     342           0 :     bool bResult = false;
     343           0 :     if (psResult)
     344             :     {
     345           0 :         bResult = psResult->nStatus == 0 && psResult->pszErrBuf == nullptr;
     346             : 
     347             :         // Get error message.
     348           0 :         if (!bResult)
     349             :         {
     350           0 :             ReportError(psResult->pabyData, psResult->nDataLen,
     351             :                         "UpdateResource request failed");
     352             :         }
     353           0 :         CPLHTTPDestroyResult(psResult);
     354             :     }
     355             :     else
     356             :     {
     357           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Update resource %s failed",
     358             :                  osResourceId.c_str());
     359             :     }
     360           0 :     return bResult;
     361             : }
     362             : 
     363           0 : bool DeleteResource(const std::string &osUrl, const std::string &osResourceId,
     364             :                     const CPLStringList &aosHTTPOptions)
     365             : {
     366           0 :     CPLErrorReset();
     367           0 :     CPLStringList aosHTTPOptionsInt(aosHTTPOptions);
     368             : 
     369           0 :     aosHTTPOptionsInt.AddString("CUSTOMREQUEST=DELETE");
     370           0 :     auto osUrlNew = GetResourceURL(osUrl, osResourceId);
     371           0 :     CPLHTTPResult *psResult = CPLHTTPFetch(osUrlNew.c_str(), aosHTTPOptionsInt);
     372           0 :     bool bResult = false;
     373           0 :     if (psResult)
     374             :     {
     375           0 :         bResult = psResult->nStatus == 0 && psResult->pszErrBuf == nullptr;
     376             :         // Get error message.
     377           0 :         if (!bResult)
     378             :         {
     379           0 :             ReportError(psResult->pabyData, psResult->nDataLen,
     380             :                         "DeleteResource request failed");
     381             :         }
     382           0 :         CPLHTTPDestroyResult(psResult);
     383             :     }
     384           0 :     return bResult;
     385             : }
     386             : 
     387           0 : bool RenameResource(const std::string &osUrl, const std::string &osResourceId,
     388             :                     const std::string &osNewName,
     389             :                     const CPLStringList &aosHTTPOptions)
     390             : {
     391           0 :     CPLJSONObject oPayload;
     392           0 :     CPLJSONObject oResource("resource", oPayload);
     393           0 :     oResource.Add("display_name", osNewName);
     394           0 :     std::string osPayload = oPayload.Format(CPLJSONObject::PrettyFormat::Plain);
     395             : 
     396           0 :     return UpdateResource(osUrl, osResourceId, osPayload, aosHTTPOptions);
     397             : }
     398             : 
     399           0 : OGRwkbGeometryType NGWGeomTypeToOGRGeomType(const std::string &osGeomType)
     400             : {
     401             :     // http://docs.nextgis.com/docs_ngweb_dev/doc/developer/vector_data_types.html#nextgisweb.feature_layer.interface.GEOM_TYPE
     402           0 :     if (osGeomType == "POINT")
     403           0 :         return wkbPoint;
     404           0 :     else if (osGeomType == "LINESTRING")
     405           0 :         return wkbLineString;
     406           0 :     else if (osGeomType == "POLYGON")
     407           0 :         return wkbPolygon;
     408           0 :     else if (osGeomType == "MULTIPOINT")
     409           0 :         return wkbMultiPoint;
     410           0 :     else if (osGeomType == "MULTILINESTRING")
     411           0 :         return wkbMultiLineString;
     412           0 :     else if (osGeomType == "MULTIPOLYGON")
     413           0 :         return wkbMultiPolygon;
     414           0 :     else if (osGeomType == "POINTZ")
     415           0 :         return wkbPoint25D;
     416           0 :     else if (osGeomType == "LINESTRINGZ")
     417           0 :         return wkbLineString25D;
     418           0 :     else if (osGeomType == "POLYGONZ")
     419           0 :         return wkbPolygon25D;
     420           0 :     else if (osGeomType == "MULTIPOINTZ")
     421           0 :         return wkbMultiPoint25D;
     422           0 :     else if (osGeomType == "MULTILINESTRINGZ")
     423           0 :         return wkbMultiLineString25D;
     424           0 :     else if (osGeomType == "MULTIPOLYGONZ")
     425           0 :         return wkbMultiPolygon25D;
     426             :     else
     427           0 :         return wkbUnknown;
     428             : }
     429             : 
     430           0 : std::string OGRGeomTypeToNGWGeomType(OGRwkbGeometryType eType)
     431             : {
     432           0 :     switch (eType)
     433             :     {  // Don't flatten
     434           0 :         case wkbPoint:
     435           0 :             return "POINT";
     436           0 :         case wkbLineString:
     437           0 :             return "LINESTRING";
     438           0 :         case wkbPolygon:
     439           0 :             return "POLYGON";
     440           0 :         case wkbMultiPoint:
     441           0 :             return "MULTIPOINT";
     442           0 :         case wkbMultiLineString:
     443           0 :             return "MULTILINESTRING";
     444           0 :         case wkbMultiPolygon:
     445           0 :             return "MULTIPOLYGON";
     446           0 :         case wkbPoint25D:
     447           0 :             return "POINTZ";
     448           0 :         case wkbLineString25D:
     449           0 :             return "LINESTRINGZ";
     450           0 :         case wkbPolygon25D:
     451           0 :             return "POLYGONZ";
     452           0 :         case wkbMultiPoint25D:
     453           0 :             return "MULTIPOINTZ";
     454           0 :         case wkbMultiLineString25D:
     455           0 :             return "MULTILINESTRINGZ";
     456           0 :         case wkbMultiPolygon25D:
     457           0 :             return "MULTIPOLYGONZ";
     458           0 :         default:
     459           0 :             return "";
     460             :     }
     461             : }
     462             : 
     463           0 : OGRFieldType NGWFieldTypeToOGRFieldType(const std::string &osFieldType)
     464             : {
     465             :     // http://docs.nextgis.com/docs_ngweb_dev/doc/developer/vector_data_types.html#nextgisweb.feature_layer.interface.FIELD_TYPE
     466           0 :     if (osFieldType == "INTEGER")
     467           0 :         return OFTInteger;
     468           0 :     else if (osFieldType == "BIGINT")
     469           0 :         return OFTInteger64;
     470           0 :     else if (osFieldType == "REAL")
     471           0 :         return OFTReal;
     472           0 :     else if (osFieldType == "STRING")
     473           0 :         return OFTString;
     474           0 :     else if (osFieldType == "DATE")
     475           0 :         return OFTDate;
     476           0 :     else if (osFieldType == "TIME")
     477           0 :         return OFTTime;
     478           0 :     else if (osFieldType == "DATETIME")
     479           0 :         return OFTDateTime;
     480             :     else
     481           0 :         return OFTString;
     482             : }
     483             : 
     484           0 : std::string OGRFieldTypeToNGWFieldType(OGRFieldType eType)
     485             : {
     486           0 :     switch (eType)
     487             :     {
     488           0 :         case OFTInteger:
     489           0 :             return "INTEGER";
     490           0 :         case OFTInteger64:
     491           0 :             return "BIGINT";
     492           0 :         case OFTReal:
     493           0 :             return "REAL";
     494           0 :         case OFTString:
     495           0 :             return "STRING";
     496           0 :         case OFTDate:
     497           0 :             return "DATE";
     498           0 :         case OFTTime:
     499           0 :             return "TIME";
     500           0 :         case OFTDateTime:
     501           0 :             return "DATETIME";
     502           0 :         default:
     503           0 :             return "STRING";
     504             :     }
     505             : }
     506             : 
     507           0 : Permissions CheckPermissions(const std::string &osUrl,
     508             :                              const std::string &osResourceId,
     509             :                              const CPLStringList &aosHTTPOptions,
     510             :                              bool bReadWrite)
     511             : {
     512           0 :     Permissions stOut;
     513           0 :     CPLErrorReset();
     514           0 :     CPLJSONDocument oPermissionReq;
     515             : 
     516           0 :     auto osUrlNew = GetPermissionsURL(osUrl, osResourceId);
     517           0 :     bool bResult = oPermissionReq.LoadUrl(osUrlNew, aosHTTPOptions);
     518             : 
     519           0 :     CPLJSONObject oRoot = oPermissionReq.GetRoot();
     520           0 :     if (CheckRequestResult(bResult, oRoot, "Get permissions failed"))
     521             :     {
     522           0 :         stOut.bResourceCanRead = oRoot.GetBool("resource/read", true);
     523           0 :         stOut.bResourceCanCreate = oRoot.GetBool("resource/create", bReadWrite);
     524           0 :         stOut.bResourceCanUpdate = oRoot.GetBool("resource/update", bReadWrite);
     525           0 :         stOut.bResourceCanDelete = oRoot.GetBool("resource/delete", bReadWrite);
     526             : 
     527           0 :         stOut.bDatastructCanRead = oRoot.GetBool("datastruct/read", true);
     528           0 :         stOut.bDatastructCanWrite =
     529           0 :             oRoot.GetBool("datastruct/write", bReadWrite);
     530             : 
     531           0 :         stOut.bDataCanRead = oRoot.GetBool("data/read", true);
     532           0 :         stOut.bDataCanWrite = oRoot.GetBool("data/write", bReadWrite);
     533             : 
     534           0 :         stOut.bMetadataCanRead = oRoot.GetBool("metadata/read", true);
     535           0 :         stOut.bMetadataCanWrite = oRoot.GetBool("metadata/write", bReadWrite);
     536             : 
     537           0 :         CPLErrorReset();  // If we are here no error occurred
     538           0 :         return stOut;
     539             :     }
     540             : 
     541           0 :     return stOut;
     542             : }
     543             : 
     544           0 : std::string GetFeatureCount(const std::string &osUrl,
     545             :                             const std::string &osResourceId)
     546             : {
     547           0 :     return osUrl + "/api/resource/" + osResourceId + "/feature_count";
     548             : }
     549             : 
     550           0 : std::string GetLayerExtent(const std::string &osUrl,
     551             :                            const std::string &osResourceId)
     552             : {
     553           0 :     return osUrl + "/api/resource/" + osResourceId + "/extent";
     554             : }
     555             : 
     556           0 : std::string GetResmetaSuffix(CPLJSONObject::Type eType)
     557             : {
     558           0 :     switch (eType)
     559             :     {
     560           0 :         case CPLJSONObject::Type::Integer:
     561             :         case CPLJSONObject::Type::Long:
     562           0 :             return ".d";
     563           0 :         case CPLJSONObject::Type::Double:
     564           0 :             return ".f";
     565           0 :         default:
     566           0 :             return "";
     567             :     }
     568             : }
     569             : 
     570           0 : void FillResmeta(const CPLJSONObject &oRoot, char **papszMetadata)
     571             : {
     572           0 :     CPLJSONObject oResMeta("resmeta", oRoot);
     573           0 :     CPLJSONObject oResMetaItems("items", oResMeta);
     574           0 :     CPLStringList oaMetadata(papszMetadata, FALSE);
     575           0 :     for (int i = 0; i < oaMetadata.size(); ++i)
     576             :     {
     577           0 :         std::string osItem = oaMetadata[i];
     578           0 :         size_t nPos = osItem.find("=");
     579           0 :         if (nPos != std::string::npos)
     580             :         {
     581           0 :             std::string osItemName = osItem.substr(0, nPos);
     582           0 :             CPLString osItemValue = osItem.substr(nPos + 1);
     583             : 
     584           0 :             if (osItemName.size() > 2)
     585             :             {
     586           0 :                 size_t nSuffixPos = osItemName.size() - 2;
     587           0 :                 std::string osSuffix = osItemName.substr(nSuffixPos);
     588           0 :                 if (osSuffix == ".d")
     589             :                 {
     590           0 :                     GInt64 nVal = CPLAtoGIntBig(osItemValue.c_str());
     591           0 :                     oResMetaItems.Add(osItemName.substr(0, nSuffixPos), nVal);
     592           0 :                     continue;
     593             :                 }
     594             : 
     595           0 :                 if (osSuffix == ".f")
     596             :                 {
     597           0 :                     oResMetaItems.Add(osItemName.substr(0, nSuffixPos),
     598             :                                       CPLAtofM(osItemValue.c_str()));
     599           0 :                     continue;
     600             :                 }
     601             :             }
     602             : 
     603           0 :             oResMetaItems.Add(osItemName, osItemValue);
     604             :         }
     605             :     }
     606           0 : }
     607             : 
     608           0 : bool FlushMetadata(const std::string &osUrl, const std::string &osResourceId,
     609             :                    char **papszMetadata, const CPLStringList &aosHTTPOptions)
     610             : {
     611           0 :     if (nullptr == papszMetadata)
     612             :     {
     613           0 :         return true;
     614             :     }
     615           0 :     CPLJSONObject oMetadataJson;
     616           0 :     FillResmeta(oMetadataJson, papszMetadata);
     617             : 
     618           0 :     return UpdateResource(
     619             :         osUrl, osResourceId,
     620           0 :         oMetadataJson.Format(CPLJSONObject::PrettyFormat::Plain),
     621           0 :         aosHTTPOptions);
     622             : }
     623             : 
     624           0 : bool DeleteFeature(const std::string &osUrl, const std::string &osResourceId,
     625             :                    const std::string &osFeatureId,
     626             :                    const CPLStringList &aosHTTPOptions)
     627             : {
     628           0 :     CPLErrorReset();
     629           0 :     CPLStringList aosHTTPOptionsInt(aosHTTPOptions);
     630           0 :     aosHTTPOptionsInt.AddString("CUSTOMREQUEST=DELETE");
     631           0 :     std::string osUrlInt = GetFeatureURL(osUrl, osResourceId) + osFeatureId;
     632           0 :     CPLHTTPResult *psResult = CPLHTTPFetch(osUrlInt.c_str(), aosHTTPOptionsInt);
     633           0 :     bool bResult = false;
     634           0 :     if (psResult)
     635             :     {
     636           0 :         bResult = psResult->nStatus == 0 && psResult->pszErrBuf == nullptr;
     637             :         // Get error message.
     638           0 :         if (!bResult)
     639             :         {
     640           0 :             ReportError(psResult->pabyData, psResult->nDataLen,
     641             :                         "DeleteFeature request failed");
     642             :         }
     643           0 :         CPLHTTPDestroyResult(psResult);
     644             :     }
     645           0 :     return bResult;
     646             : }
     647             : 
     648           0 : bool DeleteFeatures(const std::string &osUrl, const std::string &osResourceId,
     649             :                     const std::string &osFeaturesIDJson,
     650             :                     const CPLStringList &aosHTTPOptions)
     651             : {
     652           0 :     CPLErrorReset();
     653           0 :     std::string osPayloadInt = "POSTFIELDS=" + osFeaturesIDJson;
     654             : 
     655           0 :     CPLStringList aosHTTPOptionsInt(aosHTTPOptions);
     656           0 :     aosHTTPOptionsInt.AddString("CUSTOMREQUEST=DELETE");
     657           0 :     aosHTTPOptionsInt.AddString(osPayloadInt.c_str());
     658             :     aosHTTPOptionsInt.AddString(
     659           0 :         "HEADERS=Content-Type: application/json\r\nAccept: */*");
     660             : 
     661           0 :     std::string osUrlInt = GetFeatureURL(osUrl, osResourceId);
     662           0 :     CPLHTTPResult *psResult = CPLHTTPFetch(osUrlInt.c_str(), aosHTTPOptionsInt);
     663           0 :     bool bResult = false;
     664           0 :     if (psResult)
     665             :     {
     666           0 :         bResult = psResult->nStatus == 0 && psResult->pszErrBuf == nullptr;
     667             :         // Get error message.
     668           0 :         if (!bResult)
     669             :         {
     670           0 :             ReportError(psResult->pabyData, psResult->nDataLen,
     671             :                         "DeleteFeatures request failed");
     672             :         }
     673           0 :         CPLHTTPDestroyResult(psResult);
     674             :     }
     675           0 :     return bResult;
     676             : }
     677             : 
     678           0 : GIntBig CreateFeature(const std::string &osUrl, const std::string &osResourceId,
     679             :                       const std::string &osFeatureJson,
     680             :                       const CPLStringList &aosHTTPOptions)
     681             : {
     682           0 :     CPLErrorReset();
     683           0 :     std::string osPayloadInt = "POSTFIELDS=" + osFeatureJson;
     684             : 
     685           0 :     CPLStringList aosHTTPOptionsInt(aosHTTPOptions);
     686           0 :     aosHTTPOptionsInt.AddString("CUSTOMREQUEST=POST");
     687           0 :     aosHTTPOptionsInt.AddString(osPayloadInt.c_str());
     688             :     aosHTTPOptionsInt.AddString(
     689           0 :         "HEADERS=Content-Type: application/json\r\nAccept: */*");
     690             : 
     691           0 :     CPLDebug("NGW", "CreateFeature request payload: %s", osFeatureJson.c_str());
     692             : 
     693           0 :     std::string osUrlInt = GetFeatureURL(osUrl, osResourceId);
     694             : 
     695           0 :     CPLJSONDocument oCreateFeatureReq;
     696           0 :     bool bResult = oCreateFeatureReq.LoadUrl(osUrlInt, aosHTTPOptionsInt);
     697             : 
     698           0 :     CPLJSONObject oRoot = oCreateFeatureReq.GetRoot();
     699           0 :     GIntBig nOutFID = OGRNullFID;
     700           0 :     if (CheckRequestResult(bResult, oRoot, "Create new feature failed"))
     701             :     {
     702           0 :         nOutFID = oRoot.GetLong("id", OGRNullFID);
     703             :     }
     704             : 
     705           0 :     CPLDebug("NGW", "CreateFeature new FID: " CPL_FRMT_GIB, nOutFID);
     706           0 :     return nOutFID;
     707             : }
     708             : 
     709           0 : bool UpdateFeature(const std::string &osUrl, const std::string &osResourceId,
     710             :                    const std::string &osFeatureId,
     711             :                    const std::string &osFeatureJson,
     712             :                    const CPLStringList &aosHTTPOptions)
     713             : {
     714           0 :     CPLErrorReset();
     715           0 :     std::string osPayloadInt = "POSTFIELDS=" + osFeatureJson;
     716             : 
     717           0 :     CPLStringList aosHTTPOptionsInt(aosHTTPOptions);
     718           0 :     aosHTTPOptionsInt.AddString("CUSTOMREQUEST=PUT");
     719           0 :     aosHTTPOptionsInt.AddString(osPayloadInt.c_str());
     720             :     aosHTTPOptionsInt.AddString(
     721           0 :         "HEADERS=Content-Type: application/json\r\nAccept: */*");
     722             : 
     723           0 :     CPLDebug("NGW", "UpdateFeature request payload: %s", osFeatureJson.c_str());
     724             : 
     725           0 :     std::string osUrlInt = GetFeatureURL(osUrl, osResourceId) + osFeatureId;
     726           0 :     CPLHTTPResult *psResult = CPLHTTPFetch(osUrlInt.c_str(), aosHTTPOptionsInt);
     727           0 :     bool bResult = false;
     728           0 :     if (psResult)
     729             :     {
     730           0 :         bResult = psResult->nStatus == 0 && psResult->pszErrBuf == nullptr;
     731             : 
     732             :         // Get error message.
     733           0 :         if (!bResult)
     734             :         {
     735           0 :             ReportError(psResult->pabyData, psResult->nDataLen,
     736             :                         "UpdateFeature request failed");
     737             :         }
     738           0 :         CPLHTTPDestroyResult(psResult);
     739             :     }
     740           0 :     return bResult;
     741             : }
     742             : 
     743           0 : std::vector<GIntBig> PatchFeatures(const std::string &osUrl,
     744             :                                    const std::string &osResourceId,
     745             :                                    const std::string &osFeaturesJson,
     746             :                                    const CPLStringList &aosHTTPOptions)
     747             : {
     748           0 :     std::vector<GIntBig> aoFIDs;
     749           0 :     CPLErrorReset();
     750           0 :     std::string osPayloadInt = "POSTFIELDS=" + osFeaturesJson;
     751             : 
     752           0 :     CPLStringList aosHTTPOptionsInt(aosHTTPOptions);
     753           0 :     aosHTTPOptionsInt.AddString("CUSTOMREQUEST=PATCH");
     754           0 :     aosHTTPOptionsInt.AddString(osPayloadInt.c_str());
     755             :     aosHTTPOptionsInt.AddString(
     756           0 :         "HEADERS=Content-Type: application/json\r\nAccept: */*");
     757             : 
     758           0 :     CPLDebug("NGW", "PatchFeatures request payload: %s",
     759             :              osFeaturesJson.c_str());
     760             : 
     761           0 :     std::string osUrlInt = GetFeatureURL(osUrl, osResourceId);
     762           0 :     CPLJSONDocument oPatchFeatureReq;
     763           0 :     bool bResult = oPatchFeatureReq.LoadUrl(osUrlInt, aosHTTPOptionsInt);
     764             : 
     765           0 :     CPLJSONObject oRoot = oPatchFeatureReq.GetRoot();
     766           0 :     if (CheckRequestResult(bResult, oRoot, "Patch features failed"))
     767             :     {
     768           0 :         CPLJSONArray aoJSONIDs = oRoot.ToArray();
     769           0 :         for (int i = 0; i < aoJSONIDs.Size(); ++i)
     770             :         {
     771           0 :             GIntBig nOutFID = aoJSONIDs[i].GetLong("id", OGRNullFID);
     772           0 :             aoFIDs.push_back(nOutFID);
     773             :         }
     774             :     }
     775           0 :     return aoFIDs;
     776             : }
     777             : 
     778           0 : bool GetExtent(const std::string &osUrl, const std::string &osResourceId,
     779             :                const CPLStringList &aosHTTPOptions, int nEPSG,
     780             :                OGREnvelope &stExtent)
     781             : {
     782           0 :     CPLErrorReset();
     783           0 :     CPLJSONDocument oExtentReq;
     784             :     double dfRetryDelaySecs =
     785           0 :         CPLAtof(aosHTTPOptions.FetchNameValueDef("RETRY_DELAY", "2.5"));
     786           0 :     int nMaxRetries = atoi(aosHTTPOptions.FetchNameValueDef("MAX_RETRY", "0"));
     787           0 :     int nRetryCount = 0;
     788             :     while (true)
     789             :     {
     790           0 :         auto osUrlNew = GetLayerExtent(osUrl, osResourceId);
     791           0 :         bool bResult = oExtentReq.LoadUrl(osUrlNew, aosHTTPOptions);
     792             : 
     793           0 :         CPLJSONObject oRoot = oExtentReq.GetRoot();
     794           0 :         if (CheckRequestResult(bResult, oRoot, "Get extent failed"))
     795             :         {
     796             :             // Response extent spatial reference is EPSG:4326.
     797             : 
     798           0 :             double dfMinX = oRoot.GetDouble("extent/minLon");
     799           0 :             double dfMinY = oRoot.GetDouble("extent/minLat");
     800           0 :             double dfMaxX = oRoot.GetDouble("extent/maxLon");
     801           0 :             double dfMaxY = oRoot.GetDouble("extent/maxLat");
     802             : 
     803             :             double adfCoordinatesX[4];
     804             :             double adfCoordinatesY[4];
     805           0 :             adfCoordinatesX[0] = dfMinX;
     806           0 :             adfCoordinatesY[0] = dfMinY;
     807           0 :             adfCoordinatesX[1] = dfMinX;
     808           0 :             adfCoordinatesY[1] = dfMaxY;
     809           0 :             adfCoordinatesX[2] = dfMaxX;
     810           0 :             adfCoordinatesY[2] = dfMaxY;
     811           0 :             adfCoordinatesX[3] = dfMaxX;
     812           0 :             adfCoordinatesY[3] = dfMinY;
     813             : 
     814           0 :             OGRSpatialReference o4326SRS;
     815           0 :             o4326SRS.SetWellKnownGeogCS("WGS84");
     816           0 :             o4326SRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     817           0 :             OGRSpatialReference o3857SRS;
     818           0 :             o3857SRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     819           0 :             if (o3857SRS.importFromEPSG(nEPSG) != OGRERR_NONE)
     820             :             {
     821           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     822             :                          "Project extent SRS to EPSG:3857 failed");
     823           0 :                 return false;
     824             :             }
     825             : 
     826             :             OGRCoordinateTransformation *poTransform =
     827           0 :                 OGRCreateCoordinateTransformation(&o4326SRS, &o3857SRS);
     828           0 :             if (poTransform)
     829             :             {
     830           0 :                 poTransform->Transform(4, adfCoordinatesX, adfCoordinatesY);
     831           0 :                 delete poTransform;
     832             : 
     833           0 :                 stExtent.MinX = std::numeric_limits<double>::max();
     834           0 :                 stExtent.MaxX = std::numeric_limits<double>::min();
     835           0 :                 stExtent.MinY = std::numeric_limits<double>::max();
     836           0 :                 stExtent.MaxY = std::numeric_limits<double>::min();
     837             : 
     838           0 :                 for (int i = 1; i < 4; ++i)
     839             :                 {
     840           0 :                     if (stExtent.MinX > adfCoordinatesX[i])
     841             :                     {
     842           0 :                         stExtent.MinX = adfCoordinatesX[i];
     843             :                     }
     844           0 :                     if (stExtent.MaxX < adfCoordinatesX[i])
     845             :                     {
     846           0 :                         stExtent.MaxX = adfCoordinatesX[i];
     847             :                     }
     848           0 :                     if (stExtent.MinY > adfCoordinatesY[i])
     849             :                     {
     850           0 :                         stExtent.MinY = adfCoordinatesY[i];
     851             :                     }
     852           0 :                     if (stExtent.MaxY < adfCoordinatesY[i])
     853             :                     {
     854           0 :                         stExtent.MaxY = adfCoordinatesY[i];
     855             :                     }
     856             :                 }
     857             :             }
     858           0 :             CPLErrorReset();  // If we are here no error occurred
     859           0 :             return true;
     860             :         }
     861             : 
     862           0 :         if (nRetryCount >= nMaxRetries)
     863             :         {
     864           0 :             return false;
     865             :         }
     866             : 
     867           0 :         CPLSleep(dfRetryDelaySecs);
     868           0 :         nRetryCount++;
     869           0 :     }
     870             :     return false;
     871             : }
     872             : 
     873           0 : CPLJSONObject UploadFile(const std::string &osUrl,
     874             :                          const std::string &osFilePath,
     875             :                          const CPLStringList &aosHTTPOptions,
     876             :                          GDALProgressFunc pfnProgress, void *pProgressData)
     877             : {
     878           0 :     CPLErrorReset();
     879           0 :     CPLStringList aosHTTPOptionsInt(aosHTTPOptions);
     880             :     aosHTTPOptionsInt.AddString(
     881           0 :         CPLSPrintf("FORM_FILE_PATH=%s", osFilePath.c_str()));
     882           0 :     aosHTTPOptionsInt.AddString("FORM_FILE_NAME=file");
     883             : 
     884           0 :     const char *pszFormFileName = CPLGetFilename(osFilePath.c_str());
     885           0 :     aosHTTPOptionsInt.AddString("FORM_KEY_0=name");
     886           0 :     aosHTTPOptionsInt.AddString(CPLSPrintf("FORM_VALUE_0=%s", pszFormFileName));
     887           0 :     aosHTTPOptionsInt.AddString("FORM_ITEM_COUNT=1");
     888             : 
     889             :     CPLHTTPResult *psResult =
     890           0 :         CPLHTTPFetchEx(GetUploadURL(osUrl).c_str(), aosHTTPOptionsInt,
     891           0 :                        pfnProgress, pProgressData, nullptr, nullptr);
     892           0 :     CPLJSONObject oResult;
     893           0 :     if (psResult)
     894             :     {
     895           0 :         const bool bResult =
     896           0 :             psResult->nStatus == 0 && psResult->pszErrBuf == nullptr;
     897             : 
     898             :         // Get error message.
     899           0 :         if (!bResult)
     900             :         {
     901           0 :             ReportError(psResult->pabyData, psResult->nDataLen,
     902             :                         "Upload file request failed");
     903             :         }
     904             :         else
     905             :         {
     906           0 :             CPLJSONDocument oFileJson;
     907           0 :             if (oFileJson.LoadMemory(psResult->pabyData, psResult->nDataLen))
     908             :             {
     909           0 :                 oResult = oFileJson.GetRoot();
     910             :             }
     911             :         }
     912           0 :         CPLHTTPDestroyResult(psResult);
     913             :     }
     914             :     else
     915             :     {
     916           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Upload file %s failed",
     917             :                  osFilePath.c_str());
     918             :     }
     919           0 :     return oResult;
     920             : }
     921             : 
     922             : }  // namespace NGWAPI

Generated by: LCOV version 1.14