Ejemplo n.º 1
0
    def log(self, id, params):
        user = getCurrentUser()
        offset = 0
        if 'offset' in params:
            offset = int(params['offset'])

        if not self._model.load(id, user=user, level=AccessType.READ):
            raise RestException('Volume not found.', code=404)

        log_records = self._model.log_records(user, id, offset)

        return {'log': log_records}
Ejemplo n.º 2
0
    def getUser(self, token):
        headers = {
            'Authorization': 'Bearer %s' % token['access_token'],
            'Accept': 'application/json'
        }

        # Get user's email address
        resp = self._getJson(method='GET', url=self._API_USER_URL, headers=headers)
        email = resp.get('login')
        if not email:
            raise RestException(
                'Box did not return user information.', code=502)

        # Get user's OAuth2 ID, login, and name
        oauthId = resp.get('id')
        if not oauthId:
            raise RestException('Box did not return a user ID.', code=502)

        names = resp.get('name').split()
        firstName, lastName = names[0], names[-1]
        return self._createOrReuseUser(oauthId, email, firstName, lastName)
Ejemplo n.º 3
0
    def _getGeometry(self, params):
        try:
            geometry = bson.json_util.loads(params['geometry'])
            GeoJSON.to_instance(geometry, strict=True)

            if geometry['type'] != 'Point':
                raise ValueError

            return geometry
        except (TypeError, ValueError):
            raise RestException("Invalid GeoJSON passed as 'geometry'"
                                " parameter.")
Ejemplo n.º 4
0
    def setGeospatial(self, item, params):
        """
        Set geospatial data on an item.

        :param item: item on which to set geospatial data.
        :type item: dict[str, unknown]
        :param params: parameters to the API call, unused.
        :type params: dict[str, unknown]
        :returns: filtered fields of the item with geospatial data appended to
                 its 'geo' field.
        :rtype : dict[str, unknown]
        :raise RestException: on malformed, forbidden, or unauthorized API call.
        """
        geospatial = self.getBodyJson()

        for k, v in six.viewitems(geospatial):
            if '.' in k or k[0] == '$':
                raise RestException('Geospatial key name %s must not contain a'
                                    ' period or begin with a dollar sign.' % k)
            if v:
                try:
                    GeoJSON.to_instance(v, strict=True)
                except ValueError:
                    raise RestException('Geospatial field with key %s does not'
                                        ' contain valid GeoJSON: %s' % (k, v))

        if GEOSPATIAL_FIELD not in item:
            item[GEOSPATIAL_FIELD] = dict()

        item[GEOSPATIAL_FIELD].update(six.viewitems(geospatial))
        keys = [
            k for k, v in six.viewitems(item[GEOSPATIAL_FIELD]) if v is None
        ]

        for key in keys:
            del item[GEOSPATIAL_FIELD][key]

        item = self.model('item').updateItem(item)

        return self._filter(item)
Ejemplo n.º 5
0
    def login(self, params):
        """
        Login endpoint. Sends an auth cookie in the response on success.
        The caller is expected to use HTTP Basic Authentication when calling
        this endpoint.
        """
        user, token = self.getCurrentUser(returnToken=True)

        # Only create and send new cookie if user isn't already sending
        # a valid one.
        if not user:
            authHeader = cherrypy.request.headers.get('Girder-Authorization')

            if not authHeader:
                authHeader = cherrypy.request.headers.get('Authorization')

            if not authHeader or not authHeader[0:6] == 'Basic ':
                raise RestException('Use HTTP Basic Authentication', 401)

            try:
                credentials = base64.b64decode(authHeader[6:]).decode('utf8')
                if ':' not in credentials:
                    raise TypeError
            except Exception:
                raise RestException('Invalid HTTP Authorization header', 401)

            login, password = credentials.split(':', 1)

            login = login.lower().strip()
            loginField = 'email' if '@' in login else 'login'

            user = self.model('user').findOne({loginField: login})
            if user is None:
                raise RestException('Login failed.', code=403)

            if not self.model('password').authenticate(user, password):
                raise RestException('Login failed.', code=403)

            if self.model('user').emailVerificationRequired(user):
                raise RestException(
                    'Email verification required.', code=403,
                    extra='emailVerification')

            if self.model('user').adminApprovalRequired(user):
                raise RestException(
                    'Account approval required.', code=403,
                    extra='accountApproval')

            setattr(cherrypy.request, 'girderUser', user)
            token = self.sendAuthTokenCookie(user)

        return {
            'user': self.model('user').filter(user, user),
            'authToken': {
                'token': token['_id'],
                'expires': token['expires'],
                'scope': token['scope']
            },
            'message': 'Login succeeded.'
        }
