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 ...")
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
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
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
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.")