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 457 1.1 %
Date: 2024-11-21 22:18:42 Functions: 1 32 3.1 %

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

Generated by: LCOV version 1.14