Esempio n. 1
0
def info_v1_0():
    raise APIError(
        "This is the Ocean Navigator API - Additional Parameters are required to complete a request, help can be found at ...")
Esempio n. 2
0
def plot_v1_0():
    """
    API Format: /api/v1.0/plot/?query='...'&format

    query = {
        dataset   : Dataset to extract data
        names     :
        plottitle : Title of Plot (Default if blank)
        quantum   : (year, month, day, hour)
        showmap   : Include a map of the plots location on the map
        station   : Coordinates of the point/line/area/etc
        time      : Time retrieved data was gathered/modeled
        type      : File / Plot Type (Check Navigator for Possible options)
        variable  : Type of data to plot - Options found using /api/variables/?dataset='...'
    }
    **Query must be written in JSON and converted to encodedURI**
    **Not all components of query are required
    """

    args = None
    if request.method == 'GET':
        args = request.args
    else:
        args = request.form

    if "query" not in args:
        raise APIError("Please provide a query.")

    query = json.loads(args.get('query'))

    fmt = args.get('format')
    if fmt == 'json':
        def make_response(data, mime):
            b64 = base64.encodebytes(data).decode()

            return Response(json.dumps("data:%s;base64,%s" % (
                mime,
                b64
            )), status=200, mimetype="application/json")
    else:
        def make_response(data, mime):
            return Response(data, status=200, mimetype=mime)

    dataset = query.get('dataset')
    plottype = query.get('type')

    """
    if 'station' in query:
        station = query.get('station')

        def wrapdeg(num):   #Ensures the lat and lon are between -180 and 180deg
            num = num % 360
            if num > 180:
                num = num - 360
            return num

        for index in range(0, len(station)):
            if station[index][0] >= 0:
                station[index][0] = wrapdeg(station[index][0])
            else:
                station[index][0] = wrapdeg(station[index][0])

            if station[index][1] >= 0:
                station[index][1] = wrapdeg(station[index][1])
            else:
                station[index][1] = wrapdeg(station[index][1])
    """

    options = {}
    options['format'] = fmt
    options['size'] = args.get('size', '15x9')
    options['dpi'] = args.get('dpi', 72)

    # Determine which plotter we need.
    if plottype == 'map':
        plotter = MapPlotter(dataset, query, **options)
    elif plottype == 'transect':
        plotter = TransectPlotter(dataset, query, **options)
    elif plottype == 'timeseries':
        plotter = TimeseriesPlotter(dataset, query, **options)
    elif plottype == 'ts':
        plotter = TemperatureSalinityPlotter(dataset, query, **options)
    elif plottype == 'sound':
        plotter = SoundSpeedPlotter(dataset, query, **options)
    elif plottype == 'profile':
        plotter = ProfilePlotter(dataset, query, **options)
    elif plottype == 'hovmoller':
        plotter = HovmollerPlotter(dataset, query, **options)
    elif plottype == 'observation':
        plotter = ObservationPlotter(dataset, query, **options)
    elif plottype == 'track':
        plotter = TrackPlotter(dataset, query, **options)
    elif plottype == 'class4':
        plotter = Class4Plotter(dataset, query, **options)
    elif plottype == 'stick':
        plotter = StickPlotter(dataset, query, **options)
    else:
        raise APIError(
            "You Have Not Selected a Plot Type - Please Review your Query")

    filename = 'png'

    if 'data' in request.args:
        data = plotter.prepare_plot()
        return data

    img, mime, filename = plotter.run()

    if img:
        response = make_response(img, mime)
    else:
        raise FAILURE

    if 'save' in args:
        response.headers[
            'Content-Disposition'] = "attachment; filename=\"%s\"" % filename

    response.cache_control.max_age = 300

    if 'data' in args:
        plotData = {
            'data': str(resp),
            'shape': resp.shape,
            'mask': str(resp.mask)
        }
        plotData = json.dumps(plotData)
        return Response(plotData, status=200, mimetype='application/json')

    return response
