def post(self): ''' Create a foreign server ''' drivers = Database.notices(multicorn_drivers_sql)[-1] drivers = drivers.strip('NOTICE: \n').split(',') if api.payload['driver'] not in drivers: return abort( 400, '{} driver does not exist, available drivers are {}' .format(api.payload['driver'], drivers)) options = api.payload['options'] options.update(wrapper=api.payload['driver']) options = {k: str(v) for k, v in options.items()} options_sql = sql.SQL(', ').join([ sql.SQL(' ').join((sql.Identifier(opt), sql.Placeholder(opt))) for opt in options ]) req = sql.SQL(""" create server {name} foreign data wrapper multicorn options ( {options} ); """).format(name=sql.Identifier(api.payload['name']), options=options_sql) Database.rowcount(req, options) req = servers_sql + ' where srvname = %(name)s' return Database.query_asjson(req, api.payload), 201
def transfo_trees(name, url, label, ids): edges = Database.query( """ select t.id, t.source, t.target, t.transfo_type, t.name, tft.name as tname from ( select distinct unnest(tt.transfos) as tid from li3ds.transfo_tree tt where tt.id = ANY(%s) ) as tf join li3ds.transfo t on t.id = tf.tid join li3ds.transfo_type tft on tft.id = t.transfo_type """, (list(ids), ) ) urefs = set() for edge in edges: urefs.add(edge.source) urefs.add(edge.target) nodes = Database.query(""" select distinct r.id, r.name, r.sensor, s.name as sname, s.type from li3ds.referential r join li3ds.sensor s on r.sensor = s.id where ARRAY[r.id] <@ %s """, (list(urefs), )) return make_dot(name, url, label, nodes, edges)
def post(self): ''' Import foreign schema for a rosbag file ''' req = sql.SQL(""" create schema if not exists {schema}; select coalesce(max(pcid) + 1, 1) as pcid from pointcloud_formats """).format(schema=sql.Identifier(api.payload['schema'])) pcid = Database.query_asdict(req)[0]['pcid'] identifiers = {k: sql.Identifier(v) for k, v in api.payload.items()} req = sql.SQL(""" import foreign schema {rosbag} limit to (pointcloud_formats) from server {server} into {schema} options (pcid %(pcid)s); insert into pointcloud_formats select pcid, srid, schema from {schema}.pointcloud_formats; import foreign schema {rosbag} except (pointcloud_formats) from server {server} into {schema} options (pcid %(pcid)s) """).format(**identifiers) Database.rowcount(req, {'pcid': str(pcid)}) return "foreign schema imported", 201
def get(self, session_id): '''List all images in a given session with their location''' # get project name res = Database.query( """ select p.id, p.name from li3ds.project p join li3ds.session s on s.project = p.id where s.id = %s """, (session_id, )) if not res: nsitowns.abort(404, 'Session not found') project_name, project_id = res[0].name, res[0].id return Database.query_asjson( """ with images as ( -- extract image epoch select i.id, i.filename, i.etime, extract(epoch from etime) as epoch, rf.sensor from %(project)s.image i join li3ds.datasource ds on i.datasource = ds.id join li3ds.referential rf on ds.referential = rf.id where ds.session = %(session)s ), posdatasource as ( -- get latest version of the route select max(pds.id) as id, max(version) from li3ds.project p join li3ds.session s on s.project = p.id join li3ds.posdatasource pds on pds.session = s.id where p.id = %(project_id)s ) select i.id, i.filename, i.etime as date, i.sensor, pc_get(newpt, 'x') as easting, pc_get(newpt, 'y') as northing, pc_get(newpt, 'z') as altitude, pc_get(newpt, 'm_roll') as roll, pc_get(newpt, 'm_pitch') as pitch, pc_get(newpt, 'm_plateformHeading') - pc_get(newpt, 'm_wanderAngle') as heading from posdatasource pds join %(project)s.route r on pds.id = r.posdatasource join images i on i.etime <@ tstzrange(r.start_time, r.end_time), pc_interpolate(r.points, 'm_time', i.epoch) as newpt """, ({ 'project': AsIs(project_name), 'project_id': project_id, 'session': session_id }))
def delete(self, name): ''' Delete a project. ''' res = Database.query_asjson("select * from li3ds.project where name=%s", (name,)) if not res: nsproject.abort(404, 'Project not found') Database.query_aslist("delete from li3ds.project where id=%s", (name,)) return '', 410
def delete(self, name): ''' Delete a project. ''' res = Database.query_asjson("select * from li3ds.project where name=%s", (name,)) if not res: nsproject.abort(404, 'Project not found') Database.query_aslist("select li3ds.delete_project(%s)", (name,)) return '', 410
def get(self, name): '''List all sessions for a given project''' res = Database.query_asjson("select * from li3ds.project where name=%s", (name,)) if not res: nsproject.abort(404, 'Project not found') return Database.query_asjson( """select s.* from li3ds.session s join li3ds.project p on s.project=p.id where p.name=%s """, (name,) )
def get(self, id): '''Get the posprocessing tool used to generate this datasource''' res = Database.query_asjson( "select * from li3ds.posdatasource where id=%s", (id,) ) if not res: nspds.abort(404, 'PosDatasource not found') return Database.query_asjson( " select p.* from li3ds.posprocessing p" " join li3ds.posdatasource s on s.id = p.target where s.id=%s", (id,) )
def get(self, id): '''List session positional datasources''' return Database.query_asjson( """select d.* from li3ds.session s join li3ds.posdatasource d on d.session = s.id where s.id = %s """, (id, ))
def get(self, id): '''List session datasources''' return Database.query_asjson( """select d.* from li3ds.session s join li3ds.datasource d on d.session = s.id where s.id = %s """, (id,))
def get(self, id): '''Get the platform used by the given session''' return Database.query_asjson( """select p.* from li3ds.platform p join li3ds.session s on s.platform = p.id where s.id=%s """, (id,) )
def get(self, id): '''Get one sensor given its identifier''' res = Database.query_asjson("select * from li3ds.sensor where id=%s", (id, )) if not res: nssensor.abort(404, 'sensor not found') return res
def get(self, id): '''Get one transformation given its identifier''' res = Database.query_asjson( "select * from li3ds.transfo_tree where id=%s", (id, )) if not res: nstft.abort(404, 'Transformation tree not found') return res
def delete(self, id): '''Delete a transformation given its identifier''' res = Database.rowcount("delete from li3ds.transfo_tree where id=%s", (id, )) if not res: nstft.abort(404, 'Transformation tree not found') return '', 410
def delete(self, id): '''Delete a session given its identifier''' res = Database.rowcount("delete from li3ds.session where id=%s", (id, )) if not res: nssession.abort(404, 'Session not found') return '', 410
def post(self): '''Create a referential''' return Database.query_asdict( "insert into li3ds.referential (name, description, srid, root, sensor) " "values (%(name)s, %(description)s, %(srid)s, %(root)s, %(sensor)s) " "returning *", defaultpayload(api.payload) ), 201
def post(self, id): '''Create a new platform configuration''' return Database.query_asdict( "insert into li3ds.platform_config (name, owner, platform, transfo_trees) " "values (%(name)s, %(owner)s, {}, %(transfo_trees)s) " "returning *".format(id), defaultpayload(api.payload) ), 201
def post(self): '''Create a platform''' return Database.query_asdict( "insert into li3ds.platform (name, description, start_time, end_time) " "values (%(name)s, %(description)s, %(start_time)s, %(end_time)s) " "returning *", defaultpayload(api.payload) ), 201
def get(self, id): '''Get one datasource given its identifier''' res = Database.query_asjson( "select * from li3ds.posdatasource where id=%s", (id,) ) if not res: nspds.abort(404, 'PosDatasource not found') return res
def post(self): '''Create a datasource''' return Database.query_asdict( "insert into li3ds.posdatasource (referential, session, uri) " "values (%(referential)s, %(session)s, %(uri)s) " "returning *", defaultpayload(api.payload) ), 201
def get(self, id): '''Get one sensor given its identifier''' res = Database.query_asjson( "select * from li3ds.sensor where id=%s", (id,) ) if not res: nssensor.abort(404, 'sensor not found') return res
def post(self, id): '''Add a new posprocessing tool that has generated the given datasource''' return Database.query_asdict( "insert into li3ds.posprocessing (launched, tool, description, source, target) " "values (%(launched)s, %(tool)s, %(description)s, %(source)s, {}) " "returning *".format(id), defaultpayload(api.payload) ), 201
def get(self, id): '''Get one referential given its identifier''' res = Database.query_asjson( "select * from li3ds.referential where id=%s", (id,) ) if not res: nsrf.abort(404, 'Referential not found') return res
def post(self): '''Create a referential''' return Database.query_asdict( "insert into li3ds.referential (name, description, srid, sensor) " "values (%(name)s, %(description)s, %(srid)s, %(sensor)s) " "returning *", defaultpayload(api.payload) ), 201
def get(self, id): '''Get one platform given its identifier''' res = Database.query_asjson( "select * from li3ds.platform where id=%s", (id,) ) if not res: nspfm.abort(404, 'Platform not found') return res
def post(self): '''Create a session''' return Database.query_asdict( "insert into li3ds.session (name, start_time, end_time, project, platform) " "values (%(name)s, %(start_time)s, %(end_time)s, %(project)s, %(platform)s) " "returning *", defaultpayload(api.payload) ), 201
def get(self, id): '''Get one transformation given its identifier''' res = Database.query_asjson( "select * from li3ds.transfo_tree where id=%s", (id,) ) if not res: nstft.abort(404, 'Transformation tree not found') return res
def get(self, session_id): '''List all camera calibrations for a given session''' if 'platform_config' not in request.args: nsitowns.abort(500, 'parameter required : platform_config') # get all cameras for this platform configuration values = Database.query_asjson( """ with transfos as ( -- all transformations for this platform config select unnest(tt.transfos) as tid from li3ds.platform_config pf join li3ds.transfo_tree tt on tt.id = ANY(pf.transfo_trees) where pf.id = %(pconfig)s ), ins_transfo as ( -- get ins first transformation select trlist.tid as target from transfos trlist join li3ds.transfo tr on tr.id = trlist.tid join li3ds.referential r on tr.source = r.id or tr.target = r.id join li3ds.sensor s on s.id = r.sensor where s.type = 'ins' and r.root ), camera_transfo as ( -- get all camera first transformations select tr.id as source, se.* from li3ds.session s join li3ds.datasource ds on ds.session = s.id join li3ds.referential r on r.id = ds.referential join li3ds.sensor se on se.id = r.sensor join li3ds.transfo tr on tr.source = r.id or tr.target = r.id join transfos trlist on trlist.tid = tr.id where s.id = %(session)s and se.type = 'camera' ) select id , ARRAY[specifications->'size_x', specifications->'size_y'] as size , _.transfos from camera_transfo , ins_transfo , li3ds.dijkstra(%(pconfig)s, source, target) as path , lateral ( select jsonb_agg(row_to_json(s)) as transfos from ( select t.id, t.parameters, tt.description, tt.func_name as type from unnest(path) with ordinality as u(tid, ord) join li3ds.transfo t on t.id = tid join li3ds.transfo_type tt on tt.id = t.transfo_type ) as s ) as _ """, ({ 'pconfig': request.args['platform_config'], 'session': session_id })) return values
def post(self): '''Create a transformation between referentials''' return Database.query_asdict( """ insert into li3ds.transfo_tree (name, isdefault, sensor_connections, owner, transfos) values (%(name)s,%(isdefault)s,%(sensor_connections)s,%(owner)s,%(transfos)s) returning * """, defaultpayload(api.payload)), 201
def post(self): ''' Create a project. Also create a schema with the project's name. ''' return Database.query_asdict( "select li3ds.create_project(%(name)s, %(timezone)s, %(extent)s) as id", defaultpayload(api.payload) ), 201
def post(self): '''Create a transformation between referentials''' return Database.query_asdict( """ insert into li3ds.transfo_tree (name, owner, transfos) values (%(name)s,%(owner)s,%(transfos)s) returning * """, defaultpayload(api.payload) ), 201
def post(self): '''Create a transformation type''' return Database.query_asdict( """ insert into li3ds.transfo_type (name, description, func_signature) values (%(name)s,%(description)s,%(func_signature)s) returning * """, defaultpayload(api.payload) ), 201
def post(self): '''Create a transformation type''' return Database.query_asdict( """ insert into li3ds.transfo_type (func_name, description, func_signature) values (%(func_name)s,%(description)s,%(func_signature)s) returning * """, defaultpayload(api.payload) ), 201
def post(self): '''Create a sensor''' return Database.query_asdict( """ insert into li3ds.sensor (serial_number, short_name, brand, model, description, specifications, type) values (%(serial_number)s, %(short_name)s, %(brand)s, %(model)s, %(description)s, %(specifications)s, %(type)s) returning * """, defaultpayload(api.payload)), 201
def create_app(): """ Creates application. :returns: flask application instance """ app = Flask(__name__) cfgfile = os.environ.get('API_LI3DS_SETTINGS') if cfgfile: app.config.update(load_yaml_config(cfgfile)) else: try: cfgfile = (Path(__file__).parent.parent / 'conf' / 'api_li3ds.yml').resolve() except FileNotFoundError: print(Path(__file__).parent.parent / 'conf' / 'api_li3ds.yml') app.logger.warning('no config file found !!') sys.exit(1) app.config.update(load_yaml_config(str(cfgfile))) # setting log level if app.config['DEBUG']: app.logger.setLevel(LOG_LEVELS['debug']) else: app.logger.setLevel(LOG_LEVELS['info']) app.logger.debug('loading config from {}'.format(cfgfile)) if 'HEADER_API_KEY' not in app.config: app.logger.fatal('HEADER_API_KEY missing') sys.exit(1) if not app.config['HEADER_API_KEY'] or len(app.config['HEADER_API_KEY']) < 12: app.logger.fatal('HEADER_API_KEY cannot be empty or ' 'too short (at least 12 characters)') sys.exit(1) # load extensions # be carefull to load apis before blueprint ! init_apis() api.init_app(app) Database.init_app(app) return app
def post(self): '''Create a transformation between referentials''' return Database.query_asdict( """ insert into li3ds.transfo (source, target, transfo_type, description, parameters, tdate, validity_start, validity_end) values (%(source)s, %(target)s, %(transfo_type)s, %(description)s, %(parameters)s, %(tdate)s, %(validity_start)s, %(validity_end)s) returning * """, defaultpayload(api.payload) ), 201
def post(self): '''Create a sensor''' return Database.query_asdict( """ insert into li3ds.sensor (name, serial_number, brand, model, description, specifications, type) values (%(name)s, %(serial_number)s, %(brand)s, %(model)s, %(description)s, %(specifications)s, %(type)s) returning * """, defaultpayload(api.payload) ), 201
def post(self): ''' Create a project. ''' if 'timezone' not in api.payload: api.payload.update(timezone=project_model_post['timezone'].default) return Database.query_asdict( "insert into li3ds.project (name, timezone, extent) " "values (%(name)s, %(timezone)s, ST_Transform(%(extent)s::geometry,4326)) " "returning *", defaultpayload(api.payload) ), 201
def transfo_tree(id): tftrees = Database.query_asdict( "select * from li3ds.transfo_tree where id=%s", (id,) ) if not tftrees: return None transfo_tree = tftrees[0] name = "cluster_transfotree_{}".format(id) url = url_for('transfotree', id=id, _external=True) label = "TransfoTree: {name} ({id})".format_map(transfo_tree) return transfo_trees(name, url, label, [id])
def get(self, id): '''Get all sensors used in a given platform configuration''' return Database.query_asjson(""" select distinct s.* from li3ds.platform_config pf join li3ds.transfo_tree tt on tt.id = ANY(pf.transfo_trees) , lateral unnest(tt.transfos) as tid join li3ds.transfo t on t.id = tid join li3ds.referential r on r.id = t.source or r.id = t.target join li3ds.sensor s on s.id = r.sensor where pf.id = %s """, (id,))
def post(self): '''Create a transformation between referentials''' payload = defaultpayload(api.payload) payload['parameters'] = Json(payload['parameters']) return Database.query_asdict( """ insert into li3ds.transfo (name, source, target, transfo_type, description, parameters, parameters_column, tdate, validity_start, validity_end) values (%(name)s, %(source)s, %(target)s, %(transfo_type)s, %(description)s, %(parameters)s, %(parameters_column)s, %(tdate)s, %(validity_start)s, %(validity_end)s) returning * """, payload ), 201
def platform_config(id): configs = Database.query_asdict(""" select p.name as pname, p.id as pid, c.transfo_trees, c.id, c.name from li3ds.platform_config c join li3ds.platform p on p.id = c.platform where c.id = %s """, (id, )) if not configs: return None config = configs[0] name = "cluster_config_{}".format(id) url = url_for('platform_config', id=id, _external=True) label = "Platform: {pname} ({pid})\\nConfiguration: {name} ({id})".format_map(config) return transfo_trees(name, url, label, config['transfo_trees'])
def get(self): '''Sensor type list''' return Database.query_aslist( '''select unnest(enum_range(enum_first(null::li3ds.sensor_type), null::li3ds.sensor_type))''' )
def get(self): '''List sensors''' return Database.query_asjson("select * from li3ds.sensor")
def delete(self, id): '''Delete a transformation given its identifier''' res = Database.rowcount("delete from li3ds.transfo_tree where id=%s", (id,)) if not res: nstft.abort(404, 'Transformation tree not found') return '', 410
def get(self): '''List all transformation types''' return Database.query_asjson("select * from li3ds.transfo_type")
def delete(self, id): '''Delete a datasource given its identifier''' res = Database.rowcount("delete from li3ds.posdatasource where id=%s", (id,)) if not res: nspds.abort(404, 'PosDatasource not found') return '', 410
def get(self): '''List all transformation trees''' return Database.query_asjson("select * from li3ds.transfo_tree")
def delete(self, id): '''Delete a referential given its identifier''' res = Database.rowcount("delete from li3ds.referential where id=%s", (id,)) if not res: nsrf.abort(404, 'referential not found') return '', 410
def get(self, id): '''Get the platform used by the given session''' return Database.query_asjson( """select p.* from li3ds.platform p join li3ds.session s on s.platform = p.id where s.id=%s """, (id, ))
def get(self, id): '''Get one session given its identifier''' return Database.query_asjson("select * from li3ds.session where id=%s", (id, ))
def post(self): '''Create a session''' return Database.query_asdict( "insert into li3ds.session (name, start_time, end_time, project, platform) " "values (%(name)s, %(start_time)s, %(end_time)s, %(project)s, %(platform)s) " "returning *", defaultpayload(api.payload)), 201
def get(self): '''Get all datasources''' return Database.query_asjson("select * from li3ds.posdatasource")
def delete(self, id): '''Delete a sensor given its identifier''' res = Database.rowcount("delete from li3ds.sensor where id=%s", (id,)) if not res: nssensor.abort(404, 'Sensor not found') return '', 410
def get(self): '''Sensor type list''' return Database.query_aslist( '''select unnest(enum_range(enum_first(null::li3ds.sensor_type), null::li3ds.sensor_type))''')
def get(self): '''Get all sessions''' return Database.query_asjson("select * from li3ds.session")