1- import httpx
21import json
32import time
4- from ulid import ULID
5- from django .conf import settings
6- import requests
73from urllib .parse import urlparse
84
5+ import httpx
6+ import requests
7+ from django .conf import settings
8+ from ulid import ULID
9+
10+
911class MapswipeClient :
1012 """
1113 A client for interacting with the MapSwipe backend API.
@@ -166,25 +168,31 @@ def _authenticate(self):
166168 "x-csrftoken" : csrf_token ,
167169 "origin" : self ._manager_url ,
168170 }
169-
170- def _graphql_request (self , query : str , variables : dict = None , operation_name : str = None ):
171+
172+ def _graphql_request (
173+ self , query : str , variables : dict = None , operation_name : str = None
174+ ):
171175 payload = {"query" : query , "variables" : variables }
172176 if operation_name :
173177 payload ["operationName" ] = operation_name
174-
178+
175179 response = self ._client .post ("/graphql/" , headers = self ._headers , json = payload )
176180 response .raise_for_status ()
177181 data = response .json ()
178182 if "errors" in data :
179183 raise RuntimeError (f"GraphQL errors: { data ['errors' ]} " )
180184 return data ["data" ]
181185
182- def _graphql_request_with_files (self , query : str , files : dict , map_data : dict , variables : dict ):
186+ def _graphql_request_with_files (
187+ self , query : str , files : dict , map_data : dict , variables : dict
188+ ):
183189 form_data = {
184190 "operations" : json .dumps ({"query" : query , "variables" : variables }),
185191 "map" : json .dumps (map_data ),
186192 }
187- response = self ._client .post ("/graphql/" , headers = self ._headers , files = files , data = form_data )
193+ response = self ._client .post (
194+ "/graphql/" , headers = self ._headers , files = files , data = form_data
195+ )
188196 response .raise_for_status ()
189197 data = response .json ()
190198 if "errors" in data :
@@ -198,7 +206,7 @@ def _graphql_request_with_files(self, query: str, files: dict, map_data: dict, v
198206 # if not organizations:
199207 # raise RuntimeError("No organizations found for the user.")
200208 # return organizations[0]["id"]
201-
209+
202210 def create_validation_project (
203211 self ,
204212 topic : str ,
@@ -207,7 +215,7 @@ def create_validation_project(
207215 instruction : str ,
208216 look_for : str ,
209217 project_number : int ,
210- cover_image_path : str = ' https://www.pngall.com/wp-content/uploads/8/Sample.png' ,
218+ cover_image_path : str = " https://www.pngall.com/wp-content/uploads/8/Sample.png" ,
211219 organization_id : str = "4" ,
212220 additional_info_url : str = "fair-dev.hotosm.org" ,
213221 ) -> tuple [str , str ]:
@@ -224,20 +232,19 @@ def create_validation_project(
224232 "requestingOrganization" : organization_id ,
225233 "additionalInfoUrl" : additional_info_url ,
226234 }
227-
235+
228236 create_project_data = self ._graphql_request (
229237 query = self ._CREATE_DRAFT_PROJECT_MUTATION ,
230238 variables = {"data" : project_params },
231- operation_name = "NewDraftProject"
239+ operation_name = "NewDraftProject" ,
232240 )
233-
241+
234242 response_data = create_project_data .get ("createProject" , {})
235243 if not response_data .get ("result" ) or response_data .get ("errors" ):
236244 raise RuntimeError (f"Failed to create draft project: { response_data } " )
237245
238246 project_id = response_data ["result" ]["id" ]
239247
240-
241248 def is_url (path ):
242249 try :
243250 result = urlparse (path )
@@ -249,11 +256,11 @@ def is_url(path):
249256 response = requests .get (cover_image_path )
250257 response .raise_for_status ()
251258 image_data = response .content
252- filename = cover_image_path .split ('/' )[- 1 ]
259+ filename = cover_image_path .split ("/" )[- 1 ]
253260 else :
254261 with open (cover_image_path , "rb" ) as image_file :
255262 image_data = image_file .read ()
256- filename = cover_image_path .split ('/' )[- 1 ]
263+ filename = cover_image_path .split ("/" )[- 1 ]
257264
258265 asset_params = {
259266 "inputType" : "COVER_IMAGE" ,
@@ -271,22 +278,21 @@ def is_url(path):
271278 image_asset_id = asset_response ["createProjectAsset" ]["result" ]["id" ]
272279 return project_id , image_asset_id
273280
274-
275281 def get_project_details (self , project_id : str ) -> dict :
276282 """Polls and fetches the details for a given project ID."""
277-
283+
278284 project_data = self ._graphql_request (
279285 query = self ._PROJECT_BY_ID_QUERY ,
280286 variables = {"id" : project_id },
281- operation_name = "ProjectById"
287+ operation_name = "ProjectById" ,
282288 )["project" ]
283289
284- if project_data ['firebaseId' ]:
285- project_data ['webUrl' ] = f"{ settings .MAPSWIPE_WEB_URL } /#/en/projects/{ project_data ['firebaseId' ]} "
286-
290+ if project_data ["firebaseId" ]:
291+ project_data ["webUrl" ] = (
292+ f"{ settings .MAPSWIPE_WEB_URL } /#/en/projects/{ project_data ['firebaseId' ]} "
293+ )
294+
287295 return project_data
288-
289-
290296
291297 def update_project (
292298 self ,
@@ -295,7 +301,7 @@ def update_project(
295301 tms_url : str ,
296302 image_asset_id : str ,
297303 group_size : int = 25 ,
298- verification_number : int = 4 ,
304+ verification_number : int = 1 ,
299305 tutorial_id : str = "37" ,
300306 ):
301307 """Updates a project with additional details."""
@@ -357,11 +363,11 @@ def update_project(
357363 variables = {"id" : project_id , "data" : update_params },
358364 operation_name = "UpdateProject" ,
359365 )
360-
366+
361367 response_data = update_data .get ("updateProject" , {})
362368 if not response_data .get ("result" ) or response_data .get ("errors" ):
363369 raise RuntimeError (f"Failed to update project: { response_data } " )
364-
370+
365371 return response_data
366372
367373 def update_project_status (self , project_id : str , status : str ):
@@ -372,11 +378,11 @@ def update_project_status(self, project_id: str, status: str):
372378 variables = {"id" : project_id , "data" : status_params },
373379 operation_name = "UpdateProjectStatus" ,
374380 )
375-
381+
376382 response_data = status_data .get ("updateProjectStatus" , {})
377383 if not response_data .get ("result" ) or response_data .get ("errors" ):
378384 raise RuntimeError (f"Failed to update project status: { response_data } " )
379-
385+
380386 return response_data
381387
382388 def get_project_status (self , project_id : str ) -> dict :
@@ -387,9 +393,7 @@ def get_project_status(self, project_id: str) -> dict:
387393 operation_name = "ProjectStatus" ,
388394 )["project" ]
389395
390- def poll_project_status (
391- self , project_id : str , target_status : str
392- ):
396+ def poll_project_status (self , project_id : str , target_status : str ):
393397 """Polls the project status until it reaches the target status."""
394398 interval = settings .MAPSWIPE_POLL_INTERVAL
395399 timeout = settings .MAPSWIPE_POLL_TIMEOUT
@@ -411,7 +415,7 @@ def get_project_results(self, project_id: str) -> dict:
411415 data = self ._graphql_request (
412416 query = self ._PROJECT_RESULTS_QUERY ,
413417 variables = {"id" : project_id },
414- operation_name = "ProjectResults"
418+ operation_name = "ProjectResults" ,
415419 )
416420 return data .get ("publicProject" , {})
417421
0 commit comments