예제 #1
0
def _before_requests():
    """Executed before each request for this blueprint.

    Get the request form and session details.

    Returns:
        None|Response: In case of validation error, returns a Flask response, None otherwise.
    """
    logger.info('API request [endpoint: "%s"]', request.endpoint)
    form = VectorEmbedForm(
    ) if request.endpoint[7:12] == 'embed' else VectorDetectForm()
    if not form.validate_on_submit():
        return make_response(form.errors, 400)

    session = get_session()

    src_file = os.path.join(os.environ['INPUT_DIR'], form.original.data)

    g.src_file = src_file
    g.form = form
    g.session = session

    g.params = parse_read_options(form)
    if request.endpoint[7:12] != 'embed':
        g.test_file = os.path.join(os.environ['INPUT_DIR'], form.test.data)
        g.test_params = parse_read_options(form, prefix='test_')
예제 #2
0
def detect_message():
    """**Flask POST rule**.

    Detect an invisible message.
    ---
    post:
        summary: Detect an invisible message.
        description: Detect an invisible message, previously embedded to the raster.
        tags:
            - Raster
        parameters:
            - idempotencyKey
        requestBody:
            required: true
            content:
                application/json:
                    schema: rasterDetectForm
        responses:
            200: promptDetectResponse
            202: deferredResponse
            400: validationErrorResponse
    """
    logger.info('API request [endpoint: "%s"]', request.endpoint)
    form = RasterDetectForm()
    if not form.validate_on_submit():
        return make_response(form.errors, 400)
    g.session = get_session()
    raster = os.path.join(os.environ['INPUT_DIR'], form.raster.data)
    watermarked = os.path.join(os.environ['INPUT_DIR'], form.watermarked.data)

    if form.response.data == 'prompt':
        session, message, success, error_msg = raster_detect_process(
            g.session, raster, watermarked)
        if not success:
            db_update_queue_status(g.session['ticket'],
                                   completed=True,
                                   success=False,
                                   error_msg=error_msg)
            return make_response({'error': error_msg}, 500)
        db_update_queue_status(session['ticket'],
                               completed=True,
                               success=True,
                               result=message)
        return make_response({'type': 'prompt', 'key': message}, 200)

    future = executor.submit(raster_detect_process, g.session, raster,
                             watermarked)
    future.add_done_callback(async_callback)
    return make_response(
        {
            'type':
            'deferred',
            'ticket':
            g.session['ticket'],
            'statusUri':
            "/jobs/status?ticket={ticket}".format(ticket=g.session['ticket'])
        }, 202)
예제 #3
0
def embed_message():
    """**Flask POST rule**.

    Embed an invisible message.
    ---
    post:
        summary: Embed an invisible message.
        description: Embed an invisible message to raster.
        tags:
            - Raster
        parameters:
            - idempotencyKey
        requestBody:
            required: true
            content:
                application/json:
                    schema: rasterEmbedMessageForm
        responses:
            200: promptEmbedResponse
            202: deferredResponse
            400: validationErrorResponse
    """
    logger.info('API request [endpoint: "%s"]', request.endpoint)
    form = RasterEmbedForm()
    if not form.validate_on_submit():
        return make_response(form.errors, 400)
    g.session = get_session()
    raster = os.path.join(os.environ['INPUT_DIR'], form.raster.data)

    if form.response.data == 'prompt':
        session, export, success, error_msg = raster_embed_process(
            'message', g.session, raster, form.message.data)
        if not success:
            db_update_queue_status(g.session['ticket'],
                                   completed=True,
                                   success=False,
                                   error_msg=error_msg)
            return make_response({'error': error_msg}, 500)
        path = copy_to_output(export, session['ticket'])
        db_update_queue_status(session['ticket'],
                               completed=True,
                               success=True,
                               result=path)
        return make_response({'type': 'prompt', 'path': path}, 200)

    future = executor.submit(raster_embed_process, 'message', g.session,
                             raster, form.message.data)
    future.add_done_callback(async_callback)
    return make_response(
        {
            'type':
            'deferred',
            'ticket':
            g.session['ticket'],
            'statusUri':
            "/jobs/status?ticket={ticket}".format(ticket=g.session['ticket'])
        }, 202)
