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

Generated by: LCOV version 1.14