arcgis: add endpoint to add/edit/delete features (#86679)
gitea/passerelle/pipeline/head This commit looks good
Details
gitea/passerelle/pipeline/head This commit looks good
Details
This commit is contained in:
parent
36dfa9508e
commit
38d3fbbf4e
|
@ -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'),
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue