Skip to content

Commit 38920ad

Browse files
authored
Merge pull request #84 from rYR79435/addFileTasks
Add support for the endpoint /challenge/{id}/addFileTasks, closes #83
2 parents cc35fab + ccc261d commit 38920ad

3 files changed

Lines changed: 87 additions & 0 deletions

File tree

maproulette/api/challenge.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,32 @@ def add_tasks_to_challenge(self, data, challenge_id):
278278
body=data)
279279
return response
280280

281+
def add_file_tasks_to_challenge(self, data, challenge_id, line_by_line="true", remove_unmatched="false",
282+
data_origin_date="", skip_snapshot="false"):
283+
"""Method to add tasks to an existing challenge with tasks as GeoJSON
284+
285+
:param data: a GeoJSON containing geometry of tasks to be added to a challenge
286+
:param challenge_id: the ID corresponding to the challenge that tasks will be added to
287+
:param line_by_line: whether or not the provided data is in line-by-line GeoJSON format
288+
:param remove_unmatched: whether or not the JSON provided includes seperate GeoJSON on each line
289+
:param data_origin_date: the date the data was sourced on
290+
:param skip_snapshot: whether or not to skip recording a snapshot before proceeding
291+
:returns: the API response from the PUT request
292+
"""
293+
query_params = {
294+
"lineByLine": str(line_by_line),
295+
"removeUnmatched": str(remove_unmatched),
296+
"dataOriginDate": str(data_origin_date),
297+
"skipSnapshot": str(skip_snapshot)
298+
}
299+
body = {'json': ('data', data)} # server only accepts dict with key 'json'
300+
301+
response = self.put_file(
302+
endpoint=f"/challenge/{challenge_id}/addFileTasks",
303+
body=body,
304+
params=query_params)
305+
return response
306+
281307
def delete_challenge(self, challenge_id, immediate="false"):
282308
"""Method to delete a challenge by using the corresponding challenge ID
283309

maproulette/api/maproulette_server.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,51 @@ def put(self, endpoint, body=None, params=None):
180180
"status": response.status_code
181181
}
182182

183+
def put_file(self, endpoint, body=None, params=None):
184+
"""Method that completes a multipart PUT request to the MapRoulette API
185+
186+
:param endpoint: the server endpoint to use for the PUT request
187+
:param body: the body of the request (optional)
188+
:param params: the parameters that pertain to the request (optional)
189+
:returns: a dictionary containing the API response status code as well as the decoded JSON response if decoding
190+
was successful. If not, the response text is returned.
191+
"""
192+
response = self.session.put(
193+
self.url + endpoint,
194+
params=params,
195+
files=body
196+
)
197+
try:
198+
response.raise_for_status()
199+
except requests.exceptions.HTTPError as e:
200+
if e.response.status_code == 400:
201+
raise InvalidJsonError(
202+
message=self.parse_response_message(e.response),
203+
status=e.response.status_code
204+
) from None
205+
elif e.response.status_code == 401:
206+
raise UnauthorizedError(
207+
message=self.parse_response_message(e.response),
208+
status=e.response.status_code
209+
) from None
210+
else:
211+
raise HttpError(
212+
message=self.parse_response_message(e.response),
213+
status=e.response.status_code
214+
) from None
215+
except (requests.ConnectionError, requests.Timeout) as e:
216+
raise ConnectionUnavailableError(e) from None
217+
try:
218+
return {
219+
"data": response.json(),
220+
"status": response.status_code
221+
}
222+
except ValueError:
223+
return {
224+
"data": response.text,
225+
"status": response.status_code
226+
}
227+
183228
def delete(self, endpoint, params=None):
184229
"""Method that completes a DELETE request to the MapRoulette API
185230

tests/test_challenge_api.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,22 @@ def test_add_tasks_to_challenge(self, mock_request, api_instance=api):
5757
json=test_geojson,
5858
params=None)
5959

60+
@patch('maproulette.api.maproulette_server.requests.Session.put')
61+
def test_add_file_tasks_to_challenge(self, mock_request, api_instance=api):
62+
test_challenge_id = '12978'
63+
data = {'json': ('data', test_geojson)}
64+
query_params = {
65+
"lineByLine": "true",
66+
"removeUnmatched": "false",
67+
"dataOriginDate": "",
68+
"skipSnapshot": "false"
69+
}
70+
api_instance.add_file_tasks_to_challenge(test_geojson, test_challenge_id)
71+
mock_request.assert_called_once_with(
72+
f'{self.url}/challenge/12978/addFileTasks',
73+
files=data,
74+
params=query_params)
75+
6076
@patch('maproulette.api.maproulette_server.requests.Session.post')
6177
def test_create_virtual_challenge(self, mock_request, api_instance=api):
6278
# TODO: add model for virtual challenge to aid in posting

0 commit comments

Comments
 (0)