diff --git a/api/api.py b/api/api.py index 52d9a2f581bc2c2b597ea64e8f22bd357afbae13..b8b1a1d700b9ccca39330b7d67ce178e41aaa263 100644 --- a/api/api.py +++ b/api/api.py @@ -7,27 +7,28 @@ import traceback import webapp2 import webapp2_extras.routes -from . import base -from .jobs.handlers import JobsHandler, JobHandler, GearsHandler, GearHandler, RulesHandler from . import encoder from . import root from . import util from . import config -from . import centralclient -from . import download -from . import upload -from .handlers import listhandler -from .handlers import userhandler -from .handlers import grouphandler -from .handlers import containerhandler -from .handlers import collectionshandler -from .handlers import resolvehandler -from .handlers import searchhandler -from .handlers import schemahandler -from .handlers import reporthandler -from .handlers import devicehandler from .request import SciTranRequest +from .centralclient import CentralClient +from .download import Download +from .handlers.collectionshandler import CollectionsHandler +from .handlers.confighandler import Config, Version +from .handlers.containerhandler import ContainerHandler +from .handlers.devicehandler import DeviceHandler +from .handlers.grouphandler import GroupHandler +from .handlers.listhandler import AnalysesHandler, ListHandler, FileListHandler, NotesListHandler, PermissionsListHandler, TagsListHandler +from .handlers.reporthandler import ReportHandler +from .handlers.resolvehandler import ResolveHandler +from .handlers.schemahandler import SchemaHandler +from .handlers.searchhandler import SearchHandler +from .handlers.userhandler import UserHandler +from .jobs.handlers import JobsHandler, JobHandler, GearsHandler, GearHandler, RulesHandler +from .upload import Upload + log = config.log try: @@ -35,182 +36,237 @@ try: except ImportError: uwsgi = None -class Config(base.RequestHandler): +routing_regexes = { - def get(self): - """Return public Scitran configuration information.""" - return config.get_public_config() + # Group ID: 2-32 characters of form [0-9a-z.@_-]. Start and ends with alphanum. + 'gid': '[0-9a-z][0-9a-z.@_-]{0,30}[0-9a-z]', - def get_js(self): - """Return scitran config in javascript format.""" - self.response.write( - 'config = ' + - json.dumps( self.get(), sort_keys=True, indent=4, separators=(',', ': '), default=encoder.custom_json_serializer,) + - ';' - ) + # Container ID: 24-character hex + 'cid': '[0-9a-f]{24}', -class Version(base.RequestHandler): + # Site ID: <= 24-character alphanum + 'sid': '[0-9a-z_]{0,24}', - def get(self): - """Return database schema version""" - return config.get_version() + # User ID: any length, [0-9a-z.@_-] + 'uid': '[0-9a-z.@_-]*', -#regexes used in routing table: -routing_regexes = { - # group id regex - # length between 2 and 32 characters - # allowed characters are [0-9a-z.@_-] (start and ends only with [0-9a-z]) - 'group_id_re': '[0-9a-z][0-9a-z.@_-]{0,30}[0-9a-z]', - # container id regex - # hexadecimal string exactly of length 24 - 'cid_re': '[0-9a-f]{24}', - # site id regex - # length less than 24 characters - # allowed characters are [0-9a-z] - 'site_id_re': '[0-9a-z_]{0,24}', - # user id regex - # any length, allowed chars are [0-9a-z.@_-] - 'user_id_re': '[0-9a-z.@_-]*', - # container name regex - # possible values are projects, sessions, acquisitions or collections - 'cont_name_re': 'projects|sessions|acquisitions|collections', - # tag regex - # length between 3 and 24 characters - # any character allowed except '/'' - 'tag_re': '[^/]{1,32}', - # filename regex - # any character allowed except '/' - 'filename_re': '[^/]+', - # note id regex - # hexadecimal string exactly of length 24 - 'note_id_re': '[0-9a-f]{24}', - # schema regex - # example: schema_path/schema.json - 'schema_re': r'[^/.]{3,60}/[^/.]{3,60}\.json' + # Container name + 'cname': 'projects|sessions|acquisitions|collections', + + # Tag name + 'tag': '[^/]{1,32}', + + # Filename + 'fname': '[^/]+', + + # Note ID + 'nid': '[0-9a-f]{24}', + + # Schema path + 'schema': r'[^/.]{3,60}/[^/.]{3,60}\.json' } -def _format(route): - return route.format(**routing_regexes) - -routes = [ - webapp2.Route(r'/api', root.Root), - webapp2_extras.routes.PathPrefixRoute(r'/api', [ - webapp2.Route(r'/download', download.Download, handler_method='download', methods=['GET', 'POST'], name='download'), - webapp2.Route(r'/upload/<strategy:label|uid|uid-match>', upload.Upload, handler_method='upload', methods=['POST']), - webapp2.Route(r'/clean-packfiles', upload.Upload, handler_method='clean_packfile_tokens', methods=['POST']), - webapp2.Route(r'/engine', upload.Upload, handler_method='engine', methods=['POST']), - webapp2.Route(r'/sites', centralclient.CentralClient, handler_method='sites', methods=['GET']), - webapp2.Route(r'/register', centralclient.CentralClient, handler_method='register', methods=['POST']), - webapp2.Route(r'/resolve', resolvehandler.ResolveHandler, handler_method='resolve', methods=['POST']), - webapp2.Route(r'/config', Config, methods=['GET']), - webapp2.Route(r'/config.js', Config, handler_method='get_js', methods=['GET']), - webapp2.Route(r'/version', Version, methods=['GET']), - ]), - webapp2.Route(r'/api/users', userhandler.UserHandler, handler_method='get_all', methods=['GET']), - webapp2.Route(r'/api/users', userhandler.UserHandler, methods=['POST']), - webapp2_extras.routes.PathPrefixRoute(r'/api/users', [ - webapp2.Route(r'/self', userhandler.UserHandler, handler_method='self', methods=['GET']), - webapp2.Route(r'/self/avatar', userhandler.UserHandler, handler_method='self_avatar', methods=['GET']), - webapp2.Route(r'/self/key', userhandler.UserHandler, handler_method='generate_api_key',methods=['POST']), - webapp2.Route(_format(r'/<_id:{user_id_re}>'), userhandler.UserHandler, name='user'), - webapp2.Route(_format(r'/<uid:{user_id_re}>/groups'), grouphandler.GroupHandler, handler_method='get_all', methods=['GET'], name='groups'), - webapp2.Route(_format(r'/<uid:{user_id_re}>/avatar'), userhandler.UserHandler, handler_method='avatar', methods=['GET'], name='avatar'), - ]), - webapp2.Route(r'/api/devices', devicehandler.DeviceHandler, name='device_list', handler_method='get_all', methods=['GET']), - webapp2.Route(r'/api/devices', devicehandler.DeviceHandler, methods=['POST']), - webapp2_extras.routes.PathPrefixRoute(r'/api/devices', [ - webapp2.Route(r'/status', devicehandler.DeviceHandler, handler_method='get_status', methods=['GET']), - webapp2.Route(r'/self', devicehandler.DeviceHandler, handler_method='get_self', methods=['GET']), - webapp2.Route(_format(r'/<device_id:[^/]+>'), devicehandler.DeviceHandler, name='device_details', methods=['GET']), - ]), - webapp2.Route(r'/api/jobs', JobsHandler), - webapp2_extras.routes.PathPrefixRoute(r'/api/jobs', [ - webapp2.Route(r'/next', JobsHandler, handler_method='next', methods=['GET']), - webapp2.Route(r'/stats', JobsHandler, handler_method='stats', methods=['GET']), - webapp2.Route(r'/reap', JobsHandler, handler_method='reap_stale', methods=['POST']), - webapp2.Route(r'/add', JobsHandler, handler_method='add', methods=['POST']), - webapp2.Route(r'/<:[^/]+>', JobHandler, name='job'), - webapp2.Route(r'/<:[^/]+>/config.json', JobHandler, name='job', handler_method='get_config'), - webapp2.Route(r'/<:[^/]+>/retry', JobHandler, name='job', handler_method='retry', methods=['POST']), - ]), - webapp2.Route(r'/api/gears', GearsHandler), - webapp2_extras.routes.PathPrefixRoute(r'/api/gears', [ - webapp2.Route(r'/<:[^/]+>', GearHandler), - webapp2.Route(r'/<:[^/]+>/invocation', GearHandler, handler_method='get_invocation'), - webapp2.Route(r'/<:[^/]+>/suggest/<:[^/]+>/<:[^/]+>', GearHandler, handler_method='suggest'), +def route(path, target, h=None, m=None, name=None): + + # https://webapp2.readthedocs.io/en/latest/api/webapp2.html#webapp2.Route + return webapp2.Route( + # re.compile(path) + path.format(**routing_regexes), + target, + handler_method=h, + methods=m, + name=name + ) + +def prefix(path, routes): + + # https://webapp2.readthedocs.io/en/latest/api/webapp2_extras/routes.html#webapp2_extras.routes.PathPrefixRoute + return webapp2_extras.routes.PathPrefixRoute( + path.format(**routing_regexes), + routes + ) + +endpoints = [ + route('/api', root.Root), + prefix('/api', [ + + # System configuration + + route('/config', Config, m=['GET']), + route('/config.js', Config, h='get_js', m=['GET']), + route('/version', Version, m=['GET']), + + + # General-purpose upload & download + + route('/download', Download, h='download', m=['GET', 'POST']), + route('/upload/<strategy:label|uid|uid-match>', Upload, h='upload', m=['POST']), + route('/clean-packfiles', Upload, h='clean_packfile_tokens', m=['POST']), + route('/engine', Upload, h='engine', m=['POST']), + + + # Top-level endpoints + + route('/resolve', ResolveHandler, h='resolve', m=['POST']), + route('/schemas/<schema:{schema}>', SchemaHandler, m=['GET']), + route('/report/<report_type:site|project>', ReportHandler, m=['GET']), + + + # Search + + route('/search', SearchHandler, h='advanced_search', m=['POST']), + route('/search/files', SearchHandler, h='get_datatree', m=['GET']), + route('/search/<cont_name:{cname}>', SearchHandler, m=['GET']), + + + # Users + + route( '/users', UserHandler, 'get_all', m=['GET']), + route( '/users', UserHandler, m=['POST']), + prefix('/users', [ + route('/self', UserHandler, h='self', m=['GET']), + route('/self/avatar', UserHandler, h='self_avatar', m=['GET']), + route('/self/key', UserHandler, h='generate_api_key',m=['POST']), + + route('/<_id:{uid}>', UserHandler), + route('/<uid:{uid}>/groups', GroupHandler, h='get_all', m=['GET']), + route('/<uid:{uid}>/avatar', UserHandler, h='avatar', m=['GET']), + route('/<uid:{uid}>/<cont_name:{cname}>', ContainerHandler, h='get_all_for_user', m=['GET']), + + ]), + + + # Jobs & gears + + route( '/jobs', JobsHandler), + prefix('/jobs', [ + route('/next', JobsHandler, h='next', m=['GET']), + route('/stats', JobsHandler, h='stats', m=['GET']), + route('/reap', JobsHandler, h='reap_stale', m=['POST']), + route('/add', JobsHandler, h='add', m=['POST']), + route('/<:[^/]+>', JobHandler), + route('/<:[^/]+>/config.json', JobHandler, h='get_config'), + route('/<:[^/]+>/retry', JobHandler, h='retry', m=['POST']), + ]), + + route('/gears', GearsHandler), + prefix('/gears', [ + route('/<:[^/]+>', GearHandler), + route('/<:[^/]+>/invocation', GearHandler, h='get_invocation'), + route('/<:[^/]+>/suggest/<:[^/]+>/<:[^/]+>', GearHandler, h='suggest'), + ]), + + route('/rules', RulesHandler), + + + # Devices + + route( '/devices', DeviceHandler, h='get_all', m=['GET']), + route( '/devices', DeviceHandler, m=['POST']), + prefix('/devices', [ + route('/status', DeviceHandler, h='get_status', m=['GET']), + route('/self', DeviceHandler, h='get_self', m=['GET']), + route('/<device_id:[^/]+>', DeviceHandler, m=['GET']), + ]), + + + # Groups + + route('/groups', GroupHandler, h='get_all', m=['GET']), + route('/groups', GroupHandler, m=['POST']), + route('/groups/<_id:{gid}>', GroupHandler, m=['GET', 'DELETE', 'PUT']), + + prefix('/<cont_name:groups>', [ + route('/<cid:{gid}>/<list_name:roles>', ListHandler, m=['POST']), + route('/<cid:{gid}>/<list_name:roles>/<site:{sid}>/<_id:{uid}>', ListHandler, m=['GET', 'PUT', 'DELETE']), + + route('/<cid:{gid}>/<list_name:tags>', TagsListHandler, m=['POST']), + route('/<cid:{gid}>/<list_name:tags>/<value:{tag}>', TagsListHandler, m=['GET', 'PUT', 'DELETE']), + ]), + + + # Projects + + prefix('/projects', [ + route('/groups', ContainerHandler, h='get_groups_with_project', m=['GET']), + route('/recalc', ContainerHandler, h='calculate_project_compliance', m=['POST']), + route('/<cid:{cid}>/template', ContainerHandler, h='set_project_template', m=['POST']), + route('/<cid:{cid}>/template', ContainerHandler, h='delete_project_template', m=['DELETE']), + route('/<cid:{cid}>/recalc', ContainerHandler, h='calculate_project_compliance', m=['POST']), + ]), + + + # Sessions + + route('/sessions/<cid:{cid}>/jobs', ContainerHandler, h='get_jobs', m=['GET']), + + + # Collections + + route( '/collections', CollectionsHandler, h='get_all', m=['GET']), + route( '/collections', CollectionsHandler, m=['POST']), + prefix('/collections', [ + route('/curators', CollectionsHandler, h='curators', m=['GET']), + route('/<cid:{cid}>', CollectionsHandler, m=['GET', 'PUT', 'DELETE']), + route('/<cid:{cid}>/sessions', CollectionsHandler, h='get_sessions', m=['GET']), + route('/<cid:{cid}>/acquisitions', CollectionsHandler, h='get_acquisitions', m=['GET']), + ]), + + + # Collections / Projects + + prefix('/<cont_name:collections|projects>', [ + prefix('/<cid:{cid}>', [ + route('/<list_name:permissions>', PermissionsListHandler, m=['POST']), + route('/<list_name:permissions>/<site:{sid}>/<_id:{uid}>', PermissionsListHandler, m=['GET', 'PUT', 'DELETE']), + ]), + ]), + + + # Containers + + route('/<cont_name:{cname}>', ContainerHandler, name='cont_list', h='get_all', m=['GET']), + route('/<cont_name:{cname}>', ContainerHandler, m=['POST']), + + prefix('/<cont_name:{cname}>', [ + route('/<cid:{cid}>', ContainerHandler, m=['GET','PUT','DELETE']), + + prefix('/<cid:{cid}>', [ + + route('/<list_name:tags>', TagsListHandler, m=['POST']), + route('/<list_name:tags>/<value:{tag}>', TagsListHandler, m=['GET', 'PUT', 'DELETE']), + + route('/packfile-start', FileListHandler, h='packfile_start', m=['POST']), + route('/packfile', FileListHandler, h='packfile', m=['POST']), + route('/packfile-end', FileListHandler, h='packfile_end'), + route('/<list_name:files>', FileListHandler, m=['POST']), + route('/<list_name:files>/<name:{fname}>', FileListHandler, m=['GET', 'DELETE']), + + + route('/<list_name:analyses>', AnalysesHandler, m=['POST']), + # Could be in a prefix. Had weird syntax highlighting issues so leaving for another day + route('/<list_name:analyses>/<_id:{cid}>', AnalysesHandler, m=['GET', 'DELETE']), + route('/<list_name:analyses>/<_id:{cid}>/files', AnalysesHandler, h='download', m=['GET']), + route('/<list_name:analyses>/<_id:{cid}>/files/<name:{fname}>', AnalysesHandler, h='download', m=['GET']), + route('/<list_name:analyses>/<_id:{cid}>/notes', AnalysesHandler, h='add_note', m=['POST']), + route('/<list_name:analyses>/<_id:{cid}>/notes/<note_id:{cid}>', AnalysesHandler, h='delete_note', m=['DELETE']), + route('/<list_name:notes>', NotesListHandler, m=['POST']), + route('/<list_name:notes>/<_id:{nid}>', NotesListHandler, name='notes', m=['GET', 'PUT', 'DELETE']), + ]) + ]), + + + # Misc (to be cleaned up later) + + route('/<par_cont_name:groups>/<par_id:{gid}>/<cont_name:projects>', ContainerHandler, h='get_all', m=['GET']), + route('/<par_cont_name:{cname}>/<par_id:{cid}>/<cont_name:{cname}>', ContainerHandler, h='get_all', m=['GET']), + + + # Multi - site + route('/sites', CentralClient, h='sites', m=['GET']), + route('/register', CentralClient, h='register', m=['POST']), + ]), - webapp2.Route(r'/api/rules', RulesHandler), - webapp2.Route(r'/api/groups', grouphandler.GroupHandler, handler_method='get_all', methods=['GET']), - webapp2.Route(r'/api/groups', grouphandler.GroupHandler, methods=['POST']), - webapp2.Route(_format(r'/api/groups/<_id:{group_id_re}>'), grouphandler.GroupHandler, name='group_details', methods=['GET', 'DELETE', 'PUT']), - - webapp2.Route(r'/api/collections/curators', collectionshandler.CollectionsHandler, handler_method='curators', methods=['GET']), - webapp2.Route(r'/api/collections', collectionshandler.CollectionsHandler, name='colls', handler_method='get_all', methods=['GET']), - webapp2.Route(r'/api/collections', collectionshandler.CollectionsHandler, methods=['POST']), - - webapp2.Route(_format(r'/api/collections/<cid:{cid_re}>'), collectionshandler.CollectionsHandler, name='coll_details', methods=['GET', 'PUT', 'DELETE']), - webapp2.Route(_format(r'/api/collections/<cid:{cid_re}>/sessions'), collectionshandler.CollectionsHandler, name='coll_ses', handler_method='get_sessions', methods=['GET']), - webapp2.Route(_format(r'/api/collections/<cid:{cid_re}>/acquisitions'), collectionshandler.CollectionsHandler, name='coll_acq', handler_method='get_acquisitions', methods=['GET']), - - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>'), containerhandler.ContainerHandler, name='cont_list', handler_method='get_all', methods=['GET']), - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>'), containerhandler.ContainerHandler, methods=['POST']), - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>'), containerhandler.ContainerHandler, name='cont_details', methods=['GET','PUT','DELETE']), - webapp2.Route(_format(r'/api/sessions/<cid:{cid_re}>/jobs'), containerhandler.ContainerHandler, name='cont_jobs', handler_method='get_jobs', methods=['GET']), - - webapp2.Route(_format(r'/api/<cont_name:groups>/<cid:{group_id_re}>/<list_name:roles>'), listhandler.ListHandler, name='group_roles_post', methods=['POST']), - webapp2.Route(_format(r'/api/<cont_name:groups>/<cid:{group_id_re}>/<list_name:roles>/<site:{site_id_re}>/<_id:{user_id_re}>'), listhandler.ListHandler, name='group_roles', methods=['GET', 'PUT', 'DELETE']), - - - webapp2.Route(_format(r'/api/<cont_name:groups>/<cid:{group_id_re}>/<list_name:tags>'), listhandler.TagsListHandler, methods=['POST'], name='tags_post'), - webapp2.Route(_format(r'/api/<cont_name:groups>/<cid:{group_id_re}>/<list_name:tags>/<value:{tag_re}>'), listhandler.TagsListHandler, name='tags', methods=['GET', 'PUT', 'DELETE']), - - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:tags>'), listhandler.TagsListHandler, methods=['POST'], name='tags_post'), - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:tags>/<value:{tag_re}>'), listhandler.TagsListHandler, name='tags', methods=['GET', 'PUT', 'DELETE']), - - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/packfile-start'), listhandler.FileListHandler, name='packfile-start', handler_method='packfile_start', methods=['POST']), - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/packfile'), listhandler.FileListHandler, name='packfile', handler_method='packfile', methods=['POST']), - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/packfile-end'), listhandler.FileListHandler, name='packfile-end', handler_method='packfile_end'), - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:files>'), listhandler.FileListHandler, name='files_post', methods=['POST']), - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:files>/<name:{filename_re}>'), listhandler.FileListHandler, name='files', methods=['GET', 'DELETE']), - - webapp2.Route(_format(r'/api/<cont_name:collections|projects>/<cid:{cid_re}>/<list_name:permissions>'), listhandler.PermissionsListHandler, name='perms_post', methods=['POST']), - webapp2.Route(_format(r'/api/<cont_name:collections|projects>/<cid:{cid_re}>/<list_name:permissions>/<site:{site_id_re}>/<_id:{user_id_re}>'), listhandler.PermissionsListHandler, name='perms', methods=['GET', 'PUT', 'DELETE']), - - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:notes>'), listhandler.NotesListHandler, name='notes_post', methods=['POST']), - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:notes>/<_id:{note_id_re}>'), listhandler.NotesListHandler, name='notes', methods=['GET', 'PUT', 'DELETE']), - - webapp2.Route(_format(r'/api/users/<uid:{user_id_re}>/<cont_name:{cont_name_re}>'), containerhandler.ContainerHandler, name='user_conts', handler_method='get_all_for_user', methods=['GET']), - - webapp2.Route(r'/api/projects/groups', containerhandler.ContainerHandler, handler_method='get_groups_with_project', methods=['GET']), - webapp2.Route(r'/api/projects/recalc', containerhandler.ContainerHandler, handler_method='calculate_project_compliance', methods=['POST']), - webapp2.Route(_format(r'/api/projects/<cid:{cid_re}>/template'), containerhandler.ContainerHandler, handler_method='set_project_template', methods=['POST']), - webapp2.Route(_format(r'/api/projects/<cid:{cid_re}>/template'), containerhandler.ContainerHandler, handler_method='delete_project_template', methods=['DELETE']), - webapp2.Route(_format(r'/api/projects/<cid:{cid_re}>/recalc'), containerhandler.ContainerHandler, handler_method='calculate_project_compliance', methods=['POST']), - - webapp2.Route(_format(r'/api/<par_cont_name:groups>/<par_id:{group_id_re}>/<cont_name:projects>'), containerhandler.ContainerHandler, name='cont_sublist_groups', handler_method='get_all', methods=['GET']), - webapp2.Route(_format(r'/api/<par_cont_name:{cont_name_re}>/<par_id:{cid_re}>/<cont_name:{cont_name_re}>'), containerhandler.ContainerHandler, name='cont_sublist', handler_method='get_all', methods=['GET']), - webapp2.Route(_format(r'/api/search'), searchhandler.SearchHandler, handler_method='advanced_search', name='es_proxy', methods=['POST']), - webapp2.Route(_format(r'/api/search/files'), searchhandler.SearchHandler, handler_method='get_datatree', name='es_data', methods=['GET']), - webapp2.Route(_format(r'/api/search/<cont_name:{cont_name_re}>'), searchhandler.SearchHandler, name='es_proxy', methods=['GET']), - webapp2.Route(_format(r'/api/schemas/<schema:{schema_re}>'), schemahandler.SchemaHandler, name='schemas', methods=['GET']), - webapp2.Route(r'/api/report/<report_type:site|project>', reporthandler.ReportHandler, methods=['GET']), - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:analyses>'), - listhandler.AnalysesHandler, name='analysis_post', methods=['POST']), - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:analyses>/<_id:{cid_re}>'), - listhandler.AnalysesHandler, name='analysis', - methods=['GET', 'DELETE']), - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:analyses>/<_id:{cid_re}>/files'), - listhandler.AnalysesHandler, handler_method='download', - methods=['GET'], name='analysis_files'), - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:analyses>/<_id:{cid_re}>/files/<name:{filename_re}>'), - listhandler.AnalysesHandler, handler_method='download', - methods=['GET'], name='analysis_single_file'), - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:analyses>/<_id:{cid_re}>/notes'), - listhandler.AnalysesHandler, handler_method='add_note', - methods=['POST'], name='analysis_add_note'), - webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:analyses>/<_id:{cid_re}>/notes/<note_id:{cid_re}>'), - listhandler.AnalysesHandler, handler_method='delete_note', - methods=['DELETE'], name='analysis_delete_note'), ] @@ -240,7 +296,7 @@ def app_factory(*_, **__): # pylint: disable=protected-access,unused-argument # don't use config.get_item() as we don't want to require the database at startup - application = webapp2.WSGIApplication(routes, debug=config.__config['core']['debug']) + application = webapp2.WSGIApplication(endpoints, debug=config.__config['core']['debug']) application.router.set_dispatcher(dispatcher) application.request_class = SciTranRequest if os.environ.get("SCITRAN_RUNTIME_COVERAGE") == "true": diff --git a/api/handlers/confighandler.py b/api/handlers/confighandler.py new file mode 100644 index 0000000000000000000000000000000000000000..ef4312fe25c29b88b21e8fa402306d9f533dc98f --- /dev/null +++ b/api/handlers/confighandler.py @@ -0,0 +1,25 @@ +import json + +from .. import encoder +from .. import base +from .. import config + +class Config(base.RequestHandler): + + def get(self): + """Return public Scitran configuration information.""" + return config.get_public_config() + + def get_js(self): + """Return scitran config in javascript format.""" + self.response.write( + 'config = ' + + json.dumps( self.get(), sort_keys=True, indent=4, separators=(',', ': '), default=encoder.custom_json_serializer,) + + ';' + ) + +class Version(base.RequestHandler): + + def get(self): + """Return database schema version""" + return config.get_version()