Ejemplo n.º 6
0
        def wrapped(*args, **kwargs):
            """
            Transform any passed params according to the spec, or
            fill in default values for any params not passed.
            """
            # Combine path params with form/query params into a single lookup table
            params = {k: v for k, v in six.viewitems(kwargs) if k != 'params'}
            params.update(kwargs.get('params', {}))

            for descParam in self.description.params:
                # We need either a type or a schema ( for message body )
                if 'type' not in descParam and 'schema' not in descParam:
                    continue
                name = descParam['name']
                if name in params:
                    if name in self.description.jsonParams:
                        info = self.description.jsonParams[name]
                        val = self._loadJson(name, info, params[name])
                        self._passArg(fun, kwargs, name, val)
                    elif name in self.description.modelParams:
                        info = self.description.modelParams[name]
                        kwargs.pop(name, None)  # Remove from path params
                        val = self._loadModel(name, info, params[name])
                        self._passArg(fun, kwargs, info['destName'], val)
                    else:
                        val = self._validateParam(name, descParam,
                                                  params[name])
                        self._passArg(fun, kwargs, name, val)
                elif descParam['in'] == 'body':
                    if name in self.description.jsonParams:
                        info = self.description.jsonParams[name].copy()
                        info['required'] = descParam['required']
                        val = self._loadJsonBody(name, info)
                        self._passArg(fun, kwargs, name, val)
                    else:
                        self._passArg(fun, kwargs, name, cherrypy.request.body)
                elif 'default' in descParam:
                    self._passArg(fun, kwargs, name, descParam['default'])
                elif descParam['required']:
                    raise RestException('Parameter "%s" is required.' % name)
                else:
                    # If required=False but no default is specified, use None
                    if name in self.description.modelParams:
                        info = self.description.modelParams[name]
                        kwargs.pop(name, None)  # Remove from path params
                        self._passArg(fun, kwargs, info['destName'], None)
                    else:
                        self._passArg(fun, kwargs, name, None)

            self._mungeKwargs(kwargs, fun)

            return fun(*args, **kwargs)
Ejemplo n.º 7
0
    def callback(self, provider, params):
        if 'error' in params:
            raise RestException("Provider returned error: '%s'." %
                                params['error'],
                                code=502)

        self.requireParams(('state', 'code'), params)

        providerName = provider
        provider = providers.idMap.get(providerName)
        if not provider:
            raise RestException("Unknown provider '%s'." % providerName)

        redirect = self._validateCsrfToken(params['state'])

        providerObj = provider(cherrypy.url())
        token = providerObj.getToken(params['code'])
        user = providerObj.getUser(token)

        self.sendAuthTokenCookie(user)

        raise cherrypy.HTTPRedirect(redirect)
Ejemplo n.º 8
0
def _add_indexed_output_param(param, args, user, result_hooks):
    value = args[param.identifier()]
    folder = args[param.identifier() + FOLDER_SUFFIX]

    folderModel = ModelImporter.model('folder')
    instance = folderModel.load(folder, level=AccessType.WRITE, user=user)
    if not instance:
        raise RestException('Invalid Folder id (%s).' % (str(folder)))

    # Output Binding !!
    path = VolumePath(value)
    result_hooks.append(GirderUploadVolumePathToFolder(path, folder))
    return path
