Beispiel #1
0
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)
Beispiel #2
0
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())
Beispiel #3
0
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))
Beispiel #4
0
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)
Beispiel #5
0
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())
Beispiel #6
0
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
Beispiel #7
0
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())
Beispiel #8
0
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)
Beispiel #9
0
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)
Beispiel #10
0
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)
Beispiel #11
0
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)
Beispiel #12
0
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())
Beispiel #13
0
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)))
Beispiel #14
0
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)
Beispiel #15
0
def on_join(map_id):
    #TODO: authenticated
    if Map.get(map_id):
        join_room(map_id)
        send('user joined', room=map_id)
Beispiel #16
0
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)
Beispiel #17
0
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())
Beispiel #18
0
def on_leave(map_id):
    if Map.get(map_id):
        leave_room(map_id)
        send('user left', room=map_id)