diff --git a/collections_.py b/collections_.py new file mode 100644 index 0000000000000000000000000000000000000000..8bfb6c9eb105212892a33681faaa1af1c702768e --- /dev/null +++ b/collections_.py @@ -0,0 +1,273 @@ +# @author: Gunnar Schaefer + +import re +import json +import webapp2 +import bson.json_util + +import nimsapiutil + +# curator (later: multiple curators and authorizers) +# name +# permissions +# epochs point to collections + +# /collections +# /collections/<cid>/sessions +# /collections/<cid>/epochs?session=<sid> +# /collections/<cid>/sessions/<sid>/epochs + +class Collections(nimsapiutil.NIMSRequestHandler): + + """/collections """ + + json_schema = { + '$schema': 'http://json-schema.org/draft-04/schema#', + 'title': 'Collection List', + 'type': 'array', + 'items': { + 'title': 'Collection', + 'type': 'object', + 'properties': { + '_id': { + 'title': 'Database ID', + }, + 'site': { + 'title': 'Site', + 'type': 'string', + }, + 'group': { + 'title': 'Group', + 'type': 'string', + }, + 'name': { + 'title': 'Name', + 'type': 'string', + }, + 'timestamp': { + 'title': 'Timestamp', + }, + 'permissions': { + 'title': 'Permissions', + 'type': 'object', + }, + } + } + } + + def count(self): + """Return the number of Collections.""" + self.response.write(json.dumps(self.app.db.collections.count())) + + def post(self): + """Create a new Collection.""" + self.response.write('collections post\n') + + def get(self): + """Return the list of Collections.""" + query = {'permissions.' + self.userid: {'$exists': 'true'}} if not self.user_is_superuser else None + projection = ['curator', 'name', 'permissions.'+self.userid] + collections = list(self.app.db.collections.find(query, projection)) + #session_aggregates = self.app.db.sessions.aggregate([ + # {'$match': {'collection': {'$in': [col['_id'] for col in collections]}}}, + # {'$group': {'_id': '$collection', 'timestamp': {'$max': '$timestamp'}}}, + # ])['result'] + #timestamps = {sa['_id']: sa['timestamp'] for sa in session_aggregates} + #for col in collections: + # col['timestamp'] = timestamps[col['_id']] + self.response.write(json.dumps(collections, default=bson.json_util.default)) + + def put(self): + """Update many Collections.""" + self.response.write('collections put\n') + + +class Collection(nimsapiutil.NIMSRequestHandler): + + """/collections/<cid> """ + + json_schema = { + '$schema': 'http://json-schema.org/draft-04/schema#', + 'title': 'Collection', + 'type': 'object', + 'properties': { + '_id': { + 'title': 'Database ID', + }, + 'site': { + 'title': 'Site', + 'type': 'string', + }, + 'group': { + 'title': 'Group', + 'type': 'string', + }, + 'name': { + 'title': 'Name', + 'type': 'string', + 'maxLength': 32, + }, + 'timestamp': { + 'title': 'Timestamp', + }, + 'permissions': { + 'title': 'Permissions', + 'type': 'object', + 'minProperties': 1, + }, + 'files': { + 'title': 'Files', + 'type': 'array', + 'items': nimsapiutil.NIMSRequestHandler.file_schema, + 'uniqueItems': True, + }, + }, + 'required': ['_id', 'group', 'name'], #FIXME + } + + def get(self, cid): + """Return one Collection, conditionally with details.""" + collection = self.app.db.collections.find_one({'_id': bson.objectid.ObjectId(cid)}) + if not collection: + self.abort(404) + collection['timestamp'] = self.app.db.sessions.aggregate([ + {'$match': {'collection': bson.objectid.ObjectId(cid)}}, + {'$group': {'_id': '$collection', 'timestamp': {'$max': '$timestamp'}}}, + ])['result'][0]['timestamp'] + if not self.user_is_superuser: + if self.userid not in collection['permissions']: + self.abort(403) + if collection['permissions'][self.userid] != 'admin' and collection['permissions'][self.userid] != 'pi': + collection['permissions'] = {self.userid: collection['permissions'][self.userid]} + self.response.write(json.dumps(collection, default=bson.json_util.default)) + + def put(self, cid): + """Update an existing Collection.""" + self.response.write('collection %s put, %s\n' % (exp_id, self.request.params)) + + def delete(self, cid): + """Delete an Collection.""" + self.response.write('collection %s delete, %s\n' % (exp_id, self.request.params)) + + +class Sessions(nimsapiutil.NIMSRequestHandler): + + """/collections/<cid>/sessions """ + + json_schema = { + '$schema': 'http://json-schema.org/draft-04/schema#', + 'title': 'Session List', + 'type': 'array', + 'items': { + 'title': 'Session', + 'type': 'object', + 'properties': { + '_id': { + 'title': 'Database ID', + }, + 'name': { + 'title': 'Session', + 'type': 'string', + }, + 'subject': { + 'title': 'Subject', + 'type': 'string', + }, + 'site': { + 'title': 'Site', + 'type': 'string', + }, + } + } + } + + def count(self): + """Return the number of Sessions.""" + self.response.write(json.dumps(self.app.db.sessions.count())) + + def post(self): + """Create a new Session""" + self.response.write('sessions post\n') + + def get(self, cid): + """Return the list of Session Epochs.""" + collection = self.app.db.collections.find_one({'_id': bson.objectid.ObjectId(cid)}) + if not collection: + self.abort(404) + if not self.user_is_superuser and self.userid not in collection['permissions']: + self.abort(403) + aggregated_epochs = self.app.db.epochs.aggregate([ + {'$match': {'collections': bson.objectid.ObjectId(cid)}}, + {'$group': {'_id': '$session'}}, + ])['result'] + query = {'_id': {'$in': [agg_epoch['_id'] for agg_epoch in aggregated_epochs]}} + projection = ['name', 'subject'] + sessions = list(self.app.db.sessions.find(query, projection)) + for sess in sessions: + sess['site'] = self.app.config['site_id'] + self.response.write(json.dumps(sessions, default=bson.json_util.default)) + + def put(self): + """Update many Sessions.""" + self.response.write('sessions put\n') + + +class Epochs(nimsapiutil.NIMSRequestHandler): + + """/collections/<cid>/epochs """ + + json_schema = { + '$schema': 'http://json-schema.org/draft-04/schema#', + 'title': 'Epoch List', + 'type': 'array', + 'items': { + 'title': 'Epoch', + 'type': 'object', + 'properties': { + '_id': { + 'title': 'Database ID', + }, + 'name': { + 'title': 'Epoch', + 'type': 'string', + }, + 'description': { + 'title': 'Description', + 'type': 'string', + }, + 'datatype': { + 'title': 'Datatype', + 'type': 'string', + }, + } + } + } + + def count(self): + """Return the number of Epochs.""" + self.response.write(json.dumps(self.app.db.epochs.count())) + + def post(self): + """Create a new Epoch.""" + self.response.write('epochs post\n') + + def get(self, cid): + """Return the list of Session Epochs.""" + collection = self.app.db.collections.find_one({'_id': bson.objectid.ObjectId(cid)}) + if not collection: + self.abort(404) + if not self.user_is_superuser and self.userid not in collection['permissions']: + self.abort(403) + query = {'collections': bson.objectid.ObjectId(cid)} + sid = self.request.get('session') + if re.match(r'^[0-9a-f]{24}$', sid): + query['session'] = bson.objectid.ObjectId(sid) + elif sid != '': + self.abort(400) + projection = ['name', 'description', 'datatype'] + epochs = list(self.app.db.epochs.find(query, projection)) + self.response.write(json.dumps(epochs, default=bson.json_util.default)) + + def put(self): + """Update many Epochs.""" + self.response.write('epochs put\n') diff --git a/epochs.py b/epochs.py deleted file mode 100644 index fb62300dda39543e851497b755c6690b14ade99b..0000000000000000000000000000000000000000 --- a/epochs.py +++ /dev/null @@ -1,133 +0,0 @@ -# @author: Gunnar Schaefer - -import json -import webapp2 -import bson.json_util - -import nimsdata -import nimsapiutil - - -class Epochs(nimsapiutil.NIMSRequestHandler): - - """/nimsapi/epochs """ - - json_schema = { - '$schema': 'http://json-schema.org/draft-04/schema#', - 'title': 'Epoch List', - 'type': 'array', - 'items': { - 'title': 'Epoch', - 'type': 'object', - 'properties': { - '_id': { - 'title': 'Database ID', - }, - 'timestamp': { - 'title': 'Timestamp', - }, - 'datatype': { - 'title': 'Datatype', - 'type': 'string', - }, - 'series': { - 'title': 'Series', - 'type': 'integer', - }, - 'acquisition': { - 'title': 'Acquisition', - 'type': 'integer', - }, - 'description': { - 'title': 'Description', - 'type': 'string', - }, - } - } - } - - def count(self): - """Return the number of Epochs.""" - self.response.write(json.dumps(self.app.db.epochs.count())) - - def post(self): - """Create a new Epoch.""" - self.response.write('epochs post\n') - - def get(self, sid): - """Return the list of Session Epochs.""" - session = self.app.db.sessions.find_one({'_id': bson.objectid.ObjectId(sid)}) - if not session: - self.abort(404) - experiment = self.app.db.experiments.find_one({'_id': bson.objectid.ObjectId(session['experiment'])}) - if not experiment: - self.abort(500) - if not self.user_is_superuser and self.userid not in experiment['permissions']: - self.abort(403) - query = {'session': bson.objectid.ObjectId(sid)} - projection = ['timestamp', 'series', 'acquisition', 'description', 'datatype'] - epochs = list(self.app.db.epochs.find(query, projection)) - self.response.write(json.dumps(epochs, default=bson.json_util.default)) - - def put(self): - """Update many Epochs.""" - self.response.write('epochs put\n') - - -class Epoch(nimsapiutil.NIMSRequestHandler): - - """/nimsapi/epochs/<eid> """ - - json_schema = { - '$schema': 'http://json-schema.org/draft-04/schema#', - 'title': 'Epoch', - 'type': 'object', - 'properties': { - '_id': { - 'title': 'Database ID', - }, - 'uid': { - 'title': 'UID', - 'type': 'string', - }, - 'session': { - 'title': 'Session ID', - }, - 'files': { - 'title': 'Files', - 'type': 'array', - 'items': nimsapiutil.NIMSRequestHandler.file_schema, - 'uniqueItems': True, - }, - }, - 'required': ['_id'], - } - - def schema(self, *args, **kwargs): - import copy - json_schema = copy.deepcopy(self.json_schema) - json_schema['properties'].update(nimsdata.nimsdicom.NIMSDicom.epoch_properties) - self.response.write(json.dumps(json_schema, default=bson.json_util.default)) - - def get(self, eid): - """Return one Epoch, conditionally with details.""" - epoch = self.app.db.epochs.find_one({'_id': bson.objectid.ObjectId(eid)}) - if not epoch: - self.abort(404) - session = self.app.db.sessions.find_one({'_id': epoch['session']}) - if not session: - self.abort(500) - experiment = self.app.db.experiments.find_one({'_id': bson.objectid.ObjectId(session['experiment'])}) - if not experiment: - self.abort(500) - if not self.user_is_superuser and self.userid not in experiment['permissions']: - self.abort(403) - self.response.write(json.dumps(epoch, default=bson.json_util.default)) - - def put(self, eid): - """Update an existing Epoch.""" - self.response.write('epoch %s put, %s\n' % (epoch_id, self.request.params)) - - def delete(self, eid): - """Delete an Epoch.""" - self.response.write('epoch %s delete, %s\n' % (epoch_id, self.request.params)) diff --git a/experiments.py b/experiments.py index cb3a7fd1fca1f9e6fc05aad7325e3e55969ba116..1a88fb1d5a18f67e24c007eac825bb0963568804 100644 --- a/experiments.py +++ b/experiments.py @@ -4,6 +4,7 @@ import json import webapp2 import bson.json_util +#import nimsdata import nimsapiutil @@ -22,8 +23,9 @@ class Experiments(nimsapiutil.NIMSRequestHandler): '_id': { 'title': 'Database ID', }, - 'timestamp': { - 'title': 'Timestamp', + 'site': { + 'title': 'Site', + 'type': 'string', }, 'group': { 'title': 'Group', @@ -33,6 +35,9 @@ class Experiments(nimsapiutil.NIMSRequestHandler): 'title': 'Name', 'type': 'string', }, + 'timestamp': { + 'title': 'Timestamp', + }, 'permissions': { 'title': 'Permissions', 'type': 'object', @@ -54,13 +59,14 @@ class Experiments(nimsapiutil.NIMSRequestHandler): query = {'permissions.' + self.userid: {'$exists': 'true'}} if not self.user_is_superuser else None projection = ['group', 'name', 'permissions.'+self.userid] experiments = list(self.app.db.experiments.find(query, projection)) - session_aggregates = self.app.db.sessions.aggregate([ + aggregated_sessions = self.app.db.sessions.aggregate([ {'$match': {'experiment': {'$in': [exp['_id'] for exp in experiments]}}}, {'$group': {'_id': '$experiment', 'timestamp': {'$max': '$timestamp'}}}, ])['result'] - timestamps = {sa['_id']: sa['timestamp'] for sa in session_aggregates} + timestamps = {agg_sess['_id']: agg_sess['timestamp'] for agg_sess in aggregated_sessions} for exp in experiments: exp['timestamp'] = timestamps[exp['_id']] + exp['site'] = self.app.config['site_id'] self.response.write(json.dumps(experiments, default=bson.json_util.default)) def put(self): @@ -80,8 +86,9 @@ class Experiment(nimsapiutil.NIMSRequestHandler): '_id': { 'title': 'Database ID', }, - 'timestamp': { - 'title': 'Timestamp', + 'site': { + 'title': 'Site', + 'type': 'string', }, 'group': { 'title': 'Group', @@ -92,6 +99,9 @@ class Experiment(nimsapiutil.NIMSRequestHandler): 'type': 'string', 'maxLength': 32, }, + 'timestamp': { + 'title': 'Timestamp', + }, 'permissions': { 'title': 'Permissions', 'type': 'object', @@ -104,7 +114,7 @@ class Experiment(nimsapiutil.NIMSRequestHandler): 'uniqueItems': True, }, }, - 'required': ['_id', 'group', 'name'], + 'required': ['_id', 'group', 'name'], #FIXME } def get(self, xid): @@ -130,3 +140,246 @@ class Experiment(nimsapiutil.NIMSRequestHandler): def delete(self, xid): """Delete an Experiment.""" self.response.write('experiment %s delete, %s\n' % (exp_id, self.request.params)) + + +class Sessions(nimsapiutil.NIMSRequestHandler): + + """/sessions """ + + json_schema = { + '$schema': 'http://json-schema.org/draft-04/schema#', + 'title': 'Session List', + 'type': 'array', + 'items': { + 'title': 'Session', + 'type': 'object', + 'properties': { + '_id': { + 'title': 'Database ID', + }, + 'name': { + 'title': 'Session', + 'type': 'string', + }, + 'subject': { + 'title': 'Subject', + 'type': 'string', + }, + 'site': { + 'title': 'Site', + 'type': 'string', + }, + } + } + } + + def count(self): + """Return the number of Sessions.""" + self.response.write(json.dumps(self.app.db.sessions.count())) + + def post(self): + """Create a new Session""" + self.response.write('sessions post\n') + + def get(self, xid): + """Return the list of Experiment Sessions.""" + experiment = self.app.db.experiments.find_one({'_id': bson.objectid.ObjectId(xid)}) + if not experiment: + self.abort(404) + if not self.user_is_superuser and self.userid not in experiment['permissions']: + self.abort(403) + query = {'experiment': bson.objectid.ObjectId(xid)} + projection = ['name', 'subject'] + sessions = list(self.app.db.sessions.find(query, projection)) + self.response.write(json.dumps(sessions, default=bson.json_util.default)) + + def put(self): + """Update many Sessions.""" + self.response.write('sessions put\n') + + +class Session(nimsapiutil.NIMSRequestHandler): + + """/sessions/<sid> """ + + json_schema = { + '$schema': 'http://json-schema.org/draft-04/schema#', + 'title': 'Session', + 'type': 'object', + 'properties': { + '_id': { + 'title': 'Database ID', + }, + 'uid': { + 'title': 'UID', + 'type': 'string', + }, + 'experiment': { + 'title': 'Experiment ID', + }, + 'site': { + 'title': 'Site', + 'type': 'string', + }, + 'files': { + 'title': 'Files', + 'type': 'array', + 'items': nimsapiutil.NIMSRequestHandler.file_schema, + 'uniqueItems': True, + }, + }, + 'required': ['_id', 'experiment', 'uid', 'patient_id', 'subject'], #FIXME + } + + def schema(self, *args, **kwargs): + import copy + json_schema = copy.deepcopy(self.json_schema) + json_schema['properties'].update(nimsdata.NIMSData.session_properties) + self.response.write(json.dumps(json_schema, default=bson.json_util.default)) + + def get(self, sid): + """Return one Session, conditionally with details.""" + session = self.app.db.sessions.find_one({'_id': bson.objectid.ObjectId(sid)}) + if not session: + self.abort(404) + experiment = self.app.db.experiments.find_one({'_id': bson.objectid.ObjectId(session['experiment'])}) + if not experiment: + self.abort(500) + if not self.user_is_superuser and self.userid not in experiment['permissions']: + self.abort(403) + self.response.write(json.dumps(session, default=bson.json_util.default)) + + def put(self, sid): + """Update an existing Session.""" + self.response.write('session %s put, %s\n' % (sid, self.request.params)) + + def delete(self, sid): + """Delete an Session.""" + self.response.write('session %s delete, %s\n' % (sid, self.request.params)) + + def move(self, sid): + """ + Move a Session to another Experiment. + + Usage: + /nimsapi/sessions/123/move?dest=456 + """ + self.response.write('session %s move, %s\n' % (sid, self.request.params)) + + +class Epochs(nimsapiutil.NIMSRequestHandler): + + """/nimsapi/epochs """ + + json_schema = { + '$schema': 'http://json-schema.org/draft-04/schema#', + 'title': 'Epoch List', + 'type': 'array', + 'items': { + 'title': 'Epoch', + 'type': 'object', + 'properties': { + '_id': { + 'title': 'Database ID', + }, + 'name': { + 'title': 'Epoch', + 'type': 'string', + }, + 'description': { + 'title': 'Description', + 'type': 'string', + }, + 'datatype': { + 'title': 'Datatype', + 'type': 'string', + }, + } + } + } + + def count(self): + """Return the number of Epochs.""" + self.response.write(json.dumps(self.app.db.epochs.count())) + + def post(self): + """Create a new Epoch.""" + self.response.write('epochs post\n') + + def get(self, sid): + """Return the list of Session Epochs.""" + session = self.app.db.sessions.find_one({'_id': bson.objectid.ObjectId(sid)}) + if not session: + self.abort(404) + experiment = self.app.db.experiments.find_one({'_id': bson.objectid.ObjectId(session['experiment'])}) + if not experiment: + self.abort(500) + if not self.user_is_superuser and self.userid not in experiment['permissions']: + self.abort(403) + query = {'session': bson.objectid.ObjectId(sid)} + projection = ['name', 'description', 'datatype'] + epochs = list(self.app.db.epochs.find(query, projection)) + self.response.write(json.dumps(epochs, default=bson.json_util.default)) + + def put(self): + """Update many Epochs.""" + self.response.write('epochs put\n') + + +class Epoch(nimsapiutil.NIMSRequestHandler): + + """/nimsapi/epochs/<eid> """ + + json_schema = { + '$schema': 'http://json-schema.org/draft-04/schema#', + 'title': 'Epoch', + 'type': 'object', + 'properties': { + '_id': { + 'title': 'Database ID', + }, + 'uid': { + 'title': 'UID', + 'type': 'string', + }, + 'session': { + 'title': 'Session ID', + }, + 'files': { + 'title': 'Files', + 'type': 'array', + 'items': nimsapiutil.NIMSRequestHandler.file_schema, + 'uniqueItems': True, + }, + }, + 'required': ['_id'], #FIXME + } + + def schema(self, *args, **kwargs): + import copy + json_schema = copy.deepcopy(self.json_schema) + json_schema['properties'].update(nimsdata.nimsdicom.NIMSDicom.epoch_properties) + self.response.write(json.dumps(json_schema, default=bson.json_util.default)) + + def get(self, eid): + """Return one Epoch, conditionally with details.""" + epoch = self.app.db.epochs.find_one({'_id': bson.objectid.ObjectId(eid)}) + if not epoch: + self.abort(404) + session = self.app.db.sessions.find_one({'_id': epoch['session']}) + if not session: + self.abort(500) + experiment = self.app.db.experiments.find_one({'_id': bson.objectid.ObjectId(session['experiment'])}) + if not experiment: + self.abort(500) + if not self.user_is_superuser and self.userid not in experiment['permissions']: + self.abort(403) + self.response.write(json.dumps(epoch, default=bson.json_util.default)) + + def put(self, eid): + """Update an existing Epoch.""" + self.response.write('epoch %s put, %s\n' % (epoch_id, self.request.params)) + + def delete(self, eid): + """Delete an Epoch.""" + self.response.write('epoch %s delete, %s\n' % (epoch_id, self.request.params)) diff --git a/nimsapi.py b/nimsapi.py index e205035404d21b03dc58313cd7e3ad2c26d4be39..8d9dfbeb1d2bf8edcac3762021d9f5f761aeff95 100755 --- a/nimsapi.py +++ b/nimsapi.py @@ -20,10 +20,9 @@ import Crypto.PublicKey.RSA import nimsutil -import epochs -import sessions import experiments import nimsapiutil +import collections_ log = logging.getLogger('nimsapi') @@ -39,38 +38,45 @@ class NIMSAPI(nimsapiutil.NIMSRequestHandler): def get(self): """Return API documentation""" resources = """ - Resource | Description - :-------------------------------------------------|:----------------------- - /nimsapi/download | download - /nimsapi/dump | dump - /nimsapi/upload | upload - /nimsapi/remotes | list of remote instances - [(/nimsapi/users)] | list of users - [(/nimsapi/users/count)] | count of users - [(/nimsapi/users/listschema)] | schema for user list - [(/nimsapi/users/schema)] | schema for single user - /nimsapi/users/*<uid>* | details for one user, *<uid>* - [(/nimsapi/groups)] | list of groups - [(/nimsapi/groups/count)] | count of groups - [(/nimsapi/groups/listschema)] | schema for group list - [(/nimsapi/groups/schema)] | schema for single group - /nimsapi/groups/*<gid>* | details for one group, *<gid>* - [(/nimsapi/experiments)] | list of experiments - [(/nimsapi/experiments/count)] | count of experiments - [(/nimsapi/experiments/listschema)] | schema for experiment list - [(/nimsapi/experiments/schema)] | schema for single experiment - /nimsapi/experiments/*<xid>* | details for one experiment, *<xid>* - /nimsapi/experiments/*<xid>*/sessions | list sessions for one experiment, *<xid>* - [(/nimsapi/sessions/count)] | count of sessions - [(/nimsapi/sessions/listschema)] | schema for sessions list - [(/nimsapi/sessions/schema)] | schema for single session - /nimsapi/sessions/*<sid>* | details for one session, *<sid>* - /nimsapi/sessions/*<sid>*/move | move one session, *<sid>*, to a different experiment - /nimsapi/sessions/*<sid>*/epochs | list epochs for one session, *<sid>* - [(/nimsapi/epochs/count)] | count of epochs - [(/nimsapi/epochs/listschema)] | schema for epoch list - [(/nimsapi/epochs/schema)] | schema for single epoch - /nimsapi/epochs/*<eid>* | details for one epoch, *<eid>*""" + Resource | Description + :---------------------------------------------------|:----------------------- + nimsapi/download | download + nimsapi/upload | upload + nimsapi/remotes | list of remote instances + [(nimsapi/users)] | list of users + [(nimsapi/users/count)] | count of users + [(nimsapi/users/listschema)] | schema for user list + [(nimsapi/users/schema)] | schema for single user + nimsapi/users/*<uid>* | details for user *<uid>* + [(nimsapi/groups)] | list of groups + [(nimsapi/groups/count)] | count of groups + [(nimsapi/groups/listschema)] | schema for group list + [(nimsapi/groups/schema)] | schema for single group + nimsapi/groups/*<gid>* | details for group *<gid>* + [(nimsapi/experiments)] | list of experiments + [(nimsapi/experiments/count)] | count of experiments + [(nimsapi/experiments/listschema)] | schema for experiment list + [(nimsapi/experiments/schema)] | schema for single experiment + nimsapi/experiments/*<xid>* | details for experiment *<xid>* + nimsapi/experiments/*<xid>*/sessions | list sessions for experiment *<xid>* + [(nimsapi/sessions/count)] | count of sessions + [(nimsapi/sessions/listschema)] | schema for sessions list + [(nimsapi/sessions/schema)] | schema for single session + nimsapi/sessions/*<sid>* | details for session *<sid>* + nimsapi/sessions/*<sid>*/move | move session *<sid>* to a different experiment + nimsapi/sessions/*<sid>*/epochs | list epochs for session *<sid>* + [(nimsapi/epochs/count)] | count of epochs + [(nimsapi/epochs/listschema)] | schema for epoch list + [(nimsapi/epochs/schema)] | schema for single epoch + nimsapi/epochs/*<eid>* | details for epoch *<eid>* + [(nimsapi/collections)] | list of collections + [(nimsapi/collections/count)] | count of collections + [(nimsapi/collections/listschema)] | schema for collections list + [(nimsapi/collections/schema)] | schema for single collection + nimsapi/collections/*<cid>* | details for collection *<cid>* + nimsapi/collections/*<cid>*/sessions | list sessions for collection *<cid>* + nimsapi/collections/*<cid>*/epochs?session=*<sid>* | list of epochs for collection *<cid>*, optionally restricted to session *<sid>* + """ resources = re.sub(r'\[\((.*)\)\]', r'[\1](\1)', resources).replace('<', '<').replace('>', '>').strip() self.response.headers['Content-Type'] = 'text/html; charset=utf-8' self.response.write('<html>\n') @@ -123,9 +129,6 @@ class NIMSAPI(nimsapiutil.NIMSRequestHandler): paths += _idpaths symlinks += _idsymlinks - def dump(self): - self.response.write(json.dumps(list(self.app.db.sessions.find()), default=bson.json_util.default)) - class Users(nimsapiutil.NIMSRequestHandler): @@ -392,7 +395,7 @@ class ArgumentParser(argparse.ArgumentParser): super(ArgumentParser, self).__init__() self.add_argument('uri', help='NIMS DB URI') self.add_argument('stage_path', help='path to staging area') - self.add_argument('--privkey', help='path to private SSL key file') + self.add_argument('-k', '--privkey', help='path to private SSL key file') self.add_argument('-u', '--uid', help='site UID') self.add_argument('-f', '--logfile', help='path to log file') self.add_argument('-l', '--loglevel', default='info', help='path to log file') @@ -402,7 +405,6 @@ routes = [ webapp2.Route(r'/nimsapi', NIMSAPI), webapp2_extras.routes.PathPrefixRoute(r'/nimsapi', [ webapp2.Route(r'/download', NIMSAPI, handler_method='download', methods=['GET']), - webapp2.Route(r'/dump', NIMSAPI, handler_method='dump', methods=['GET']), webapp2.Route(r'/upload', NIMSAPI, handler_method='upload', methods=['PUT']), webapp2.Route(r'/remotes', Remotes), webapp2.Route(r'/users', Users), @@ -420,17 +422,24 @@ routes = [ webapp2.Route(r'/experiments/listschema', experiments.Experiments, handler_method='schema', methods=['GET']), webapp2.Route(r'/experiments/schema', experiments.Experiment, handler_method='schema', methods=['GET']), webapp2.Route(r'/experiments/<xid:[0-9a-f]{24}>', experiments.Experiment), - webapp2.Route(r'/experiments/<xid:[0-9a-f]{24}>/sessions', sessions.Sessions), - webapp2.Route(r'/sessions/count', sessions.Sessions, handler_method='count', methods=['GET']), - webapp2.Route(r'/sessions/listschema', sessions.Sessions, handler_method='schema', methods=['GET']), - webapp2.Route(r'/sessions/schema', sessions.Session, handler_method='schema', methods=['GET']), - webapp2.Route(r'/sessions/<sid:[0-9a-f]{24}>', sessions.Session), - webapp2.Route(r'/sessions/<sid:[0-9a-f]{24}>/move', sessions.Session, handler_method='move'), - webapp2.Route(r'/sessions/<sid:[0-9a-f]{24}>/epochs', epochs.Epochs), - webapp2.Route(r'/epochs/count', epochs.Epochs, handler_method='count', methods=['GET']), - webapp2.Route(r'/epochs/listschema', epochs.Epochs, handler_method='schema', methods=['GET']), - webapp2.Route(r'/epochs/schema', epochs.Epoch, handler_method='schema', methods=['GET']), - webapp2.Route(r'/epochs/<eid:[0-9a-f]{24}>', epochs.Epoch), + webapp2.Route(r'/experiments/<xid:[0-9a-f]{24}>/sessions', experiments.Sessions), + webapp2.Route(r'/sessions/count', experiments.Sessions, handler_method='count', methods=['GET']), + webapp2.Route(r'/sessions/listschema', experiments.Sessions, handler_method='schema', methods=['GET']), + webapp2.Route(r'/sessions/schema', experiments.Session, handler_method='schema', methods=['GET']), + webapp2.Route(r'/sessions/<sid:[0-9a-f]{24}>', experiments.Session), + webapp2.Route(r'/sessions/<sid:[0-9a-f]{24}>/move', experiments.Session, handler_method='move'), + webapp2.Route(r'/sessions/<sid:[0-9a-f]{24}>/epochs', experiments.Epochs), + webapp2.Route(r'/epochs/count', experiments.Epochs, handler_method='count', methods=['GET']), + webapp2.Route(r'/epochs/listschema', experiments.Epochs, handler_method='schema', methods=['GET']), + webapp2.Route(r'/epochs/schema', experiments.Epoch, handler_method='schema', methods=['GET']), + webapp2.Route(r'/epochs/<eid:[0-9a-f]{24}>', experiments.Epoch), + webapp2.Route(r'/collections', collections_.Collections), + webapp2.Route(r'/collections/count', collections_.Collections, handler_method='count', methods=['GET']), + webapp2.Route(r'/collections/listschema', collections_.Collections, handler_method='schema', methods=['GET']), + webapp2.Route(r'/collections/schema', collections_.Collection, handler_method='schema', methods=['GET']), + webapp2.Route(r'/collections/<cid:[0-9a-f]{24}>', collections_.Collection), + webapp2.Route(r'/collections/<cid:[0-9a-f]{24}>/sessions', collections_.Sessions), + webapp2.Route(r'/collections/<cid:[0-9a-f]{24}>/epochs', collections_.Epochs), ]), ] diff --git a/nimsapiutil.py b/nimsapiutil.py index a07d5a549dce91dd3bb95021e0b515b7af63e141..17025f02db1209c02d224dacab00042b50e465a4 100644 --- a/nimsapiutil.py +++ b/nimsapiutil.py @@ -27,17 +27,9 @@ class NIMSRequestHandler(webapp2.RequestHandler): 'title': 'File', 'type': 'object', 'properties': { - 'datakind': { - 'title': 'Data Kind', - 'type': 'string', - }, - 'datatype': { - 'title': 'Data Type', - 'type': 'string', - }, - 'filetype': { - 'title': 'File Type', - 'type': 'string', + 'type': { + 'title': 'Type', + 'type': 'array', }, 'filename': { 'title': 'File Name', diff --git a/sessions.py b/sessions.py deleted file mode 100644 index a86cc17a98477758c370301be0353aca11767c7d..0000000000000000000000000000000000000000 --- a/sessions.py +++ /dev/null @@ -1,132 +0,0 @@ -# @author: Gunnar Schaefer - -import json -import webapp2 -import bson.json_util - -import nimsdata -import nimsapiutil - - -class Sessions(nimsapiutil.NIMSRequestHandler): - - """/sessions """ - - json_schema = { - '$schema': 'http://json-schema.org/draft-04/schema#', - 'title': 'Session List', - 'type': 'array', - 'items': { - 'title': 'Session', - 'type': 'object', - 'properties': { - '_id': { - 'title': 'Database ID', - }, - 'timestamp': { - 'title': 'Timestamp', - }, - 'subject': { - 'title': 'Subject Code', - 'type': 'string', - }, - } - } - } - - def count(self): - """Return the number of Sessions.""" - self.response.write(json.dumps(self.app.db.sessions.count())) - - def post(self): - """Create a new Session""" - self.response.write('sessions post\n') - - def get(self, xid): - """Return the list of Experiment Sessions.""" - experiment = self.app.db.experiments.find_one({'_id': bson.objectid.ObjectId(xid)}) - if not experiment: - self.abort(404) - if not self.user_is_superuser and self.userid not in experiment['permissions']: - self.abort(403) - query = {'experiment': bson.objectid.ObjectId(xid)} - projection = ['timestamp', 'subject'] - sessions = list(self.app.db.sessions.find(query, projection)) - self.response.write(json.dumps(sessions, default=bson.json_util.default)) - - def put(self): - """Update many Sessions.""" - self.response.write('sessions put\n') - - -class Session(nimsapiutil.NIMSRequestHandler): - - """/sessions/<sid> """ - - json_schema = { - '$schema': 'http://json-schema.org/draft-04/schema#', - 'title': 'Session', - 'type': 'object', - 'properties': { - '_id': { - 'title': 'Database ID', - }, - 'uid': { - 'title': 'UID', - 'type': 'string', - }, - 'experiment': { - 'title': 'Experiment ID', - }, - 'timestamp': { - 'title': 'Timestamp', - }, - 'subject': { - 'title': 'Subject Code', - 'type': 'string', - 'maxLength': 16, - }, - 'files': { - 'title': 'Files', - 'type': 'array', - 'items': nimsapiutil.NIMSRequestHandler.file_schema, - 'uniqueItems': True, - }, - }, - 'required': ['_id', 'experiment', 'uid', 'patient_id', 'subject'], - } - - def schema(self, *args, **kwargs): - import copy - json_schema = copy.deepcopy(self.json_schema) - json_schema['properties'].update(nimsdata.NIMSData.session_properties) - self.response.write(json.dumps(json_schema, default=bson.json_util.default)) - - def get(self, sid): - """Return one Session, conditionally with details.""" - session = self.app.db.sessions.find_one({'_id': bson.objectid.ObjectId(sid)}) - if not session: - self.abort(404) - experiment = self.app.db.experiments.find_one({'_id': bson.objectid.ObjectId(session['experiment'])}) - if not experiment: - self.abort(500) - if not self.user_is_superuser and self.userid not in experiment['permissions']: - self.abort(403) - self.response.write(json.dumps(session, default=bson.json_util.default)) - - def put(self, sid): - """Update an existing Session.""" - self.response.write('session %s put, %s\n' % (sid, self.request.params)) - - def delete(self, sid): - """Delete an Session.""" - self.response.write('session %s delete, %s\n' % (sid, self.request.params)) - - def move(self, sid): - """ - Move a Session to another Experiment. - - Usage: - /nimsapi/sessions/123/move?dest=456 - """ - self.response.write('session %s move, %s\n' % (sid, self.request.params))