arcgis: add endpoint to add/edit/delete features (#86679)
gitea/passerelle/pipeline/head This commit looks good Details

This commit is contained in:
Serghei Mihai 2024-02-07 14:17:46 +01:00
parent 36dfa9508e
commit 38d3fbbf4e
2 changed files with 123 additions and 0 deletions

View File

@ -14,6 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
import string
from urllib import parse as urlparse
@ -32,6 +33,42 @@ from passerelle.utils.conversion import num2deg
from passerelle.utils.jsonresponse import APIError
from passerelle.utils.templates import render_to_string, validate_template
EDIT_ITEM_SCHEMA = {
'$schema': 'http://json-schema.org/draft-04/schema#',
'title': 'Item schema',
'description': '',
'type': 'object',
'properties': {
'geometry': {
'type': 'object',
'properties': {
'x': {'type': 'string'},
'y': {'type': 'string'},
},
},
'attributes': {'type': 'object'},
},
'required': ['attributes'],
}
EDIT_SCHEMA = {
'$schema': 'http://json-schema.org/draft-04/schema#',
'title': 'Edit payload',
'description': '',
'type': 'object',
'properties': {
'adds': {
'type': 'array',
'description': 'Adds object',
'items': EDIT_ITEM_SCHEMA,
},
'updates': {'type': 'array', 'description': 'Updates object', 'items': EDIT_ITEM_SCHEMA},
'deletes': {'type': 'array', 'description': 'Deletes object', 'items': {'type': 'string'}},
},
'minProperties': 1,
'unflatten': True,
}
class ArcGISError(APIError):
pass
@ -316,6 +353,45 @@ class ArcGIS(BaseResource, HTTPResource):
text_fieldname=text_fieldname,
)
@endpoint(
name='featureservice-applyedits',
description=_('Feature Service Apply Edits'),
parameters={
'folder': {
'description': _('Folder name'),
'example_value': 'Specialty',
},
'service': {
'description': _('Service name'),
'example_value': 'ESRI_StateCityHighway_USA',
},
'layer': {
'description': _('Layer or table name'),
'example_value': '1',
},
},
post={'request_body': {'schema': {'application/json': EDIT_SCHEMA}}},
)
def featureservice_applyedits(
self,
request,
post_data,
service,
layer='0',
folder='',
):
# implement "apply edits" feature service
# https://developers.arcgis.com/rest/services-reference/enterprise/apply-edits-feature-service-layer-.htm
uri = 'services/'
if folder:
uri += folder + '/'
uri = uri + service + '/FeatureServer/' + layer + '/applyEdits'
params = {'f': 'pjson'}
for key, value in post_data.items():
post_data[key] = json.dumps(value)
params.update(post_data)
return {'data': self.request(urlparse.urljoin(self.base_url, uri), data=params)}
@endpoint(
name='tile',
description=_('Tiles layer'),

View File

@ -162,6 +162,12 @@ ERRORS = [
({'error': 'string crash'}, 'unknown ArcGIS/token error'),
]
EDITS_RESPONSE = '''{
"addResults": [{"objectId": 1281, "success": true}],
"updateResults": [],
"deleteResults": []
}'''
@pytest.fixture
def arcgis():
@ -857,6 +863,47 @@ def test_tile_endpoint(arcgis, app):
assert resp.content_type == 'image/png'
def test_arcgis_featureservice_applyedits(app, arcgis):
endpoint = tests.utils.generic_endpoint_url('arcgis', 'featureservice-applyedits', slug=arcgis.slug)
assert endpoint == '/arcgis/test/featureservice-applyedits'
url = endpoint + '?folder=fold&service=serv&layer=1'
payload = {
'adds/0/geometry/x': '43.688918',
'adds/0/geometry/y': '7.240237',
'adds/0/attributes/label': 'foo',
'adds/0/attributes/description': 'bar',
}
with mock.patch('passerelle.utils.Request.post') as requests_post:
requests_post.return_value = tests.utils.FakedResponse(content=EDITS_RESPONSE, status_code=200)
resp = app.post_json(url, params=payload, status=403)
assert requests_post.call_count == 0
assert resp.json['err'] == 1
assert resp.json['err_class'] == 'django.core.exceptions.PermissionDenied'
# open access
api = ApiUser.objects.create(username='all', keytype='', key='')
obj_type = ContentType.objects.get_for_model(arcgis)
AccessRight.objects.create(
codename='can_access', apiuser=api, resource_type=obj_type, resource_pk=arcgis.pk
)
resp = app.post_json(url, params=payload, status=200)
assert requests_post.call_count == 1
assert (
requests_post.call_args[0][0]
== 'https://arcgis.example.net/services/fold/serv/FeatureServer/1/applyEdits'
)
assert requests_post.call_args[1]['data']['f'] == 'pjson'
assert json.loads(requests_post.call_args[1]['data']['adds']) == [
{
'attributes': {'description': 'bar', 'label': 'foo'},
'geometry': {'x': '43.688918', 'y': '7.240237'},
}
]
assert resp.json['err'] == 0
assert resp.json['data'] == json.loads(EDITS_RESPONSE)
def test_query_documentation(arcgis, query, app):
resp = app.get(arcgis.get_absolute_url())
assert query.name in resp.text