예제 #4
0
def info():
    """**Flask GET rule**.

    Get the running processes.
    ---
    get:
        summary: Get the running processes.
        description: Get the running processes among all sessions.
        tags:
            - Jobs
        responses:
            200:
                description: The list of the running processes.
                content:
                    application/json:
                        schema:
                            type: array
                            items:
                                description: Details of the process.
                                type: object
                                properties:
                                    ticket:
                                        type: string
                                        description: The ticket assigne to the process.
                                        example: caff960ab6f1627c11b0de3c6406a140
                                    idempotencyKey:
                                        type: string
                                        description: The X-Idempotency-Key sent in the headers of the request (null if the request was not associated with an idempotency key).
                                        example: e5d16e99-dee1-4d16-acce-ca0f20a83a0a
                                    requestType:
                                        type: string
                                        description: Type of the request.
                                    initiated:
                                        type: string
                                        format: date-time
                                        description: The timestamp of the request.
    """
    logger.info('API request [endpoint: "%s"]', request.endpoint)
    running = db_get_active_jobs()
    return make_response(jsonify(running), 200)
예제 #5
0
def embed_watermark():
    """**Flask POST rule**.

    Embed a visible watermark.
    ---
    post:
        summary: Embed a visible watermark.
        description: Embed a visible watermark, placed according to the given parameters.
        tags:
            - Raster
        parameters:
            - idempotencyKey
        requestBody:
            required: true
            content:
                application/json:
                    schema: rasterEmbedWatermarkForm
        responses:
            200: promptEmbedResponse
            202: deferredResponse
            400: validationErrorResponse
    """
    logger.info('API request [endpoint: "%s"]', request.endpoint)
    form = RasterVisibleEmbedForm()
    if not form.validate_on_submit():
        return make_response(form.errors, 400)
    g.session = get_session()
    raster = os.path.join(os.environ['INPUT_DIR'], form.raster.data)
    watermark = os.path.join(os.environ['INPUT_DIR'], form.watermark.data)
    params = {
        'transparency': form.transparency.data,
        'fit': form.fit.data,
        'position': form.position.data
    }
    if params['fit'] == 'tile':
        params['distance'] = (form.distance_x.data, form.distance_y.data)

    if form.response.data == 'prompt':
        session, export, success, error_msg = raster_embed_process(
            'watermark', g.session, raster, watermark, **params)
        if not success:
            db_update_queue_status(g.session['ticket'],
                                   completed=True,
                                   success=False,
                                   error_msg=error_msg)
            return make_response({'error': error_msg}, 500)
        path = copy_to_output(export, session['ticket'])
        db_update_queue_status(session['ticket'],
                               completed=True,
                               success=True,
                               result=path)
        return make_response({'type': 'prompt', 'path': path}, 200)

    future = executor.submit(raster_embed_process, 'watermark', g.session,
                             raster, watermark, **params)
    future.add_done_callback(async_callback)
    return make_response(
        {
            'type':
            'deferred',
            'ticket':
            g.session['ticket'],
            'statusUri':
            "/jobs/status?ticket={ticket}".format(ticket=g.session['ticket'])
        }, 202)
예제 #6
0
def status():
    """**Flask GET rule**.

    Returns the status of a process.
    ---
    get:
        summary: Returns the status of a process.
        description: Returns the status of the process identified by a ticket or idempotency key.
        tags:
            - Jobs
        parameters:
            -
                name: ticket
                in: query
                schema:
                    type: string
                required: false
                description: The request ticket (required if *idempotency-key* is not given).
            -
                name: idempotency-key
                in: query
                schema:
                    type: string
                required: false
                description: The idempotency-key sent with the request (required if *ticket* is not given).
        responses:
            200:
                description: The process was found and the response contains its status details.
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                ticket:
                                    type: string
                                    description: Request ticket.
                                    example: caff960ab6f1627c11b0de3c6406a140
                                idempotencyKey:
                                    type: string
                                    description: The X-Idempotency-Key sent in the headers of the request (null if the request was not associated with an idempotency key).
                                    example: e5d16e99-dee1-4d16-acce-ca0f20a83a0a
                                requestType:
                                    type: string
                                    enum:
                                        - ingest
                                        - export
                                    description: Type of the request.
                                initiated:
                                    type: string
                                    format: date-time
                                    description: The timestamp of the request.
                                executionTime:
                                    type: number
                                    format: float
                                    description: The execution time in seconds.
                                    example: 8.29
                                completed:
                                    type: boolean
                                    description: Whether the process has been completed.
                                success:
                                    type: boolean
                                    description: Whether the process has been completed succesfully.
                                errorMessage:
                                    type: string
                                    description: The error message in case of failure.
                                resource:
                                    type: object
                                    description: The resource, in case the process result is a resource.
                                    properties:
                                        link:
                                            type: string
                                            description: The link to download a resource resulted from an export request; null for any other type of request.
                                            example: /download/my_dataset.tar.gz
                                        outputPath:
                                            type: string
                                            description: The relative path of the resource resulted from an export request in the output directory; null for any other type of request or if copy to the output directory was not requested.
                                            example: 2102/{token}/caff960ab6f1627c11b0de3c6406a140/my_dataset.tar.gz
                                key:
                                    type: string
                                    description: The result of the process.
                                    example: 09061d7e-3b1a-4a14-bfa5-b65b9ce0412d
            400:
                description: Both query parameters are missing.
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                status:
                                    type: string
                                    description: Error message
                                    example: One of 'ticket', 'idempotency-key' is required in query parameters.
            404:
                description: The ticket or idempotency-key not found.
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                status:
                                    type: string
                                    description: Error message
                                    example: Process not found.
    """
    ticket = request.args.get('ticket')
    key = request.args.get('idempotency-key')
    logger.info('API request [endpoint: "%s", ticket: "%s", idempotency-key: "%s"]', request.endpoint, ticket, key)
    if ticket is not None:
        queue = Queue().get(ticket=ticket)
    elif key is not None:
        queue = Queue().get(idempotency_key=key)
    else:
        return make_response({"status": "One of 'ticket', 'idempotency-key' is required in query parameters."}, 400)
    if queue is None:
        return make_response({"status": "Process not found."}, 404)
    resource = {'link': None, 'outputPath': None}
    key = None
    if queue['result'] is not None:
        if os.path.isfile(os.path.join(os.environ['OUTPUT_DIR'], queue['result'])):
            resource = {'link': '/download/{ticket}/{filename}'.format(ticket=queue['ticket'], filename=os.path.basename(queue['result'])), 'outputPath': queue['result']}
        else:
            key = queue['result']
    info = {
        "ticket": queue['ticket'],
        "idempotencyKey": queue['idempotency_key'],
        "requestType": queue['request'],
        "initiated": queue['initiated'],
        "executionTime": queue['execution_time'],
        "completed": queue['completed'],
        "success": queue['success'],
        "errorMessage": queue['error_msg'],
        "resource": resource,
        "key": key
    }
    return make_response(info, 200)
