def test_map_delete_private(app, db): m = Map('foo', bbox=[1, 1, 1, 1]) db.session.add(m) db.session.commit() token = m.gen_token() resp = _get_map(app, m.uuid, token) assert (resp.status_code == 200) with app.test_client() as client: point = GeoFeature(geometry=GeoPoint([1, 1])) f = Feature(point) m.features.append(f) db.session.add(m) db.session.commit() url = '/api/maps/{}'.format(m.uuid) resp = client.delete(url) assert (resp.status_code == 401 ) # TODO: should be 404 for private maps headers = {'X-MAP': m.uuid, 'X-TOKEN': token} resp = client.delete(url, headers=headers) assert (resp.status_code == 204) assert (not Map.get(m.uuid)) resp = _get_map(app, m.uuid, token) assert (resp.status_code == 404)
def map_edit(map_id): m = Map.get(map_id) if not m: abort(404) json = request.json for key in [ 'name', 'bbox', 'description', 'place', 'attributes', 'published' ]: if key in json: setattr(m, key, json[key]) if 'theme' in json and json['theme'] in current_app.config['MAP_RENDERER']: m.theme = json['theme'] if 'datetime' in json: m.datetime = datetime_fromisoformat(request.json['datetime']) if 'lifespan' in json: m.lifespan = timedelta(days=request.json['lifespan']) db.session.add(m) db.session.commit() return jsonify(m.to_dict())
def map_features(map_id): m = Map.get(map_id) if not m or not (m.published or auth()): abort(404) features = [f.to_dict() for f in m.features] return jsonify(FeatureCollection(features))
def map_render(map_id, file_type): """Renders a map **Example request**: .. sourcecode:: bash $ curl -i -X POST -H "Content-Type: application/json" -d @tests/data/test_map.json http://localhost:5000/render/png **Example response**: .. sourcecode:: http HTTP/1.1 202 Accepted Content-Type: application/json { "file_type": "png", "job_id": "fce3b682-feaa-48b7-b945-ad243ce62df4", "map_id": "test123", "status": "queued", "version": "c8bbde29fa1cfd1109fae1835fcc1ea1f92f4e31292c1b3d338c782f18333605" } :param file_type: file type of rendered map. Either `pdf`, `svg` or `png:<size>` with size `small`, `medium` or `large` """ _map = Map.get(map_id) if not _map: abort(404) # TODO: merge with file_info exception UnsupportedFileType extension = file_type.split(':')[0] if '.' + extension not in mimetypes.types_map: abort(400) # if already rendered or enqueued, don't enqueue again version = _map.version force = request.args.get('force', default=False, type=bool) try: if not force: return status_by_map(map_id, file_type, version) except NotFound: pass data = _map.to_dict(grid_included=True, features_included=True) args = (data, file_type, force) queue = current_app.task_queue meta = { 'map_id': map_id, 'version': version, 'file_type': file_type, } job = queue.enqueue("app.tasks.render_map", *args, meta=meta) return status_by_job(job)
def gen_auth_token(map_id): secret = request.headers.get('X-Secret', '') obj = Map.get(map_id) if not obj or not secret: abort(400) # bad request - invalid input if not safe_str_cmp(secret, obj.secret): abort(401) # forbidden - secrets do not match return jsonify(token=obj.gen_token())
def auth(): map_id = request.headers.get('X-Map') token = request.headers.get('X-Token') if not map_id or not token: return False obj = Map.get(map_id) if not obj or not obj.check_token(token): return False return True
def test_maps_new_datetime(app, db): name = 'foo-new-private' now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc) uuid, token = _create_map(app, {'name': name, 'datetime': now.isoformat()}) m = Map.get(uuid) assert (m) assert (m.datetime == now) assert (not m.outdated) resp = _get_map(app, m.uuid, token) assert (resp.status_code == 200) assert (resp.json['datetime'] == now.isoformat())
def map_features_new(map_id): m = Map.get(map_id) if not m: abort(404) if not request.json or not Feature(request.json).is_valid: abort(400) # TODO: strip input data feature = MapFeature(request.json) m.features.append(feature) db.session.add(m) db.session.commit() return make_response(jsonify(feature.to_dict()), 201)
def test_maps_new_private(app, db): name = 'foo-new-private' uuid, token = _create_map(app, {'name': name}) m = Map.get(uuid) assert (m) assert (m.name == name) assert (m.check_token(token)) assert (not m.published) assert (not m.outdated) # FORBIDDEN is 404 not 403 (to prevent leak of sensitive data) resp = _get_map(app, uuid) assert (resp.status_code == 404) for t in ['WRONG_TOKEN', 'undefined', 'NULL', None, [], {}]: resp = _get_map(app, uuid, t) assert (resp.status_code == 404) resp = _get_map(app, uuid, token) assert (resp.status_code == 200)
def map_download(map_id, file_type, version=None): """ Download a map identified by map_id, file_type and optional version. Only already rendered maps can be downloaded. Each file format has to be rendered separately. If a map is not found you will get an 404 error statuscode. :param map_id: id of map :param file_type: `svg`, `pdf` or `png[:small|medium|large]` :status 200: sends content of map :status 404: map, version or file_type not found """ m = Map.get(map_id) if not m: abort(404) if not version: version = m.version dirname = sha256(map_id.encode()).hexdigest() extension, *args = file_type.split(':') mimetype = mimetypes.types_map['.' + extension] suffix = '' if len(args) > 0: suffix = '_' + args.pop() filename = '{}{}.{}'.format(version, suffix, extension) static_path = current_app.static_folder path = os.path.join(static_path, 'maps', dirname, filename) # map is already rendered if os.path.exists(path): return send_file(path, attachment_filename=filename, mimetype=mimetype) # map is not yet rendered return map_render(map_id, file_type)
def map_export_twitter(map_id): m = Map.get(map_id) if not m or not m.published: abort(404) url = "%s#/de/maps/%s/map" % (request.url_root, map_id) datetime = m.datetime.strftime("%d.%m.%Y %H:%M") data = { 'card': 'summary_large_image', 'site': '@aktionskarten_', 'title': 'Aktionskarten - ' + m.name, 'description': '%s @ %s' % (datetime, m.place), 'image': url_for('Renderer.map_download', map_id=map_id, file_type='png', _external=True) } return render_template('twitter.html', data=data, url=url)
def map_get(map_id): m = Map.get(map_id.hex) if not m or not (auth() or m.published) or m.outdated: abort(404) return jsonify(m.to_dict())
def map_export_geojson(map_id): m = Map.get(map_id) if not m or not (m.published or auth()): abort(404) features = [f.to_dict() for f in m.features] return jsonify(FeatureCollection(features, properties=m.to_dict(False)))
def map_get_grid(map_id): m = Map.get(map_id) if not m or not (m.published or auth()): abort(404) return jsonify(m.grid)
def on_join(map_id): #TODO: authenticated if Map.get(map_id): join_room(map_id) send('user joined', room=map_id)
def map_wait_until_finished(map_id, file_type, version=None): m = Map.get(map_id) if not m: abort(404) return render_template('rendering.html', m=m, file_type=file_type)
def render(mid, filename): m = Map.get(mid) data = m.to_dict(grid_included=True, features_included=True) renderer = SurfaceRenderer(data) with open(filename, 'wb') as f2: f2.write(renderer.render('application/pdf').read())
def on_leave(map_id): if Map.get(map_id): leave_room(map_id) send('user left', room=map_id)