Ejemplo n.º 9
0
    def image_shape(self, id, user, name):
        path = '/stem/images'
        with self._open_h5py_file(id, user) as rf:
            dataset = rf[path]

            if self._str_is_int(name):
                index = int(name)
                if index >= len(dataset):
                    raise RestException('Index is too large')
            else:
                index = self._get_image_index_from_name(dataset, name)

            return dataset[index].shape
Ejemplo n.º 10
0
    def mongoSearch(self, params):
        self.requireParams(('type', 'q'), params)
        allowed = {
            'collection': ['_id', 'name', 'description'],
            'folder': ['_id', 'name', 'description'],
            'item': ['_id', 'name', 'description', 'folderId'],
            'user': ['_id', 'firstName', 'lastName', 'login']
        }
        limit, offset, sort = self.getPagingParameters(params, 'name')
        coll = params['type']

        events.trigger('mongo_search.allowed_collections', info=allowed)

        if coll not in allowed:
            raise RestException('Invalid resource type: {}'.format(coll))

        try:
            query = bson.json_util.loads(params['q'])
        except ValueError:
            raise RestException('The query parameter must be a JSON object.')

        model = ModelImporter().model(coll)
        if hasattr(model, 'filterResultsByPermission'):
            cursor = model.find(query,
                                fields=allowed[coll] + ['public', 'access'])
            return list(
                model.filterResultsByPermission(cursor,
                                                user=self.getCurrentUser(),
                                                level=AccessType.READ,
                                                limit=limit,
                                                offset=offset,
                                                removeKeys=('public',
                                                            'access')))
        else:
            return list(
                model.find(query,
                           fields=allowed[coll],
                           limit=limit,
                           offset=offset))
Ejemplo n.º 11
0
    def getUser(self, token):
        headers = {'Authorization': 'Bearer {}'.format(token['access_token'])}

        resp = self._getJson(method='GET',
                             url=self._API_USER_URL,
                             headers=headers)

        oauthId = resp.get('sub')
        if not oauthId:
            raise RestException('Globus identity did not return a valid ID.',
                                code=502)

        email = resp.get('email')
        if not email:
            raise RestException(
                'Globus identity did not return a valid email.', code=502)

        name = resp['name'].split()
        firstName = name[0]
        lastName = name[-1]

        return self._createOrReuseUser(oauthId, email, firstName, lastName)
Ejemplo n.º 12
0
    def updateGraph(self, graphObj, graph, params):
        """Update graph."""
        user = self.getCurrentUser()

        graphObj['name'] = graph['name']
        graphObj['content'] = graph['content']

        if 'public' in graph and graph['public'] and not user['admin']:
            raise RestException('Not authorized to create public graphs', 403)
        elif 'public' in graph:
            graphObj['public'] = graph['public']

        return self.model('graph', 'cis').updateGraph(graphObj)
Ejemplo n.º 13
0
    def resetPassword(self, email):
        user = self.model('user').findOne({'email': email.lower()})
        if user is None:
            raise RestException('That email is not registered.')

        randomPass = genToken(length=12)

        html = mail_utils.renderTemplate('resetPassword.mako', {
            'password': randomPass
        })
        mail_utils.sendEmail(to=email, subject='Girder: Password reset', text=html)
        self.model('user').setPassword(user, randomPass)
        return {'message': 'Sent password reset email.'}
Ejemplo n.º 14
0
    def _getTilesInfo(self, item, imageArgs):
        """
        Get metadata for an item's large image.

        :param item: the item to query.
        :param imageArgs: additional arguments to use when fetching image data.
        :return: the tile metadata.
        """
        try:
            return self.model('image_item', 'large_image').getMetadata(
                item, **imageArgs)
        except TileGeneralException as e:
            raise RestException(e.message, code=400)
