def post(self, challenge_slug): challenge = get_challenge_or_404(challenge_slug, instance_type=False, abort_if_inactive=False) parser = reqparse.RequestParser() parser.add_argument('run', required=True, help="Bulk inserts require a Run ID") parser.add_argument('tasks', type=JsonTasks, required=True, help="Bulk inserts require tasks") run = args['run'] tasks = args['tasks'].data results = [] for t in tasks: task = Task(challenge.slug, t['id']) task.instruction = t['text'] task.location = t['location'] task.manifest = t['manifest'] task.run = run results.append(marshal(task), task_fields) db.session.add(task) db.session.flush() action = Action(task.id, "created") db.session.add(action) # This is going to be a bit challenge specific action = Action(task.id, "available") db.session.add(action) db.session.commit() return jsonify(tasks=results)
def load_fixtures(): """Load some fixture data into the database.""" from maproulette.models import Task, Challenge, User from random import randrange, random # Create a user u = User() u.osm_id = 8909 u.osm_username = '******' session.add(u) for x in range(1, 11): c = Challenge() c.name = "Challenge {}".format(x) c.instruction = "Challenge {} Instruction".format(x) session.add(c) for x in range(1, 10000): t = Task() t.challenge_id = randrange(1, 11) t.geometry = 'POINT({lon} {lat})'.format(lon=random() * 360 - 180, lat=random() * 180 - 90) session.add(t) session.commit()
def put(self, slug, identifier): """Create or update one task. By default, the geometry must be supplied as WKB, but this can be overridden by adding ?geoformat=geojson to the URL""" task_geometries = [] # Get the posted data taskdata = json.loads(request.data) exists = task_exists(slug, identifier) app.logger.debug("taskdata: %s" % (taskdata,)) # abort if the taskdata does not contain geometries and it's a new task if not 'geometries' in taskdata: if not exists: abort(400) else: # extract the geometries geometries = taskdata.pop('geometries') app.logger.debug("geometries: %s" % (geometries,)) app.logger.debug("features: %s" % (geometries['features'],)) # parse the geometries for feature in geometries['features']: app.logger.debug(feature) osmid = feature['properties'].get('osmid') shape = asShape(feature['geometry']) t = TaskGeometry(osmid, shape) task_geometries.append(t) # there's two possible scenarios: # 1. An existing task gets an update, in that case # we only need the identifier # 2. A new task is inserted, in this case we need at # least an identifier and encoded geometries. # now we check if the task exists if exists: # if it does, update it app.logger.debug('existing task') task = get_task_or_404(slug, identifier) if not task.update(taskdata, task_geometries): abort(400) else: # if it does not, create it app.logger.debug('new task') new_task = Task(slug, identifier) new_task.update(taskdata, task_geometries) return {}
def geojson_to_task(slug, feature): """converts one geojson feature to a task. This will only work in a limited number of cases, where: * The geometry is one single Point or Linestring feature, * The OSM ID of the feature is in the id field of the JSON, and you are OK with the following: * The description cannot be set at the task level * The identifier will be slug-osmid""" # check for id and geometries if 'id' not in feature: app.logger.debug('no id in this feature, skipping') return None if 'geometry' not in feature: app.logger.debug('no geometries in feature, skipping') return None # generate an identifier osmid = feature['id'] identifier = '{slug}-{osmid}'.format( slug=slug, osmid=osmid) # find, or create a task task = Task.query.filter( Task.challenge_slug == slug).filter( Task.identifier == identifier).first() if task is None: task = Task(slug, identifier) app.logger.debug('creating task {identifier}'.format( identifier=identifier)) else: app.logger.debug('updating task {identifier}'.format( identifier=identifier)) # clear existing geometries task.geometries = [] # get the geometry geom = feature['geometry'] shape = asShape(geom) try: g = TaskGeometry(osmid, shape) task.geometries.append(g) return task except Exception as e: app.logger.debug("task could not be created, {}".format(e)) return None
def json_to_task(slug, data, task=None, identifier=None): """Parse task json coming in through the admin api""" app.logger.debug(data) if identifier is None and task is None: if 'identifier' not in data: raise Exception('no identifier given') identifier = data['identifier'] if task is None: # create the task if none was passed in try: task = Task(slug, identifier) except Exception as e: app.logger.warn(e) raise e else: # delete existing task geometries task.geometries = [] # check for instruction if 'instruction' in data: task.instruction = data['instruction'] # check for status if 'status' in data: task.status = data['status'] # extract the task geometries if 'geometries' in data: geometries = data.pop('geometries') # parse the geometries app.logger.debug(geometries) for feature in geometries['features']: osmid = None if 'properties' in feature and feature['properties'].get('osmid'): osmid = feature['properties'].get('osmid') app.logger.debug(feature) shape = asShape(feature['geometry']) g = TaskGeometry(shape, osmid) task.geometries.append(g) return task
def geojson_to_task(slug, feature): """converts one geojson feature to a task. This will only work in a limited number of cases, where: * The geometry is one single Point or Linestring feature, * The OSM ID of the feature is in the id field of the JSON, and you are OK with the following: * The description cannot be set at the task level * The identifier will be slug-osmid""" # check for id and geometries if 'id' not in feature: app.logger.debug('no id in this feature, skipping') return None if 'geometry' not in feature: app.logger.debug('no geometries in feature, skipping') return None # generate an identifier osmid = feature['id'] identifier = '{slug}-{osmid}'.format(slug=slug, osmid=osmid) # find, or create a task task = Task.query.filter(Task.challenge_slug == slug).filter( Task.identifier == identifier).first() if task is None: task = Task(slug, identifier) app.logger.debug( 'creating task {identifier}'.format(identifier=identifier)) else: app.logger.debug( 'updating task {identifier}'.format(identifier=identifier)) # clear existing geometries task.geometries = [] # get the geometry geom = feature['geometry'] shape = asShape(geom) try: g = TaskGeometry(osmid, shape) task.geometries.append(g) return task except Exception, e: app.logger.debug("task could not be created, {}".format(e)) return None
def load_sampledata(path): identifier = 0 tasks = [] actions = [] c = Challenge('test') c.title = 'Just a test challenge' with open(path, 'rb') as filehandle: q = json.load(filehandle) for feature in q['features']: identifier += 1 coordinates = feature['geometry']['coordinates'] shape = Point(coordinates[0], coordinates[1]) properties = feature['properties'] t = Task('test',identifier) t.location = dumps(shape) t.run = 1 a = Action(t.id, "created") tasks.append(t) print tasks feedengine = create_engine('postgresql://*****:*****@localhost/maproulette') Session = sessionmaker(bind=feedengine) session = Session() session.add(c) session.commit() for t in tasks: session.add(t) for a in actions: session.add(a) c.active = True session.commit()
def parse_task_json(data, slug, identifier, commit=True): """Parse task json coming in through the admin api""" task_geometries = [] exists = task_exists(slug, identifier) # abort if the taskdata does not contain geometries and it's a new task if not 'geometries' in data: if not exists: abort(400) else: # extract the geometries geometries = data.pop('geometries') # parse the geometries for feature in geometries['features']: osmid = feature['properties'].get('osmid') shape = asShape(feature['geometry']) t = TaskGeometry(osmid, shape) task_geometries.append(t) # there's two possible scenarios: # 1. An existing task gets an update, in that case # we only need the identifier # 2. A new task is inserted, in this case we need at # least an identifier and encoded geometries. # now we check if the task exists if exists: # if it does, update it task = get_task_or_404(slug, identifier) if not task.update(data, task_geometries, commit=commit): abort(400) else: # if it does not, create it new_task = Task(slug, identifier) new_task.update(data, task_geometries, commit=commit) return True
def put(self, challenge_slug, task_id): challenge = get_challenge_or_404(challenge_slug, instance_type=False, abort_if_inactive=False) task = Task.query(Task.identifier == task_id). \ filter(Task.challenge_slug == challenge.slug).first() if task: action = Action(task.id, "modified") db.session.add(action) else: task = Task(challenge.slug, task_id) db.session.add(task) db.session.flush() action = Action(task.id, "created") db.session.add(action) action = Action(task.id, "available") db.session.add(action) parser = reqparse.RequestParser() parser.add_argument('run', required=True, help="New tasks must include a Run ID") parser.add_argument('text', dest='instruction') parser.add_argument('location', type=GeoPoint, help="Location must be in the form lon|lat") parser.add_argument('manifest', type=JsonData, help="Manifest must be valid JSON") args = parser.parse_args() if request.form.get('run'): task['run'] = request.form['run'] if request.form.get('text'): task['instruction'] = request.form['text'] if request.form.get('location'): # WILL THIS WORK??? task['location'] = request.form['location'] if request.form.get('manifest'): task['manifest'] = request.form['manifest'] # LET'S HOPE ADDING IT TWICE DOESN'T BREAK ANYTHING db.session.add(task) db.commit() return task
def json_to_task(slug, data, task=None, identifier=None): """Parse task json coming in through the admin api""" if identifier is None and task is None: if not 'identifier' in data: raise Exception('no identifier given') identifier = data['identifier'] if task is None: # create the task if none was passed in try: task = Task(slug, identifier) except Exception, e: app.logger.warn(e.message) raise e
def create_testdata(challenges=10, tasks=100, users=10): """Creates test data in the database""" import uuid import random from maproulette import db from maproulette.models import User, Challenge, Task, TaskGeometry, Action from shapely.geometry import Point, LineString, box # statuses to use statuses = ['available', 'skipped', 'fixed', 'deleted', 'alreadyfixed', 'falsepositive'] # challenge default strings challenge_help_test = "Sample challenge *help* text" challenge_instruction_test = "Challenge instruction text" task_instruction_text = "Task instruction text" # delete old tasks and challenges db.session.query(TaskGeometry).delete() db.session.query(Action).delete() db.session.query(Task).delete() db.session.query(Challenge).delete() db.session.query(User).delete() db.session.commit() # create users for uid in range(int(users)): user = User() user.id = uid user.display_name = 'Test User {uid}'.format(uid=uid) db.session.add(user) db.session.commit() # create ten challenges for i in range(1, int(challenges) + 1): print "Generating Test Challenge #%d" % i minx = -120 maxx = -40 miny = 20 maxy = 50 challengepoly = None slug = "test%d" % i title = "Test Challenge %d" % i challenge = Challenge(slug, title) challenge.difficulty = random.choice([1, 2, 3]) challenge.active = True challenge.blurb = "This is test challenge number %d" % i challenge.description = "This describes challenge %d in detail" % i challenge.help = challenge_help_test challenge.instruction = challenge_instruction_test # have bounding boxes for all but the first two challenges. if i > 2: minx = random.randrange(-120, -40) miny = random.randrange(20, 50) maxx = minx + 1 maxy = miny + 1 challengepoly = box(minx, miny, maxx, maxy) print "\tChallenge has a bounding box of ", challengepoly challenge.polygon = challengepoly db.session.add(challenge) # add some tasks to the challenge print "\tGenerating %i tasks for challenge %i" % (int(tasks), i) # generate NUM_TASKS random tasks for j in range(int(tasks)): # generate a unique identifier identifier = str(uuid.uuid4()) # create two random points not too far apart task_geometries = [] p1 = Point( random.randrange(minx, maxx) + random.random(), random.randrange(miny, maxy) + random.random()) p2 = Point( p1.x + (random.random() * random.choice((1, -1)) * 0.01), p1.y + (random.random() * random.choice((1, -1)) * 0.01)) # create a linestring connecting the two points # no constructor for linestring from points? l1 = LineString([(p1.x, p1.y), (p2.x, p2.y)]) # add the first point and the linestring to the task's geometries task_geometries.append(TaskGeometry(p1)) # set a linestring for every other challenge if not j % 2: task_geometries.append(TaskGeometry(l1)) # instantiate the task and register it with challenge 'test' # Initialize a task with its challenge slug and persistent ID task = Task(challenge.slug, identifier, task_geometries) # because we are not using the API, we need to call set_location # explicitly to set the task's location task.set_location() # generate random string for the instruction task.instruction = task_instruction_text # set a status action = Action(random.choice(statuses), user_id=random.choice(range(int(users)))) task.append_action(action) # add the task to the session db.session.add(task) # commit the generated tasks and the challenge to the database. db.session.commit()
maxy = miny + 1 challengepoly = box(minx, miny, maxx, maxy) print "\tChallenge has a bounding box of ", challengepoly challenge.polygon = challengepoly db.session.add(challenge) # add some tasks to the challenge print "\tGenerating %i tasks for challenge %i" % (NUM_TASKS, i) # generate NUM_TASKS random tasks for j in range(NUM_TASKS): # generate a unique identifier identifier = str(uuid.uuid4()) # instantiate the task and register it with challenge 'test' # Initialize a task with its challenge slug and persistent ID task = Task(challenge.slug, identifier) # create two random points not too far apart p1 = Point( random.randrange(minx, maxx) + random.random(), random.randrange(miny, maxy) + random.random()) p2 = Point( p1.x + (random.random() * random.choice((1, -1)) * 0.01), p1.y + (random.random() * random.choice((1, -1)) * 0.01)) # create a linestring connecting the two points # no constructor for linestring from points? l1 = LineString([(p1.x, p1.y), (p2.x, p2.y)]) # generate some random 'osm ids' osmids = [random.randrange(1000000, 1000000000) for _ in range(2)] # add the first point and the linestring to the task's geometries task.geometries.append(TaskGeometry(osmids[0], p1)) task.geometries.append(TaskGeometry(osmids[1], l1))
def create_testdata(challenges=10, tasks=100, users=10): """Creates test data in the database""" import uuid import random from maproulette import db from maproulette.models import User, Challenge, Task, TaskGeometry, Action from shapely.geometry import Point, LineString, box # statuses to use statuses = ['available', 'skipped', 'fixed', 'deleted', 'alreadyfixed', 'falsepositive'] # challenge default strings challenge_help_test = "Sample challenge *help* text" challenge_instruction_test = "Challenge instruction text" task_instruction_text = "Task instruction text" # delete old tasks and challenges db.session.query(TaskGeometry).delete() db.session.query(Action).delete() db.session.query(Task).delete() db.session.query(Challenge).delete() db.session.query(User).delete() db.session.commit() # create users for uid in range(int(users)): user = User() user.id = uid user.display_name = 'Test User {uid}'.format(uid=uid) db.session.add(user) db.session.commit() # create ten challenges for i in range(1, int(challenges) + 1): print "Generating Test Challenge #%d" % i minx = -120 maxx = -40 miny = 20 maxy = 50 challengepoly = None slug = "test%d" % i title = "Test Challenge %d" % i challenge = Challenge(slug, title) challenge.difficulty = random.choice([1, 2, 3]) challenge.active = True challenge.blurb = "This is test challenge number %d" % i challenge.description = "This describes challenge %d in detail" % i challenge.help = challenge_help_test challenge.instruction = challenge_instruction_test # have bounding boxes for all but the first two challenges. if i > 2: minx = random.randrange(-120, -40) miny = random.randrange(20, 50) maxx = minx + 1 maxy = miny + 1 challengepoly = box(minx, miny, maxx, maxy) print "\tChallenge has a bounding box of ", challengepoly challenge.polygon = challengepoly db.session.add(challenge) # add some tasks to the challenge print "\tGenerating %i tasks for challenge %i" % (int(tasks), i) # generate NUM_TASKS random tasks for j in range(int(tasks)): # generate a unique identifier identifier = str(uuid.uuid4()) # create two random points not too far apart task_geometries = [] p1 = Point( random.randrange(minx, maxx) + random.random(), random.randrange(miny, maxy) + random.random()) p2 = Point( p1.x + (random.random() * random.choice((1, -1)) * 0.01), p1.y + (random.random() * random.choice((1, -1)) * 0.01)) # create a linestring connecting the two points # no constructor for linestring from points? l1 = LineString([(p1.x, p1.y), (p2.x, p2.y)]) # generate some random 'osm ids' osmids = [random.randrange(1000000, 1000000000) for _ in range(2)] # add the first point and the linestring to the task's geometries task_geometries.append(TaskGeometry(osmids[0], p1)) # set a linestring for every other challenge if not j % 2: task_geometries.append(TaskGeometry(osmids[1], l1)) # instantiate the task and register it with challenge 'test' # Initialize a task with its challenge slug and persistent ID task = Task(challenge.slug, identifier, task_geometries) # because we are not using the API, we need to call set_location # explicitly to set the task's location task.set_location() # generate random string for the instruction task.instruction = task_instruction_text # set a status action = Action(random.choice(statuses), user_id=random.choice(range(int(users)))) task.append_action(action) # add the task to the session db.session.add(task) # commit the generated tasks and the challenge to the database. db.session.commit()
def create_testdata(): """Creates test data in the database""" import uuid import random from maproulette.models import db, Challenge, Task, TaskGeometry, Action from shapely.geometry import Point, LineString, box num_challenges = 10 num_tasks = 100 # the gettysburg address challenge_help_test = "Sample challenge *help* text" challenge_instruction_test = "Challenge instruction text" task_instruction_text = "Task instruction text" # delete old tasks and challenges db.session.query(TaskGeometry).delete() db.session.query(Action).delete() db.session.query(Task).delete() db.session.query(Challenge).delete() db.session.commit() for i in range(1, num_challenges + 1): print "Generating Test Challenge #%d" % i minx = -120 maxx = -40 miny = 20 maxy = 50 challengepoly = None slug = "test%d" % i title = "Test Challenge %d" % i challenge = Challenge(slug, title) challenge.difficulty = random.choice([1, 2, 3]) challenge.active = True challenge.blurb = "This is test challenge number %d" % i challenge.description = "This describes test challenge %d in detail" % i challenge.help = challenge_help_test challenge.instruction = challenge_instruction_test # have bounding boxes for all but the first two challenges. if i > 2: minx = random.randrange(-120, -40) miny = random.randrange(20, 50) maxx = minx + 1 maxy = miny + 1 challengepoly = box(minx, miny, maxx, maxy) print "\tChallenge has a bounding box of ", challengepoly challenge.polygon = challengepoly db.session.add(challenge) # add some tasks to the challenge print "\tGenerating %i tasks for challenge %i" % (num_tasks, i) # generate NUM_TASKS random tasks for j in range(num_tasks): # generate a unique identifier identifier = str(uuid.uuid4()) # instantiate the task and register it with challenge 'test' # Initialize a task with its challenge slug and persistent ID task = Task(challenge.slug, identifier) # create two random points not too far apart p1 = Point(random.randrange(minx, maxx) + random.random(), random.randrange(miny, maxy) + random.random()) p2 = Point( p1.x + (random.random() * random.choice((1, -1)) * 0.01), p1.y + (random.random() * random.choice((1, -1)) * 0.01), ) # create a linestring connecting the two points # no constructor for linestring from points? l1 = LineString([(p1.x, p1.y), (p2.x, p2.y)]) # generate some random 'osm ids' osmids = [random.randrange(1000000, 1000000000) for _ in range(2)] # add the first point and the linestring to the task's geometries task.geometries.append(TaskGeometry(osmids[0], p1)) task.geometries.append(TaskGeometry(osmids[1], l1)) # and add the first point as the task's location task.location = p1 # generate random string for the instruction task.instruction = task_instruction_text # add the task to the session db.session.add(task) # commit the generated tasks and the challenge to the database. db.session.commit()