예제 #7
0
def health():
    """**Flask GET rule**

    Perform basic health checks.
    ---
    get:
        summary: Get health status.
        tags:
            - Misc
        responses:
            200:
                description: An object with status information.
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                status:
                                    type: string
                                    enum:
                                        - OK
                                        - FAILED
                                    description: A status of 'OK' or 'FAILED'.
                                details:
                                    type: object
                                    description: The reason of failure for each component, or 'OK' if not failed.
                                    properties:
                                        gdal:
                                            type: string
                                            example: OK
                                        filesystem:
                                            type: string
                                            example: OK
                                        db:
                                            type: string
                                            example: OK
    """
    from osgeo import ogr

    logger.info('Performing health checks...')
    msg = {'gdal': 'OK', 'filesystem': 'OK', 'db': 'OK'}
    status = True

    for drv in ['CSV', 'GeoJSON', 'ESRI Shapefile']:
        if ogr.GetDriverByName(drv) is None:
            msg['gdal'] = 'GDAL is not properly installed.'
            status = False
            break

    for path in [os.environ['WORKING_DIR'], os.environ['OUTPUT_DIR']]:
        try:
            _checkDirectoryWritable(path)
        except Exception as e:
            msg['filesystem'] = str(e)
            status = False
            break

    try:
        _checkConnectToDB()
    except Exception as e:
        msg['db'] = str(e)
        status = False

    return make_response(
        {
            'status': 'OK' if status else 'FAILED',
            'details': msg
        }, 200)
예제 #8
0
def download(ticket, filename):
    """**Flask GET rule

    Download a resource.
    ---
    get:
        summary: Download a resource.
        tags:
            - Misc
        parameters:
            -
                name: ticket
                in: path
                schema:
                    type: string
                description: The ticket of the request resulted in the resource.
            -
                name: filename
                in: path
                schema:
                    type: string
                description: The requested file name.
        responses:
            200:
                description: The requested file.
                content:
                    application/x-tar:
                        schema:
                            type: string
                            format: binary
            404:
                description: Ticket not found.
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                status:
                                    type: string
                                    description: Error message
                                    example: Ticket not found.
            410:
                description: Resource not available.
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                status:
                                    type: string
                                    description: Error message
                                    example: Resource not available.
    """
    logger.info('API request [endpoint: "%s"]', request.endpoint)
    queue = Queue().get(ticket=ticket)
    if queue is None:
        return make_response({"status": "Ticket not found."}, 404)
    path = os.path.join(os.environ['OUTPUT_DIR'], queue['result'])
    if filename != os.path.basename(
            queue['result']) or not os.path.isfile(path):
        return make_response({"status": "Resource not available."}, 410)
    return send_file(path)