Ejemplo n.º 15
0
def launch_taskflow(user, body):
    # Perform some validation
    taskFlowBody = body.get('taskFlowBody')
    if taskFlowBody is None:
        raise RestException('taskFlowBody is a required key')

    if 'taskFlowClass' not in taskFlowBody:
        raise RestException('taskFlowClass is required in taskFlowBody')

    taskflow_class = taskFlowBody['taskFlowClass']

    # Check that we can load the taskflow class
    try:
        load_class(taskflow_class)
    except Exception as ex:
        msg = 'Unable to load taskflow class: %s (%s)' % \
              (taskflow_class, ex)
        raise RestException(msg, 400)

    # Set up the taskflow input
    taskFlowInput = body.get('taskFlowInput', {})
    if 'cluster' not in taskFlowInput:
        # Make a cluster
        taskFlowInput['cluster'] = create_cluster_object(user)

    if 'container' not in taskFlowInput:
        taskFlowInput['container'] = 'docker'

    # Load the queue
    queue = fetch_or_create_queue(user)

    # Create the taskflow
    taskflow = TaskflowModel().create(user, taskFlowBody)

    # Add it to the queue and start it
    QueueModel().add(queue, taskflow, taskFlowInput, user)
    QueueModel().pop(queue, limit=sys.maxsize, user=user)

    return taskflow['_id']
Ejemplo n.º 16
0
    def searchCase(self, params):
        user = self.getCurrentUser()
        limit, offset, sort = self.getPagingParameters(params, 'name')
        self.requireParams('table', params)

        table = params.get('table')
        key = params.get('key')
        value = params.get('value')
        substring = params.get('substring')

        if value and substring:
            raise RestException('Cannot search by both value and substring')

        if (value or substring) and not key:
            raise RestException('A key must be provided to search by value')

        if key and invalid_key_re.search(key):
            raise RestException('Invalid key parameter')

        query = {}
        if not key:
            query = {'tcga.meta.' + table: {'$exists': True}}
        elif not value and not substring:
            query = {'tcga.meta.' + table + '.' + key: {'$exists': True}}
        elif value:
            query = {'tcga.meta.' + table + '.' + key: value}
        else:
            query = {
                'tcga.meta.' + table + '.' + key:
                re.compile(re.escape(substring))
            }

        cursor = self.model('case',
                            'digital_slide_archive').find(query,
                                                          user=user,
                                                          offset=offset,
                                                          limit=limit,
                                                          sort=sort)
        return pagedResponse(cursor, limit, offset, sort)
Ejemplo n.º 17
0
    def updateAccess(self, challenge, params):
        self.requireParams('access', params)

        public = self.boolParam('public', params, default=False)
        self.model('challenge', 'covalic').setPublic(challenge, public)

        try:
            access = json.loads(params['access'])
            return self.model('challenge', 'covalic').setAccessList(challenge,
                                                                    access,
                                                                    save=True)
        except ValueError:
            raise RestException('The access parameter must be JSON.')
Ejemplo n.º 18
0
 def _get_h5_dataset(self,
                     id,
                     user,
                     path,
                     offset=None,
                     limit=None,
                     format='bytes'):
     if format == 'bytes' or format is None:
         return self._get_h5_dataset_bytes(id, user, path, offset, limit)
     elif format == 'msgpack':
         return self._get_h5_dataset_msgpack(id, user, path, offset, limit)
     else:
         raise RestException('Unknown format: ' + format)
Ejemplo n.º 19
0
    def cullNotebooks(self):
        # SC16: query all tmpnb_urls here and aggregate the results
        #       may not be necessary if we disable 'heartbeat', but
        #       I'm annotating it for completeness
        resp = requests.get(
            self.model('setting').get(PluginSettings.TMPNB_URL))
        content = resp.content
        if isinstance(content, six.binary_type):
            content = content.decode('utf8')
        try:
            resp.raise_for_status()
        except requests.HTTPError:
            raise RestException('Got %s code from tmpnb, response="%s"/' %
                                (resp.status_code, content),
                                code=502)
        try:
            activity = json.loads(content)
        except ValueError:
            raise RestException('Non-JSON response: %s' % content, code=502)

        admin = next(_ for _ in self.model('user').getAdmins())
        token = self.model('token').createToken(user=admin, days=1)

        # Iterate over all notebooks, not the prettiest way...
        cull_period = self.model('setting').get(PluginSettings.CULLING_PERIOD,
                                                '4')
        cull_time = datetime.datetime.utcnow() - \
            datetime.timedelta(hours=float(cull_period))
        for nb in self.find({}):
            try:
                last_activity = dateutil.parser.parse(
                    activity[nb['containerId']], ignoretz=True)
            except KeyError:
                # proxy is not aware of such container, kill it...
                logger.info('Deleting nb %s' % nb['_id'])
                self.deleteNotebook(nb, token)
            if last_activity < cull_time:
                logger.info('Deleting nb %s' % nb['_id'])
                self.deleteNotebook(nb, token)
