def get(self, slug): """Return task statuses for the challenge identified by 'slug'""" challenge = get_challenge_or_404(slug, True, False) return [{ 'identifier': task.identifier, 'status': task.status } for task in challenge.tasks]
def task_by_id(challenge_slug, task_id): "Either displays a task (assigning it) or else posts the commit" # make sure we're authenticated challenge = get_challenge_or_404(challenge_slug, True) task = get_task_or_404(challenge, task_id) osmid = session.get('osm_id') if request.method == 'GET': try: assign = int(request.args.get('assign', 1)) except ValueError: abort(400) if assign: action = Action(task.id, "assigned", osmid) task.current_state = action db.session.add(action) db.session.add(task) return jsonify(marshal(task, task_fields)) elif request.method == 'POST': valid_actions = [button.action for button in challenge.dlg['buttons']] action = None for key in valid_actions: if request.form.get(key): action = Action(task.id, key, osmid) task.current_action = action db.session.add(action) break if not action: abort(400) new_state = challenge.task_status(task) action = Action(task.id, new_state, osmid) task.current_action = action db.session.add(action) db.session.add(task) db.commit()
def put(self, slug): c = get_challenge_or_404(slug, abort_if_inactive=False) if not re.match("^[\w\d_-]+$", slug): abort(400, message='slug should contain only a-z, A-Z, 0-9, _, -') try: payload = json.loads(request.data) except Exception: abort(400, message="There is something wrong with your JSON.") app.logger.debug(payload) c.title = payload.get('title') c.geometry = payload.get('geometry') c.description = payload.get('description') c.blurb = payload.get('blurb') c.help = payload.get('help') c.instruction = payload.get('instruction') c.active = payload.get('active') c.difficulty = payload.get('difficulty') c.options = payload.get('options') db.session.add(c) try: db.session.commit() except Exception as e: if type(e) == IntegrityError: app.logger.warn(e) db.session.rollback() abort(409, message='the session and the database did not agree: {}'.format(e)) else: app.logger.warn(e) abort(500, message=message_internal_server_error) return {}, 200
def put(self, slug): exists = challenge_exists(slug) try: payload = json.loads(request.data) except Exception: abort(400, "JSON bad") if not exists and 'title' not in payload: abort(400, "No title") return {} if exists: app.logger.debug('challenge existed, retrieving') c = get_challenge_or_404(slug, abort_if_inactive=False) if 'title' in payload: c.title = payload.get('title') else: c = Challenge(slug, payload.get('title')) if 'geometry' in payload: c.geometry = payload.get('geometry') if 'description' in payload: c.description = payload.get('description') if 'blurb' in payload: c.blurb = payload.get('blurb') if 'help' in payload: c.help = payload.get('help') if 'instruction' in payload: c.instruction = payload.get('instruction') if 'active' in payload: c.active = payload.get('active') if 'difficulty' in payload: c.difficulty = payload.get('difficulty') db.session.add(c) db.session.commit() return {}
def put(self, slug): c = get_challenge_or_404(slug, abort_if_inactive=False) if not re.match("^[\w\d_-]+$", slug): abort(400, message='slug should contain only a-z, A-Z, 0-9, _, -') try: payload = json.loads(request.data) except Exception: abort(400, message="There is something wrong with your JSON.") app.logger.debug(payload) c.title = payload.get('title') c.geometry = payload.get('geometry') c.description = payload.get('description') c.blurb = payload.get('blurb') c.help = payload.get('help') c.instruction = payload.get('instruction') c.active = payload.get('active') c.difficulty = payload.get('difficulty') c.options = payload.get('options') db.session.add(c) try: db.session.commit() except Exception as e: if type(e) == IntegrityError: app.logger.warn(e.message) db.session.rollback() abort(409, message='the session and the database did not agree: {}'.format(e.message)) else: app.logger.warn(e.message) abort(500, message=message_internal_server_error) return {}, 200
def get(self, slug): """Returns a task for specified challenge""" challenge = get_challenge_or_404(slug, True) parser = reqparse.RequestParser() parser.add_argument('lon', type=float, help='longitude could not be parsed') parser.add_argument('lat', type=float, help='longitude could not be parsed') parser.add_argument('assign', type=int, default=1, help='Assign could not be parsed') args = parser.parse_args() osmid = session.get('osm_id') assign = args['assign'] lon = args['lon'] lat = args['lat'] task = None if lon and lat: coordWKT = 'POINT(%s %s)' % (lat, lon) task = Task.query.filter(Task.location.ST_Intersects( ST_Buffer(coordWKT, app.config["NEARBUFFER"]))).first() if task is None: # we did not get a lon/lat or there was no task close # If no location is specified, or no tasks were found, gather # random tasks task = get_random_task(challenge) app.logger.debug('got task %s' % task.id) # If no tasks are found with this method, then this challenge # is complete if task is None: # Send a mail to the challenge admin requests.post( "https://api.mailgun.net/v2/maproulette.org/messages", auth=("api", app.config["MAILGUN_API_KEY"]), data={"from": "MapRoulette <*****@*****.**>", "to": ["*****@*****.**"], "subject": "Challenge {} is complete".format(challenge.slug), "text": "{challenge} has no remaining tasks on server {server}".format( challenge=challenge.title, server=url_for('index', _external=True))}) # Deactivate the challenge challenge.active = False db.session.add(challenge) db.session.commit() # Is this the right error? return osmerror("ChallengeComplete", "Challenge {} is complete".format(challenge.title)) if assign: task.append_action(Action("assigned", osmid)) db.session.add(task) db.session.commit() return marshal(task, task_fields)
def challenge_stats(challenge_slug): "Returns stat data for a challenge" challenge = get_challenge_or_404(challenge_slug, True) total = Task.query.filter(challenge_slug == challenge.slug).count() tasks = Task.query.filter(challenge_slug == challenge.slug).all() osmid = session.get('osm_id') logging.info("{user} requested challenge stats for {challenge}".format( user=osmid, challenge=challenge_slug)) available = len([task for task in tasks if challenge.task_available(task, osmid)]) return jsonify(stats={'total': total, 'available': available})
def get(self, slug): """Returns a task for specified challenge""" challenge = get_challenge_or_404(slug, True) parser = reqparse.RequestParser() parser.add_argument('lon', type=float, help='longitude could not be parsed') parser.add_argument('lat', type=float, help='longitude could not be parsed') parser.add_argument('assign', type=int, default=1, help='Assign could not be parsed') args = parser.parse_args() osmid = session.get('osm_id') assign = args['assign'] lon = args['lon'] lat = args['lat'] task = None if lon and lat: coordWKT = 'POINT(%s %s)' % (lat, lon) task = Task.query.filter(Task.location.ST_Intersects( ST_Buffer(coordWKT, app.config["NEARBUFFER"]))).first() if task is None: # we did not get a lon/lat or there was no task close # If no location is specified, or no tasks were found, gather # random tasks task = get_random_task(challenge) # If no tasks are found with this method, then this challenge # is complete if task is None: if not user_area_is_defined(): # send email and deactivate challenge only when # there are no more tasks for the entire challenge, # not if the user has defined an area to work on. subject = "Challenge {} is complete".format(challenge.slug) body = "{challenge} has no remaining tasks" " on server {server}".format( challenge=challenge.title, server=url_for('index', _external=True)) send_email("*****@*****.**", subject, body) # Deactivate the challenge challenge.active = False db.session.add(challenge) db.session.commit() # Is this the right error? return osmerror("ChallengeComplete", "Challenge {} is complete".format(challenge.title)) if assign: task.append_action(Action("assigned", osmid)) db.session.add(task) db.session.commit() return marshal(task, task_fields)
def delete(self, slug): """delete a challenge""" challenge = get_challenge_or_404(slug, abort_if_inactive=False) db.session.delete(challenge) try: db.session.commit() except Exception as e: if type(e) == IntegrityError: app.logger.warn(e.message) db.session.rollback() abort(409, message='the session and the database did not agree: {}'.format(e.message)) else: app.logger.warn(e.message) abort(500, message='Something really unexpected happened...') return {}, 204
def delete(self, slug): """delete a challenge""" challenge = get_challenge_or_404(slug, abort_if_inactive=False) db.session.delete(challenge) try: db.session.commit() except Exception as e: if type(e) == IntegrityError: app.logger.warn(e) db.session.rollback() abort(409, message='the session and the database did not agree: {}'.format(e)) else: app.logger.warn(e) abort(500, message='Something really unexpected happened...') return {}, 204
def challenge_tasks(challenge_slug): "Returns a task for specified challenge" challenge = get_challenge_or_404(challenge_slug, True) parser = reqparse.RequestParser() parser.add_argument('num', type=int, default=1, help='Number of return results cannot be parsed') parser.add_argument('near', type=GeoPoint, help='Near argument could not be parsed') parser.add_argument('assign', type=int, default=1, help='Assign could not be parsed') args = parser.parse_args() osmid = session.get('osm_id') # By default, we return a single task, but no more than 10 num = min(args['num'], 10) assign = args['assign'] near = args['near'] logging.info("{user} requesting {num} tasks from {challenge} near {near} assiging: {assign}".format(user=osmid, num=num, challenge=challenge_slug, near=near, assign=assign)) task_list = [] if near: coordWKT = 'POINT(%s %s)' % (near.lat, near.lon) task_query = Task.query.filter(Task.location.ST_Intersects( ST_Buffer(coordWKT, app.config["NEARBUFFER"]))).limit(num) task_list = [task for task in task_query if challenge.task_available(task, osmid)] if not near or not task_list: # If no location is specified, or no tasks were found, gather # random tasks task_list = [get_random_task(challenge) for _ in range(num)] task_list = filter(None, task_list) # If no tasks are found with this method, then this challenge # is complete if not task_list: # Is this the right error? osmerror("ChallengeComplete", "Challenge {} is complete".format(challenge_slug)) if assign: for task in task_list: action = Action(task.id, "assigned", osmid) task.current_state = action db.session.add(action) db.session.add(task) db.session.commit() logging.info( "{num} tasks found matching criteria".format(num=len(task_list))) tasks = [marshal(task, task_fields) for task in task_list] for query in get_debug_queries(): app.logger.debug(query) return jsonify(tasks=tasks)
def get(self, slug): """Returns a task for specified challenge""" challenge = get_challenge_or_404(slug, True) parser = reqparse.RequestParser() parser.add_argument('lon', type=float, help='longitude could not be parsed') parser.add_argument('lat', type=float, help='longitude could not be parsed') parser.add_argument('assign', type=int, default=1, help='Assign could not be parsed') args = parser.parse_args() osmid = session.get('osm_id') assign = args['assign'] lon = args['lon'] lat = args['lat'] app.logger.info( "{user} requesting task from {challenge} near\ ({lon}, {lat}) assiging: {assign}".format( user=osmid, challenge=slug, lon=lon, lat=lat, assign=assign)) task = None if lon and lat: coordWKT = 'POINT(%s %s)' % (lat, lon) task = Task.query.filter(Task.location.ST_Intersects( ST_Buffer(coordWKT, app.config["NEARBUFFER"]))).first() if task is None: # we did not get a lon/lat or there was no task close # If no location is specified, or no tasks were found, gather # random tasks app.logger.debug('getting random task') task = get_random_task(challenge) # If no tasks are found with this method, then this challenge # is complete if task is None: # Is this the right error? return osmerror("ChallengeComplete", "Challenge {} is complete".format(slug)) if assign: task.append_action(Action("assigned", osmid)) db.session.add(task) db.session.commit() return marshal(task, task_fields)
def get(self, challenge_slug): """Return statistics for the challenge identified by 'slug'""" # get the challenge challenge = get_challenge_or_404(challenge_slug, abort_if_inactive=False) # query the number of tasks query = db.session.query(Task).filter_by(challenge_slug=challenge.slug) # refine with the user defined editing area query = refine_with_user_area(query) # emit count total = query.count() # get the approximate number of available tasks unfixed = query.filter(Task.status.in_( ['available', 'created', 'skipped'])).count() return {'total': total, 'unfixed': unfixed}
def put(self, slug): c = get_challenge_or_404(slug, abort_if_inactive=False) if not re.match("^[\w\d_-]+$", slug): abort(400, 'slug should contain only a-z, A-Z, 0-9, _, -') try: payload = json.loads(request.data) except Exception: abort(400, "JSON bad") if 'title' in payload: c.title = payload.get('title') if 'geometry' in payload: c.geometry = payload.get('geometry') if 'description' in payload: c.description = payload.get('description') if 'blurb' in payload: c.blurb = payload.get('blurb') if 'help' in payload: c.help = payload.get('help') if 'instruction' in payload: c.instruction = payload.get('instruction') if 'active' in payload: c.active = payload.get('active') if 'difficulty' in payload: c.difficulty = payload.get('difficulty') db.session.add(c) try: db.session.commit() except Exception as e: if type(e) == IntegrityError: app.logger.warn(e.message) db.session.rollback() abort( 409, 'the session and the database did not agree: {}'.format( e.message)) else: app.logger.warn(e.message) abort(500, 'something unexpected happened') return {}, 200
def put(self, slug): c = get_challenge_or_404(slug, abort_if_inactive=False) if not re.match("^[\w\d_-]+$", slug): abort(400, 'slug should contain only a-z, A-Z, 0-9, _, -') try: payload = json.loads(request.data) except Exception: abort(400, "JSON bad") if 'title' in payload: c.title = payload.get('title') if 'geometry' in payload: c.geometry = payload.get('geometry') if 'description' in payload: c.description = payload.get('description') if 'blurb' in payload: c.blurb = payload.get('blurb') if 'help' in payload: c.help = payload.get('help') if 'instruction' in payload: c.instruction = payload.get('instruction') if 'active' in payload: c.active = payload.get('active') if 'difficulty' in payload: c.difficulty = payload.get('difficulty') db.session.add(c) try: db.session.commit() except Exception as e: if type(e) == IntegrityError: app.logger.warn(e.message) db.session.rollback() abort(409, 'the session and the database did not agree: {}'.format(e.message)) else: app.logger.warn(e.message) abort(500, 'something unexpected happened') return {}, 200
def get(self, slug): """Return task statuses for the challenge identified by 'slug'""" challenge = get_challenge_or_404(slug, True, False) return [{ 'identifier': task.identifier, 'status': task.status} for task in challenge.tasks]
def get(self, slug): """Return statistics for the challenge identified by 'slug'""" challenge = get_challenge_or_404(slug, True) total = len(challenge.tasks) available = challenge.tasks_available return {'total': total, 'available': available}
def get(self, slug): """Return statistics for the challenge identified by 'slug'""" challenge = get_challenge_or_404(slug, True) total = len(challenge.tasks) unfixed = challenge.approx_tasks_available return {'total': total, 'unfixed': unfixed}
def get(self, slug): """Return the geometry (spatial extent) for the challenge identified by 'slug'""" challenge = get_challenge_or_404(slug, True) return challenge.polygon
def get(self, slug): """Return a single challenge by slug""" challenge = get_challenge_or_404(slug, abort_if_inactive=False) return marshal(challenge, challenge_detail)
def delete(self, slug): """delete a challenge""" challenge = get_challenge_or_404(slug) db.session.delete(challenge) db.session.commit() return {}, 204
def get(self, slug): """Return a single challenge by slug""" challenge = get_challenge_or_404(slug, True) return marshal(challenge, challenge.marshal_fields)
def get(self): """Return a single challenge""" return get_challenge_or_404(app.config["DEFAULT_CHALLENGE"])
def challenge_by_slug(challenge_slug): """Returns the metadata for a challenge""" challenge = get_challenge_or_404(challenge_slug, "Default") app.logger.debug('done dialog for challenge: %s' % (challenge.done_dlg)) return challenge
def get(self, slug): """Returns a task for specified challenge""" challenge = get_challenge_or_404(slug, True) parser = reqparse.RequestParser() parser.add_argument('lon', type=float, help='longitude could not be parsed') parser.add_argument('lat', type=float, help='longitude could not be parsed') parser.add_argument('assign', type=int, default=1, help='Assign could not be parsed') args = parser.parse_args() osmid = session.get('osm_id') assign = args['assign'] lon = args['lon'] lat = args['lat'] task = None if lon and lat: coordWKT = 'POINT(%s %s)' % (lat, lon) task = Task.query.filter(Task.location.ST_Intersects( ST_Buffer(coordWKT, app.config["NEARBUFFER"]))).first() if task is None: # we did not get a lon/lat or there was no task close # If no location is specified, or no tasks were found, gather # random tasks task = get_random_task(challenge) # If no tasks are found with this method, then this challenge # is complete if task is None: if not user_area_is_defined(): # send email and deactivate challenge only when # there are no more tasks for the entire challenge, # not if the user has defined an area to work on. subject = "Challenge {} is complete".format(challenge.slug) body = "{challenge} has no remaining tasks" " on server {server}".format( challenge=challenge.title, server=url_for('index', _external=True)) send_email("*****@*****.**", subject, body) # Deactivate the challenge challenge.active = False merged_c = db.session.merge(challenge) db.session.add(merged_c) db.session.commit() # Is this the right error? return osmerror("ChallengeComplete", "Challenge {} is complete".format(challenge.title)) if assign: task.append_action(Action("assigned", osmid)) merged_t = db.session.merge(task) db.session.add(merged_t) try: db.session.commit() except Exception as e: if type(e) == IntegrityError: app.logger.warn(e.message) db.session.rollback() abort(409, message='The session and the database did not agree for task identifier {identifier}: {message}'.format(id=task.identifier, message=e.message)) else: app.logger.warn(e.message) abort(500, message=message_internal_server_error) return marshal(task, task_fields)