Esempio n. 3
0
def plot_v1_0():
    """
    API Format: /api/v1.0/plot/?query='...'&format

    query = {
        dataset   : Dataset to extract data
        names     :
        plottitle : Title of Plot (Default if blank)
        showmap   : Include a map of the plots location on the map
        station   : Coordinates of the point/line/area/etc
        time      : Time retrieved data was gathered/modeled
        type      : File / Plot Type (Check Navigator for Possible options)
        variable  : Variable key (e.g. votemper)
    }
    **Query must be written in JSON and converted to encodedURI**
    **Not all components of query are required
    """

    if request.method == "GET":
        args = request.args
    else:
        args = request.form

    if "query" not in args:
        raise APIError("Please provide a query.")

    query = json.loads(args.get("query"))

    fmt = args.get("format")
    if fmt == "json":

        def make_response(data, mime):
            b64 = base64.encodebytes(data).decode()

            return Response(
                json.dumps("data:%s;base64,%s" % (mime, b64)),
                status=200,
                mimetype="application/json",
            )

    else:

        def make_response(data, mime):
            return Response(data, status=200, mimetype=mime)

    dataset = query.get("dataset")
    plottype = query.get("type")

    options = {
        "format": fmt,
        "size": args.get("size", "15x9"),
        "dpi": args.get("dpi", 72),
    }

    # Determine which plotter we need.
    if plottype == "map":
        plotter = MapPlotter(dataset, query, **options)
    elif plottype == "transect":
        plotter = TransectPlotter(dataset, query, **options)
    elif plottype == "timeseries":
        plotter = TimeseriesPlotter(dataset, query, **options)
    elif plottype == "ts":
        plotter = TemperatureSalinityPlotter(dataset, query, **options)
    elif plottype == "sound":
        plotter = SoundSpeedPlotter(dataset, query, **options)
    elif plottype == "profile":
        plotter = ProfilePlotter(dataset, query, **options)
    elif plottype == "hovmoller":
        plotter = HovmollerPlotter(dataset, query, **options)
    elif plottype == "observation":
        plotter = ObservationPlotter(dataset, query, **options)
    elif plottype == "track":
        plotter = TrackPlotter(dataset, query, **options)
    elif plottype == "class4":
        plotter = Class4Plotter(dataset, query, **options)
    elif plottype == "stick":
        plotter = StickPlotter(dataset, query, **options)
    else:
        raise APIError("You Have Not Selected a Plot Type - Please Review your Query")

    if "data" in request.args:
        data = plotter.prepare_plot()
        return data

    img, mime, filename = plotter.run()

    if img:
        response = make_response(img, mime)
    else:
        raise FAILURE

    if "save" in args:
        response.headers["Content-Disposition"] = 'attachment; filename="%s"' % filename

    response.cache_control.max_age = 300

    if "data" in args:
        plotData = {
            "data": str(resp),  # noqa: F821
            "shape": resp.shape,  # noqa: F821
            "mask": str(resp.mask),  # noqa: F821
        }
        plotData = json.dumps(plotData)
        return Response(plotData, status=200, mimetype="application/json")

    return response
Esempio n. 4
0
def initialize_database(user, local):
    new_db_name = email_to_name(user.email)
    new_password = random_password()

    # Create a user that will have access to the new datase
    new_database = UserDatabase(drivername='mysql+pymysql',
                                username=new_db_name,
                                password=new_password,
                                host=app.config["APP_DB_HOST"],
                                port=app.config["APP_DB_PORT"],
                                database=new_db_name,
                                query=app.config["CLOUD_SQL_CONNECTION_NAME"],
                                user_id=user.id)

    url = get_db_url({
        'drivername': 'mysql+pymysql',
        'username': app.config["APP_DB_USER"],
        'password': app.config["APP_DB_PASS"],
        'host': app.config["APP_DB_HOST"],
        'port': app.config["APP_DB_PORT"],
        'database': new_db_name,
        'query': app.config["CLOUD_SQL_CONNECTION_NAME"]
    })

    # Step 1: create the new database
    if database_exists(url):
        raise APIError(
            http_code=409,
            error_type_key=APIErrorTypes.database_already_exists,
            message=
            f'Trying to create database {new_db_name} for user {user.email}, but the database already exists'
        )
    else:
        create_database(url)

    # Step 2: create all the tables in the new database
    # Setting the config to the new database url is a hack
    # to make sure SQLALCHAMY does all the heavy lifting
    app.config['SQLALCHEMY_BINDS']['user_db'] = url
    db.create_all(['user_db'])

    # Step 3: Create the new user so that someone can connect
    create_user_query = f'CREATE USER \'{new_db_name}\'@\'%%\' ' \
                        f'IDENTIFIED WITH mysql_native_password ' \
                        f'BY \'{new_password}\';'
    db.engine.execute(create_user_query)

    # Step 4: Give the user the right privileges
    priveleges = [
        'CREATE', 'INSERT', 'SELECT', 'UPDATE', 'ALTER', 'DROP', 'REFERENCES'
    ]
    priveleges_string = ', '.join(priveleges)

    priveleges_string = 'ALL PRIVILEGES'

    grant_perms_query = f'GRANT {priveleges_string} ON {new_db_name}.* ' \
                        f'TO \'{new_db_name}\'@\'%%\';'

    db.engine.execute(grant_perms_query)

    # Step 5: Create the alembic table for migration purposes
    alembic_create_query = f'CREATE TABLE `{new_db_name}`.`alembic_version` ' \
                           f'(' \
                           f'  `version_num` varchar(32) NOT NULL,' \
                           f'  PRIMARY KEY (`version_num`)' \
                           f')'
    db.engine.execute(alembic_create_query)

    # Step 6: Get the data that should be in the new alembic table
    alembic_select_query = f'SELECT `version_num` FROM ' \
                           f'`{app.config["EXAMPLE_DB_NAME"]}`.alembic_version'
    versions = db.engine.execute(alembic_select_query).fetchall()

    # Step 7: Insert the data into the new alembic table
    if len(versions) > 0:
        alembic_insert_query = f'INSERT INTO `{new_db_name}`.' \
                               f'`alembic_version` ' \
                               f'(`version_num`)\n' \
                               f'VALUES\n'
        for row in versions:
            alembic_insert_query += f'(\'{row[0]}\')'
        db.engine.execute(alembic_insert_query)

    # Step 8: Add the user to the session. As the relationship
    # to a UserDatabase object is created in the new_database creation,
    # adding the User object user to the session and committing it will
    # create a new User and UserDatabase row
    db.session.add(new_database)
    db.session.commit()

    createMetabase(user, local)

    return new_database
Esempio n. 5
0
def test_sentry():
    # Hit this endpoint to confirm that exception and transaction logging to Sentry are
    # operating correctly; a transaction should appear in the appropriate project at:
    # https://sentry.io/organizations/dfo-ocean-navigator/performance/
    raise APIError("This is the Ocean Navigator API Sentry integration test endpoint.")