Ejemplo n.º 20
0
    def import_script(self, id, params):
        user = self.getCurrentUser()
        lines = cherrypy.request.body.read().decode('utf8').splitlines()

        script = self._model.load(id, user=user, level=AccessType.ADMIN)

        if not script:
            raise RestException('Script doesn\'t exist', code=404)

        script['commands'] = lines
        self._model.save(script)

        return self._clean(script)
Ejemplo n.º 21
0
    def createThumbnail(self, file, params):
        self.requireParams(('attachToId', 'attachToType'), params)

        user = self.getCurrentUser()
        width = params.get('width')
        height = params.get('height')

        if params['attachToType'] not in (
                'item', 'collection', 'user', 'folder'):
            raise RestException('You can only attach thumbnails to users, '
                                'folders, collections, or items.')

        self.model(params['attachToType']).load(
            params['attachToId'], user=user, level=AccessType.WRITE, exc=True)

        width = max(int(params.get('width', 0)), 0)
        height = max(int(params.get('height', 0)), 0)

        if not width and not height:
            raise RestException(
                'You must specify a valid width, height, or both.')

        kwargs = {
            'width': width,
            'height': height,
            'fileId': str(file['_id']),
            'crop': self.boolParam('crop', params, default=True),
            'attachToType': params['attachToType'],
            'attachToId': params['attachToId']
        }

        job = self.model('job', 'jobs').createLocalJob(
            title='Generate thumbnail for %s' % file['name'], user=user,
            type='thumbnails.create', public=False, kwargs=kwargs,
            module='girder.plugins.thumbnails.worker')

        self.model('job', 'jobs').scheduleJob(job)

        return job
Ejemplo n.º 22
0
def max_instances(user, profile, params):
    client = get_ec2_client(profile)
    response = client.describe_account_attributes(
        AttributeNames=['max-instances'])
    jsonpath = 'AccountAttributes[0].AttributeValues[0].AttributeValue'
    max_instances = parse(jsonpath).find(response)

    if max_instances:
        max_instances = max_instances[0].value
    else:
        raise RestException('Unable to extract "max-instances" attribute.')

    return {'maxinstances': max_instances}
Ejemplo n.º 23
0
def acceptCollectionTerms(self, collection, termsHash):
    if not collection.get('terms'):
        raise RestException('This collection currently has no terms.')

    # termsHash should be encoded to a bytes object, but storing bytes into MongoDB behaves
    # differently in Python 2 vs 3. Additionally, serializing a bytes to JSON behaves differently
    # in Python 2 vs 3. So, just keep it as a unicode (or ordinary Python 2 str).
    realTermsHash = hashlib.sha256(collection['terms'].encode('utf-8')).hexdigest()
    if termsHash != realTermsHash:
        # This "proves" that the client has at least accessed the terms
        raise RestException(
            'The submitted "termsHash" does not correspond to the collection\'s current terms.')

    ModelImporter.model('user').update(
        {'_id': self.getCurrentUser()['_id']},
        {'$set': {
            'terms.collection.%s' % collection['_id']: {
                'hash': termsHash,
                'accepted': datetime.datetime.now()
            }
        }}
    )
Ejemplo n.º 24
0
def delete_profile(user, profile, params):

    query = {'profileId': profile['_id']}

    if ModelImporter.model('volume', 'cumulus').findOne(query):
        raise RestException(
            'Unable to delete profile as it is associated with'
            ' a volume', 400)

    if ModelImporter.model('cluster', 'cumulus').findOne(query):
        raise RestException(
            'Unable to delete profile as it is associated with'
            ' a cluster', 400)

    # Clean up key associate with profile
    cumulus.aws.ec2.tasks.key.delete_key_pair.delay(_filter(profile),
                                                    get_task_token()['_id'])

    client = get_ec2_client(profile)
    client.delete_key_pair(KeyName=str(profile['_id']))

    ModelImporter.model('aws', 'cumulus').remove(profile)
Ejemplo n.º 25
0
    def intersects(self, field, geometry, limit, offset, sort):
        try:
            GeoJSON.to_instance(geometry, strict=True)
        except (TypeError, ValueError):
            raise RestException(
                "Invalid GeoJSON passed as 'geometry' parameter.")

        if field[:3] != '%s.' % GEOSPATIAL_FIELD:
            field = '%s.%s' % (GEOSPATIAL_FIELD, field)

        query = {field: {'$geoIntersects': {'$geometry': geometry}}}

        return self._find(query, limit, offset, sort)
Ejemplo n.º 26
0
    def deleteFeatureset(self, featureset, params):
        user = self.getCurrentUser()
        # For now, study admins will be the ones that can delete featuresets
        User().requireAdminStudy(user)

        if Study().find({'meta.featuresetId': featureset['_id']}).count():
            raise RestException('Featureset is in use by one or more studies.',
                                409)

        Featureset().remove(featureset)

        # No Content
        cherrypy.response.status = 204
Ejemplo n.º 27
0
 def createGeojsonDataset(self, item, params):
     user = self.getCurrentUser()
     folder = findDatasetFolder(user, user, create=True)
     if folder is None:
         raise RestException('User has no Minerva Dataset folder.')
     if folder['_id'] != item['folderId']:
         raise RestException("Items need to be in user's Minerva Dataset " +
                             "folder.")
     minerva_metadata = {
         'original_type': 'geojson',
         'dataset_type': 'geojson',
     }
     # Use the first geojson or json file found as the dataset.
     for file in self.model('item').childFiles(item=item, limit=0):
         if ('geojson' in file['exts'] or 'json' in file['exts']
                 or file.get('mimeType') in (
                     'application/json',
                     'application/vnd.geo+json',
                 )):
             minerva_metadata['original_files'] = [{
                 'name': file['name'],
                 '_id': file['_id']
             }]
             minerva_metadata['geojson_file'] = {
                 'name': file['name'],
                 '_id': file['_id']
             }
             minerva_metadata['geo_render'] = {
                 'type': 'geojson',
                 'file_id': file['_id']
             }
             minerva_metadata['original_type'] = 'geojson'
             minerva_metadata['source'] = {'layer_source': 'GeoJSON'}
             minerva_metadata['source_type'] = 'item'
             break
     if 'geojson_file' not in minerva_metadata:
         raise RestException('Item contains no geojson file.')
     updateMinervaMetadata(item, minerva_metadata)
     return item
Ejemplo n.º 28
0
    def getHistograms(self, item, params):
        if 'meta' not in item or 'rlab' not in item[
                'meta'] or 'schema' not in item['meta']['rlab']:
            raise RestException('Item ' + str(item['_id']) +
                                ' has no schema information.')

        params, binSettings = self.fillInDefaultHistogramParams(item, params)

        # Stringify the params for cache hashing
        paramsCode = json.dumps(params, sort_keys=True)

        # Check if this query has already been run - if so, return the cached result
        if params['cache']:
            paramsMD5 = md5.md5(paramsCode).hexdigest()
            if 'histogramCaches' in item['meta']['rlab'] and paramsMD5 in item[
                    'meta']['rlab']['histogramCaches']:
                return item['meta']['rlab']['histogramCaches'][paramsMD5]

        # Construct and run the histogram MapReduce code
        mapScript = 'function map () {\n' + \
            self.foreignCode['binUtils.js'] + '\n' + \
            self.foreignCode['histogram_map.js'] + '\n}'

        reduceScript = 'function reduce (attrName, allHistograms) {\n' + \
            self.foreignCode['histogram_reduce.js'] + '\n' + \
            'return {histogram: histogram};\n}'

        histogram = self.mapReduce(item, mapScript, reduceScript, params)

        # We have to clean up the histogram wrappers (mongodb can't return
        # an array from reduce functions).
        for attrName, wrappedHistogram in histogram.iteritems():
            histogram[attrName] = wrappedHistogram['histogram']

        if '__passedFilters__' not in histogram:
            # This will only happen if there's a count of zero;
            # the __passedFilters__ bin will never have been emitted
            histogram['__passedFilters__'] = [{'count': 0, 'label': 'count'}]

        # Cache the results before returning them
        if params['cache']:
            if 'histogramCaches' not in item['meta']['rlab']:
                item['meta']['rlab']['histogramCaches'] = {}
            item['meta']['rlab']['histogramCaches'][paramsMD5] = histogram
            try:
                self.model('item').updateItem(item)
            except AccessException:
                # Meh, we couldn't cache the result. Not a big enough deal
                # to throw / display errors, so just fail silently
                pass
        return histogram
Ejemplo n.º 29
0
    def create_calc(self, params):
        body = getBodyJson()
        if 'cjson' not in body and ('fileId' not in body
                                    or 'format' not in body):
            raise RestException('Either cjson or fileId is required.')

        user = getCurrentUser()

        cjson = body.get('cjson')
        props = body.get('properties', {})
        molecule_id = body.get('moleculeId', None)
        geometry_id = body.get('geometryId', None)
        public = body.get('public', True)
        notebooks = body.get('notebooks', [])
        image = body.get('image')
        input_parameters = body.get('input', {}).get('parameters')
        if input_parameters is None:
            input_parameters = body.get('inputParameters', {})
        file_id = None
        file_format = body.get('format', 'cjson')

        if 'fileId' in body:
            file = File().load(body['fileId'], user=getCurrentUser())
            file_id = file['_id']
            cjson = self._file_to_cjson(file, file_format)

        if molecule_id is None:
            mol = create_molecule(json.dumps(cjson),
                                  'cjson',
                                  user,
                                  public,
                                  parameters=input_parameters)
            molecule_id = mol['_id']

        calc = CalculationModel().create_cjson(
            user,
            cjson,
            props,
            molecule_id,
            geometry_id=geometry_id,
            image=image,
            input_parameters=input_parameters,
            file_id=file_id,
            notebooks=notebooks,
            public=public)

        cherrypy.response.status = 201
        cherrypy.response.headers['Location'] \
            = '/calculations/%s' % (str(calc['_id']))

        return CalculationModel().filter(calc, user)
Ejemplo n.º 30
0
    def getUser(self, token):
        headers = {
            'Authorization': 'Bearer {}'.format(token['access_token']),
            'Accept': 'application/json'
        }

        # Get user's email address
        # In the unlikely case that a user has more than 30 email addresses,
        # this HTTP request might have to be made multiple times with
        # pagination
        resp = self._getJson(method='GET', url=self._API_EMAILS_URL,
                             headers=headers)
        emails = [
            email.get('email')
            for email in resp['values']
            if email.get('is_primary') and email.get('is_confirmed')
        ]
        if not emails:
            raise RestException(
                'This Bitbucket user has no registered email address.',
                code=502)
        # There should never be more than one primary email
        email = emails[0]

        # Get user's OAuth2 ID, login, and name
        resp = self._getJson(method='GET', url=self._API_USER_URL,
                             headers=headers)
        oauthId = resp.get('uuid')
        if not oauthId:
            raise RestException('Bitbucket did not return a user ID.', code=502)

        login = resp.get('username', None)

        names = (resp.get('display_name') or login).split()
        firstName, lastName = names[0], names[-1]

        user = self._createOrReuseUser(oauthId, email, firstName, lastName, login)
        return user