Пример #1
0
    def setTimestamp(self, id, type, created, updated):
        user = self.getCurrentUser()
        model = self._getResourceModel(type)
        doc = model.load(id=id, user=user, level=AccessType.WRITE, exc=True)

        if created is not None:
            if 'created' not in doc:
                raise RestException('Resource has no "created" field.')
            doc['created'] = parseTimestamp(created)
        if updated is not None:
            if 'updated' not in doc:
                raise RestException('Resource has no "updated" field.')
            doc['updated'] = parseTimestamp(updated)
        return model.filter(model.save(doc), user=user)
Пример #2
0
    def setTimestamp(self, id, type, created, updated):
        user = self.getCurrentUser()
        model = self._getResourceModel(type)
        doc = model.load(id=id, user=user, level=AccessType.WRITE, exc=True)

        if created is not None:
            if 'created' not in doc:
                raise RestException('Resource has no "created" field.')
            doc['created'] = parseTimestamp(created)
        if updated is not None:
            if 'updated' not in doc:
                raise RestException('Resource has no "updated" field.')
            doc['updated'] = parseTimestamp(updated)
        return model.filter(model.save(doc), user=user)
Пример #3
0
 def setTimestamp(self, id, params):
     user = self.getCurrentUser()
     model = self._getResourceModel(params['type'])
     doc = model.load(id=id, user=user, level=AccessType.WRITE)
     if not doc:
         raise RestException('Resource not found.')
     if 'created' in params:
         if 'created' not in doc:
             raise RestException('Resource has no "created" field.')
         doc['created'] = parseTimestamp(params['created'])
     if 'updated' in params:
         if 'updated' not in doc:
             raise RestException('Resource has no "updated" field.')
         doc['updated'] = parseTimestamp(params['updated'])
     return model.save(doc)
Пример #4
0
 def setTimestamp(self, id, params):
     user = self.getCurrentUser()
     model = self._getResourceModel(params['type'])
     doc = model.load(id=id, user=user, level=AccessType.WRITE)
     if not doc:
         raise RestException('Resource not found.')
     if 'created' in params:
         if 'created' not in doc:
             raise RestException('Resource has no "created" field.')
         doc['created'] = parseTimestamp(params['created'])
     if 'updated' in params:
         if 'updated' not in doc:
             raise RestException('Resource has no "updated" field.')
         doc['updated'] = parseTimestamp(params['updated'])
     return model.save(doc)
Пример #5
0
    def create(self, **kwargs):

        model = {}
        for prop in self.create_props:
            prop_value = kwargs.get(prop['name'], prop.get('default'))
            if prop_value is not None:
                if prop.get('type') == 'file':
                    file = File().load(prop_value,
                                       user=getCurrentUser(),
                                       level=AccessType.READ)
                    if file is None:
                        raise ValidationException('File doesn\'t exists: %s' %
                                                  prop_value)

                    if not isinstance(prop_value, ObjectId):
                        prop_value = ObjectId(prop_value)
                elif prop.get('type') == ObjectId:
                    if isinstance(prop_value, list):
                        prop_value = [ObjectId(x) for x in prop_value]
                    else:
                        prop_value = ObjectId(prop_value)
                elif prop.get('type') == 'timestamp':
                    prop_value = parseTimestamp(prop_value)

                model[prop['name']] = prop_value

        self.setPublic(model, public=kwargs.get('public', False))
        user = kwargs.get('user')
        self.setUserAccess(model, user=user, level=AccessType.ADMIN)
        model['owner'] = user['_id']
        if edp_group() is not None:
            self.setGroupAccess(model, edp_group(), AccessType.ADMIN)

        saved_model = self.save(model)

        # Now spawn thumbnail jobs if the model contains any image
        for prop in self.create_props:
            prop_value = kwargs.get(prop['name'], prop.get('default'))
            if prop_value is not None and prop.get('type') == 'file':
                file = File().load(prop_value,
                                   user=getCurrentUser(),
                                   level=AccessType.READ)
                mime_type = file.get('mimeType', '')
                if mime_type is not None and mime_type.startswith('image/'):
                    self._create_thumbnail(file, saved_model, prop['name'],
                                           user)

        return saved_model
Пример #6
0
    def testUploadDataset(self):
        File = self.model('file')
        Folder = self.model('folder')
        Group = self.model('group')
        Upload = self.model('upload')
        User = self.model('user', 'isic_archive')

        # Create a reviewer user that will receive notification emails
        resp = self.request(path='/user',
                            method='POST',
                            params={
                                'email': '*****@*****.**',
                                'login': '******',
                                'firstName': 'reviewer',
                                'lastName': 'user',
                                'password': '******'
                            })
        self.assertStatusOk(resp)
        reviewerUser = User.findOne({'login': '******'})
        reviewersGroup = Group.findOne({'name': 'Dataset QC Reviewers'})
        Group.addUser(reviewersGroup, reviewerUser, level=AccessType.READ)

        # Create an uploader user
        resp = self.request(path='/user',
                            method='POST',
                            params={
                                'email': '*****@*****.**',
                                'login': '******',
                                'firstName': 'uploader',
                                'lastName': 'user',
                                'password': '******'
                            })
        self.assertStatusOk(resp)
        uploaderUser = User.findOne({'login': '******'})
        contributorsGroup = Group.findOne({'name': 'Dataset Contributors'})
        Group.addUser(contributorsGroup, uploaderUser, level=AccessType.READ)

        # Create and upload two ZIP files of images
        publicDataset = self._uploadDataset(
            uploaderUser=uploaderUser,
            zipName='test_zip_1',
            zipContentNames=[
                'test_1_small_1.jpg', 'test_1_small_2.jpg',
                'test_1_large_1.jpg'
            ],
            datasetName='test_dataset_1',
            datasetDescription='A public test dataset')
        privateDataset = self._uploadDataset(
            uploaderUser=uploaderUser,
            zipName='test_zip_2',
            zipContentNames=['test_1_small_3.jpg', 'test_1_large_2.jpg'],
            datasetName='test_dataset_2',
            datasetDescription='A private test dataset')

        # Ensure that ordinary users aren't getting review tasks
        resp = self.request(path='/task/me/review', method='GET')
        self.assertStatus(resp, 401)
        resp = self.request(path='/task/me/review',
                            method='GET',
                            user=uploaderUser)
        self.assertStatus(resp, 403)

        # Ensure that reviewer users are getting tasks
        resp = self.request(path='/task/me/review',
                            method='GET',
                            user=reviewerUser)
        self.assertStatusOk(resp)
        reviewTasks = resp.json
        self.assertEqual(len(reviewTasks), 2)
        self.assertIn(
            {
                'dataset': {
                    '_id': str(publicDataset['_id']),
                    'name': publicDataset['name']
                },
                'count': 3
            }, reviewTasks)
        self.assertIn(
            {
                'dataset': {
                    '_id': str(privateDataset['_id']),
                    'name': privateDataset['name']
                },
                'count': 2
            }, reviewTasks)

        # Ensure that review task redirects are working
        resp = self.request(path='/task/me/review/redirect',
                            method='GET',
                            user=reviewerUser)
        self.assertStatus(resp, 400)
        for reviewTask in reviewTasks:
            reviewId = reviewTask['dataset']['_id']
            resp = self.request(path='/task/me/review/redirect',
                                method='GET',
                                params={'datasetId': reviewId},
                                user=reviewerUser,
                                isJson=False)
            self.assertStatus(resp, 307)
            self.assertDictContainsSubset(
                {'Location': '/markup/gallery#/qc/%s' % reviewId},
                resp.headers)

        # Accept all images
        resp = self.request(path='/dataset/%s/review' % publicDataset['_id'],
                            method='GET',
                            user=reviewerUser)
        self.assertStatusOk(resp)
        self.assertEqual(len(resp.json), 3)
        imageIds = [image['_id'] for image in resp.json]
        resp = self.request(path='/dataset/%s/review' % publicDataset['_id'],
                            method='POST',
                            user=reviewerUser,
                            params={
                                'accepted': json.dumps(imageIds),
                                'flagged': []
                            })
        self.assertStatusOk(resp)

        # Test metadata registration
        resp = self.request(path='/folder',
                            method='POST',
                            user=uploaderUser,
                            params={
                                'parentType': 'user',
                                'parentId': str(uploaderUser['_id']),
                                'name': 'test_1_metadata_folder'
                            })
        self.assertStatusOk(resp)
        uploadCsvFolder = Folder.load(resp.json['_id'], force=True)

        # Upload the CSV metadata file
        csvPath = os.path.join(self.testDataDir, 'test_1_metadata.csv')
        with open(csvPath, 'rb') as csvStream:
            metadataFile = Upload.uploadFromFile(obj=csvStream,
                                                 size=os.path.getsize(csvPath),
                                                 name='test_1_metadata.csv',
                                                 parentType='folder',
                                                 parent=uploadCsvFolder,
                                                 user=uploaderUser,
                                                 mimeType='text/csv')

        # Attempt to register metadata as invalid users
        resp = self.request(path='/dataset/%s/metadata' % publicDataset['_id'],
                            method='POST',
                            params={'metadataFileId': metadataFile['_id']})
        self.assertStatus(resp, 401)
        resp = self.request(path='/dataset/%s/metadata' % publicDataset['_id'],
                            method='POST',
                            user=reviewerUser,
                            params={'metadataFileId': metadataFile['_id']})
        self.assertStatus(resp, 403)

        # Attempt to register metadata with invalid parameters
        resp = self.request(path='/dataset/%s/metadata' % publicDataset['_id'],
                            method='POST',
                            user=uploaderUser)
        self.assertStatus(resp, 400)
        self.assertIn('required', resp.json['message'].lower())
        resp = self.request(path='/dataset/%s/metadata' % publicDataset['_id'],
                            method='POST',
                            user=uploaderUser,
                            params={'metadataFileId': 'bad_id'})
        self.assertStatus(resp, 400)
        self.assertIn('invalid', resp.json['message'].lower())
        resp = self.request(
            path='/dataset/%s/metadata' % publicDataset['_id'],
            method='POST',
            user=uploaderUser,
            params={
                # TODO: find a cleaner way to pass a file with the wrong format
                'metadataFileId':
                File.findOne({'mimeType': 'application/zip'})['_id'],
            })
        self.assertStatus(resp, 400)
        self.assertIn('format', resp.json['message'].lower())

        # Attempt to list registered metadata as invalid users
        resp = self.request(path='/dataset/%s/metadata' % publicDataset['_id'],
                            method='GET')
        self.assertStatus(resp, 401)
        resp = self.request(path='/dataset/%s/metadata' % publicDataset['_id'],
                            method='GET',
                            user=uploaderUser)
        self.assertStatus(resp, 403)

        # List (empty) registered metadata
        resp = self.request(path='/dataset/%s/metadata' % publicDataset['_id'],
                            method='GET',
                            user=reviewerUser)
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, [])

        # Register metadata with dataset
        self.assertNoMail()
        resp = self.request(path='/dataset/%s/metadata' % publicDataset['_id'],
                            method='POST',
                            user=uploaderUser,
                            params={'metadataFileId': metadataFile['_id']})
        self.assertStatusOk(resp)
        # Reviewer user should receive email
        self.assertMails(count=1)

        # List registered metadata
        resp = self.request(path='/dataset/%s/metadata' % publicDataset['_id'],
                            user=reviewerUser)
        self.assertStatusOk(resp)
        self.assertIsInstance(resp.json, list)
        self.assertEqual(len(resp.json), 1)
        # Check the 'time' field separately, as we don't know what it will be
        self.assertIn('time', resp.json[0])
        self.assertLess(parseTimestamp(resp.json[0]['time']),
                        datetime.datetime.utcnow())
        self.assertDictEqual(
            {
                'file': {
                    '_id': str(metadataFile['_id']),
                    'name': metadataFile['name']
                },
                'user': {
                    '_id': str(uploaderUser['_id']),
                    'name': User.obfuscatedName(uploaderUser)
                },
                # This is actually checked above
                'time': resp.json[0]['time']
            },
            resp.json[0])

        # Test applying metadata
        resp = self.request(path='/dataset/%s/metadata/%s' %
                            (publicDataset['_id'], metadataFile['_id']),
                            method='POST',
                            user=uploaderUser,
                            params={'save': False})
        self.assertStatusOk(resp)
        self.assertIn('errors', resp.json)
        self.assertIn('warnings', resp.json)
        self.assertEqual(resp.json['errors'], [{
            'description':
            'on CSV row 5: values [u\'solar lentigo\', False] for fields [\'diagnosis\', '
            '\'melanocytic\'] are inconsistent'
        }])
        self.assertEqual(resp.json['warnings'], [{
            'description':
            'on CSV row 4: no images found that match u\'filename\': u\'test_1_small_3.jpg\''
        }, {
            'description':
            'on CSV row 6: no images found that match u\'filename\': u\'test_1_large_2.jpg\''
        }, {
            'description':
            'unrecognized field u\'age_approx\' will be added to unstructured metadata'
        }, {
            'description':
            'unrecognized field u\'isic_source_name\' will be added to unstructured metadata'
        }])
Пример #7
0
    def testFeatureset(self):
        Featureset = self.model('featureset', 'isic_archive')
        Group = self.model('group')
        Study = self.model('study', 'isic_archive')
        User = self.model('user', 'isic_archive')

        # Create a basic user
        resp = self.request(path='/user', method='POST', params={
            'email': '*****@*****.**',
            'login': '******',
            'firstName': 'basic',
            'lastName': 'user',
            'password': '******'
        })
        self.assertStatusOk(resp)
        basicUser = User.findOne({'login': '******'})

        # Create a study admin user
        resp = self.request(path='/user', method='POST', params={
            'email': '*****@*****.**',
            'login': '******',
            'firstName': 'study admin',
            'lastName': 'user',
            'password': '******'
        })
        self.assertStatusOk(resp)
        studyAdminUser = User.findOne({'login': '******'})
        studyAdminsGroup = Group.findOne({'name': 'Study Administrators'})
        Group.addUser(studyAdminsGroup, studyAdminUser, level=AccessType.READ)

        basicFeaturesetParams = {
            'name': '  Basic  ',
            'version': '1.0',
            'globalFeatures': [
                {
                    'id': 'quality',
                    'name': ['Quality'],
                    'options': [
                        {
                            'id': 'acceptable',
                            'name': 'Acceptable'
                        },
                        {
                            'id': 'unacceptable',
                            'name': 'Unacceptable'
                        }
                    ],
                    'type': 'radio'
                },
                {
                    'id': 'diagnosis',
                    'name': ['Diagnosis'],
                    'options': [
                        {
                            'id': 'benign',
                            'name': 'Benign'
                        },
                        {
                            'id': 'indeterminate',
                            'name': 'Indeterminate'
                        },
                        {
                            'id': 'malignant',
                            'name': 'Malignant'
                        }
                    ],
                    'type': 'radio'
                }
            ],
            'localFeatures': [
                {
                    'id': 'lesion',
                    'name': ['Lesion'],
                    'type': 'superpixel'
                },
                {
                    'id': 'skin',
                    'name': ['Normal Skin'],
                    'type': 'superpixel'
                }
            ]
        }

        # Try to create a featureset as anonymous
        resp = self.request(
            path='/featureset', method='POST', params=basicFeaturesetParams)
        self.assertStatus(resp, 401)

        # Try to create a featureset without privileges
        resp = self.request(
            path='/featureset', method='POST', user=basicUser,
            params=basicFeaturesetParams)
        self.assertStatus(resp, 403)

        # Try to create a featureset with an empty name
        tempFeaturesetParams = basicFeaturesetParams.copy()
        tempFeaturesetParams['name'] = ''
        resp = self.request(
            path='/featureset', method='POST', user=studyAdminUser,
            type='application/json', body=json.dumps(tempFeaturesetParams))
        self.assertStatus(resp, 400)

        # Try to create a featureset with an invalid version
        tempFeaturesetParams = basicFeaturesetParams.copy()
        tempFeaturesetParams['version'] = 'foo'
        resp = self.request(
            path='/featureset', method='POST', user=studyAdminUser,
            type='application/json', body=json.dumps(tempFeaturesetParams))
        self.assertStatus(resp, 400)

        # TODO: Try to create a featureset with invalid features

        # List all (nonexistent) featuresets
        resp = self.request(
            path='/featureset', method='GET')
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, [])

        # Create a valid featureset
        resp = self.request(
            path='/featureset', method='POST', user=studyAdminUser,
            type='application/json', body=json.dumps(basicFeaturesetParams))
        self.assertStatusOk(resp)
        # Lookup the database entry, for access to non-deterministic details
        # like '_id' and 'created'
        basicFeatureset = Featureset.load(resp.json['_id'])

        # Check the list of all featuresets
        resp = self.request(
            path='/featureset', method='GET')
        self.assertStatusOk(resp)
        self.assertIsInstance(resp.json, list)
        self.assertEqual(len(resp.json), 1)
        self.assertDictEqual({
            '_id': str(basicFeatureset['_id']),
            'name': basicFeaturesetParams['name'].strip(),
            'version': float(basicFeaturesetParams['version']),
        }, resp.json[0])

        # Check featureset details as anonymous
        resp = self.request(
            path='/featureset/%s' % basicFeatureset['_id'], method='GET')
        self.assertStatusOk(resp)
        # Parse the "created" field first, to make comparison easier
        self.assertIn('created', resp.json)
        resp.json['created'] = parseTimestamp(resp.json['created'])
        self.assertDictEqual({
            '_id': str(basicFeatureset['_id']),
            '_modelType': 'featureset',
            'name': basicFeaturesetParams['name'].strip(),
            'version': float(basicFeaturesetParams['version']),
            'created': basicFeatureset['created'],
            'creator': {
                '_id': str(studyAdminUser['_id']),
                'name': User.obfuscatedName(studyAdminUser)
            },
            'globalFeatures': basicFeaturesetParams['globalFeatures'],
            'localFeatures': basicFeaturesetParams['localFeatures']
        }, resp.json)

        # Ensure that normal users don't get private creator info
        resp = self.request(
            path='/featureset/%s' % basicFeatureset['_id'], method='GET',
            user=basicUser)
        self.assertStatusOk(resp)
        self.assertDictEqual({
            '_id': str(studyAdminUser['_id']),
            'name': User.obfuscatedName(studyAdminUser)
        }, resp.json['creator'])

        # Ensure that study admin users do get private creator info
        resp = self.request(
            path='/featureset/%s' % basicFeatureset['_id'], method='GET',
            user=studyAdminUser)
        self.assertStatusOk(resp)
        self.assertDictEqual({
            '_id': str(studyAdminUser['_id']),
            'name': User.obfuscatedName(studyAdminUser),
            'firstName': studyAdminUser['firstName'],
            'lastName': studyAdminUser['lastName'],
            'login': studyAdminUser['login']
        }, resp.json['creator'])

        # Try to delete a featureset as anonymous
        resp = self.request(
            path='/featureset/%s' % basicFeatureset['_id'], method='DELETE')
        self.assertStatus(resp, 401)

        # Try to delete a featureset without privileges
        resp = self.request(
            path='/featureset/%s' % basicFeatureset['_id'], method='DELETE',
            user=basicUser)
        self.assertStatus(resp, 403)

        # Try to delete a featureset being used by a study
        resp = self.request(
            path='/study', method='POST', user=studyAdminUser,
            type='application/json', body=json.dumps({
                'name': 'Test Study',
                'featuresetId': str(basicFeatureset['_id']),
                'userIds': [],
                'imageIds': []
            }))
        self.assertStatusOk(resp)
        testStudy = Study.load(resp.json['_id'], force=True)
        resp = self.request(
            path='/featureset/%s' % basicFeatureset['_id'], method='DELETE',
            user=studyAdminUser)
        self.assertStatus(resp, 409)
        resp = self.request(
            path='/featureset', method='GET')
        self.assertStatusOk(resp)
        self.assertEqual(len(resp.json), 1)

        # TODO: Use the Study API, once it exists
        Study.remove(testStudy)

        # Delete an unused featureset
        resp = self.request(
            path='/featureset/%s' % basicFeatureset['_id'], method='DELETE',
            user=studyAdminUser, isJson=False)
        self.assertStatus(resp, 204)
        resp = self.request(
            path='/featureset', method='GET')
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, [])
Пример #8
0
    def testFeatureset(self):
        Featureset = self.model('featureset', 'isic_archive')
        Group = self.model('group')
        Study = self.model('study', 'isic_archive')
        User = self.model('user', 'isic_archive')

        # Create a basic user
        resp = self.request(path='/user',
                            method='POST',
                            params={
                                'email': '*****@*****.**',
                                'login': '******',
                                'firstName': 'basic',
                                'lastName': 'user',
                                'password': '******'
                            })
        self.assertStatusOk(resp)
        basicUser = User.findOne({'login': '******'})

        # Create a study admin user
        resp = self.request(path='/user',
                            method='POST',
                            params={
                                'email': '*****@*****.**',
                                'login': '******',
                                'firstName': 'study admin',
                                'lastName': 'user',
                                'password': '******'
                            })
        self.assertStatusOk(resp)
        studyAdminUser = User.findOne({'login': '******'})
        studyAdminsGroup = Group.findOne({'name': 'Study Administrators'})
        Group.addUser(studyAdminsGroup, studyAdminUser, level=AccessType.READ)

        basicFeaturesetParams = {
            'name':
            '  Basic  ',
            'version':
            '1.0',
            'globalFeatures': [{
                'id':
                'quality',
                'name': ['Quality'],
                'options': [{
                    'id': 'acceptable',
                    'name': 'Acceptable'
                }, {
                    'id': 'unacceptable',
                    'name': 'Unacceptable'
                }],
                'type':
                'radio'
            }, {
                'id':
                'diagnosis',
                'name': ['Diagnosis'],
                'options': [{
                    'id': 'benign',
                    'name': 'Benign'
                }, {
                    'id': 'indeterminate',
                    'name': 'Indeterminate'
                }, {
                    'id': 'malignant',
                    'name': 'Malignant'
                }],
                'type':
                'radio'
            }],
            'localFeatures': [{
                'id': 'lesion',
                'name': ['Lesion'],
                'type': 'superpixel'
            }, {
                'id': 'skin',
                'name': ['Normal Skin'],
                'type': 'superpixel'
            }]
        }

        # Try to create a featureset as anonymous
        resp = self.request(path='/featureset',
                            method='POST',
                            params=basicFeaturesetParams)
        self.assertStatus(resp, 401)

        # Try to create a featureset without privileges
        resp = self.request(path='/featureset',
                            method='POST',
                            user=basicUser,
                            params=basicFeaturesetParams)
        self.assertStatus(resp, 403)

        # Try to create a featureset with an empty name
        tempFeaturesetParams = basicFeaturesetParams.copy()
        tempFeaturesetParams['name'] = ''
        resp = self.request(path='/featureset',
                            method='POST',
                            user=studyAdminUser,
                            type='application/json',
                            body=json.dumps(tempFeaturesetParams))
        self.assertStatus(resp, 400)

        # Try to create a featureset with an invalid version
        tempFeaturesetParams = basicFeaturesetParams.copy()
        tempFeaturesetParams['version'] = 'foo'
        resp = self.request(path='/featureset',
                            method='POST',
                            user=studyAdminUser,
                            type='application/json',
                            body=json.dumps(tempFeaturesetParams))
        self.assertStatus(resp, 400)

        # TODO: Try to create a featureset with invalid features

        # List all (nonexistent) featuresets
        resp = self.request(path='/featureset', method='GET')
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, [])

        # Create a valid featureset
        resp = self.request(path='/featureset',
                            method='POST',
                            user=studyAdminUser,
                            type='application/json',
                            body=json.dumps(basicFeaturesetParams))
        self.assertStatusOk(resp)
        # Lookup the database entry, for access to non-deterministic details
        # like '_id' and 'created'
        basicFeatureset = Featureset.load(resp.json['_id'])

        # Check the list of all featuresets
        resp = self.request(path='/featureset', method='GET')
        self.assertStatusOk(resp)
        self.assertIsInstance(resp.json, list)
        self.assertEqual(len(resp.json), 1)
        self.assertDictEqual(
            {
                '_id': str(basicFeatureset['_id']),
                'name': basicFeaturesetParams['name'].strip(),
                'version': float(basicFeaturesetParams['version']),
            }, resp.json[0])

        # Check featureset details as anonymous
        resp = self.request(path='/featureset/%s' % basicFeatureset['_id'],
                            method='GET')
        self.assertStatusOk(resp)
        # Parse the "created" field first, to make comparison easier
        self.assertIn('created', resp.json)
        resp.json['created'] = parseTimestamp(resp.json['created'])
        self.assertDictEqual(
            {
                '_id': str(basicFeatureset['_id']),
                '_modelType': 'featureset',
                'name': basicFeaturesetParams['name'].strip(),
                'version': float(basicFeaturesetParams['version']),
                'created': basicFeatureset['created'],
                'creator': {
                    '_id': str(studyAdminUser['_id']),
                    'name': User.obfuscatedName(studyAdminUser)
                },
                'globalFeatures': basicFeaturesetParams['globalFeatures'],
                'localFeatures': basicFeaturesetParams['localFeatures']
            }, resp.json)

        # Ensure that normal users don't get private creator info
        resp = self.request(path='/featureset/%s' % basicFeatureset['_id'],
                            method='GET',
                            user=basicUser)
        self.assertStatusOk(resp)
        self.assertDictEqual(
            {
                '_id': str(studyAdminUser['_id']),
                'name': User.obfuscatedName(studyAdminUser)
            }, resp.json['creator'])

        # Ensure that study admin users do get private creator info
        resp = self.request(path='/featureset/%s' % basicFeatureset['_id'],
                            method='GET',
                            user=studyAdminUser)
        self.assertStatusOk(resp)
        self.assertDictEqual(
            {
                '_id': str(studyAdminUser['_id']),
                'name': User.obfuscatedName(studyAdminUser),
                'firstName': studyAdminUser['firstName'],
                'lastName': studyAdminUser['lastName'],
                'login': studyAdminUser['login']
            }, resp.json['creator'])

        # Try to delete a featureset as anonymous
        resp = self.request(path='/featureset/%s' % basicFeatureset['_id'],
                            method='DELETE')
        self.assertStatus(resp, 401)

        # Try to delete a featureset without privileges
        resp = self.request(path='/featureset/%s' % basicFeatureset['_id'],
                            method='DELETE',
                            user=basicUser)
        self.assertStatus(resp, 403)

        # Try to delete a featureset being used by a study
        resp = self.request(path='/study',
                            method='POST',
                            user=studyAdminUser,
                            type='application/json',
                            body=json.dumps({
                                'name':
                                'Test Study',
                                'featuresetId':
                                str(basicFeatureset['_id']),
                                'userIds': [],
                                'imageIds': []
                            }))
        self.assertStatusOk(resp)
        testStudy = Study.load(resp.json['_id'], force=True)
        resp = self.request(path='/featureset/%s' % basicFeatureset['_id'],
                            method='DELETE',
                            user=studyAdminUser)
        self.assertStatus(resp, 409)
        resp = self.request(path='/featureset', method='GET')
        self.assertStatusOk(resp)
        self.assertEqual(len(resp.json), 1)

        # TODO: Use the Study API, once it exists
        Study.remove(testStudy)

        # Delete an unused featureset
        resp = self.request(path='/featureset/%s' % basicFeatureset['_id'],
                            method='DELETE',
                            user=studyAdminUser,
                            isJson=False)
        self.assertStatus(resp, 204)
        resp = self.request(path='/featureset', method='GET')
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, [])
Пример #9
0
    def testUploadDataset(self):
        User = self.model('user', 'isic_archive')

        # Create users
        reviewerUser = self._createReviewerUser()
        uploaderUser = self._createUploaderUser()
        adminUser = self._createSiteAdminUser()

        # Create and upload two ZIP files of images
        publicDataset = self._uploadDataset(
            uploaderUser=uploaderUser,
            zipName='test_zip_1',
            zipContentNames=[
                'test_1_small_1.jpg', 'test_1_small_2.jpg',
                'test_1_large_1.jpg'
            ],
            datasetName='test_dataset_1',
            datasetDescription='A public test dataset')
        privateDataset = self._uploadDataset(
            uploaderUser=uploaderUser,
            zipName='test_zip_2',
            zipContentNames=['test_1_small_3.jpg', 'test_1_large_2.jpg'],
            datasetName='test_dataset_2',
            datasetDescription='A private test dataset')

        # Ensure that ordinary users aren't getting review tasks
        resp = self.request(path='/task/me/review', method='GET')
        self.assertStatus(resp, 401)
        resp = self.request(path='/task/me/review',
                            method='GET',
                            user=uploaderUser)
        self.assertStatus(resp, 403)

        # Ensure that reviewer users are getting tasks
        resp = self.request(path='/task/me/review',
                            method='GET',
                            user=reviewerUser)
        self.assertStatusOk(resp)
        reviewTasks = resp.json
        self.assertEqual(len(reviewTasks), 2)
        self.assertIn(
            {
                'dataset': {
                    '_id': str(publicDataset['_id']),
                    'name': publicDataset['name']
                },
                'count': 3
            }, reviewTasks)
        self.assertIn(
            {
                'dataset': {
                    '_id': str(privateDataset['_id']),
                    'name': privateDataset['name']
                },
                'count': 2
            }, reviewTasks)

        # Ensure that review task redirects are working
        resp = self.request(path='/task/me/review/redirect',
                            method='GET',
                            user=reviewerUser)
        self.assertStatus(resp, 400)
        for reviewTask in reviewTasks:
            reviewId = reviewTask['dataset']['_id']
            resp = self.request(path='/task/me/review/redirect',
                                method='GET',
                                params={'datasetId': reviewId},
                                user=reviewerUser,
                                isJson=False)
            self.assertStatus(resp, 307)
            self.assertDictContainsSubset(
                {'Location': '/#tasks/review/%s' % reviewId}, resp.headers)

        # Accept all images
        resp = self.request(path='/dataset/%s/review' % publicDataset['_id'],
                            method='GET',
                            user=reviewerUser)
        self.assertStatusOk(resp)
        self.assertEqual(len(resp.json), 3)
        imageIds = [image['_id'] for image in resp.json]
        resp = self.request(path='/dataset/%s/review' % publicDataset['_id'],
                            method='POST',
                            user=reviewerUser,
                            params={
                                'accepted': json.dumps(imageIds),
                                'flagged': []
                            })
        self.assertStatusOk(resp)

        # Attempt to register metadata as invalid users
        csvPath = os.path.join(self.testDataDir, 'test_1_metadata.csv')
        with open(csvPath, 'rb') as csvStream:
            resp = self.request(path='/dataset/%s/metadata' %
                                publicDataset['_id'],
                                method='POST',
                                body=csvStream.read(),
                                type='text/csv',
                                params={'filename': 'test_1_metadata.csv'})
            self.assertStatus(resp, 401)

        # Attempt to register metadata with invalid parameters
        with open(csvPath, 'rb') as csvStream:
            resp = self.request(path='/dataset/%s/metadata' %
                                publicDataset['_id'],
                                method='POST',
                                body=csvStream.read(),
                                type='text/csv',
                                user=uploaderUser)
            self.assertStatus(resp, 400)
        self.assertIn('"filename" is required', resp.json['message'].lower())
        with open(csvPath, 'rb') as csvStream:
            resp = self.request(path='/dataset/%s/metadata' %
                                publicDataset['_id'],
                                method='POST',
                                body=csvStream.read(),
                                type='text/csv',
                                user=uploaderUser,
                                params={'filename': ' '})
        self.assertStatus(resp, 400)
        self.assertIn('filename must be specified',
                      resp.json['message'].lower())

        # Attempt to list registered metadata as invalid users
        resp = self.request(path='/dataset/%s/metadata' % publicDataset['_id'],
                            method='GET')
        self.assertStatus(resp, 401)
        resp = self.request(path='/dataset/%s/metadata' % publicDataset['_id'],
                            method='GET',
                            user=uploaderUser)
        self.assertStatus(resp, 403)

        # List (empty) registered metadata
        resp = self.request(path='/dataset/%s/metadata' % publicDataset['_id'],
                            method='GET',
                            user=reviewerUser)
        self.assertStatusOk(resp)
        self.assertEqual(resp.json, [])

        # Register metadata with dataset
        self.assertNoMail()
        with open(csvPath, 'rb') as csvStream:
            resp = self.request(path='/dataset/%s/metadata' %
                                publicDataset['_id'],
                                method='POST',
                                body=csvStream.read(),
                                type='text/csv',
                                isJson=False,
                                user=uploaderUser,
                                params={'filename': 'test_1_metadata.csv'})
            self.assertStatusOk(resp)
            # Reviewer user should receive email
            self.assertMails(count=1)

        # List registered metadata
        resp = self.request(path='/dataset/%s/metadata' % publicDataset['_id'],
                            user=reviewerUser)
        self.assertStatusOk(resp)
        self.assertIsInstance(resp.json, list)
        self.assertEqual(len(resp.json), 1)

        # Check file field
        self.assertIn('file', resp.json[0])
        self.assertIn('_id', resp.json[0]['file'])
        self.assertIn('name', resp.json[0]['file'])
        self.assertEqual('test_1_metadata.csv', resp.json[0]['file']['name'])
        self.assertIn('user', resp.json[0])

        # Check user field
        self.assertDictEqual(
            {
                '_id': str(uploaderUser['_id']),
                'name': User.obfuscatedName(uploaderUser)
            }, resp.json[0]['user'])

        # Check time field
        self.assertIn('time', resp.json[0])
        self.assertLess(parseTimestamp(resp.json[0]['time']),
                        datetime.datetime.utcnow())
        metadataFileId = resp.json[0]['file']['_id']

        # Test downloading metadata as invalid users
        resp = self.request(path='/dataset/%s/metadata/%s/download' %
                            (publicDataset['_id'], metadataFileId),
                            method='GET',
                            isJson=False)
        self.assertStatus(resp, 401)
        resp = self.request(path='/dataset/%s/metadata/%s/download' %
                            (publicDataset['_id'], metadataFileId),
                            method='GET',
                            user=uploaderUser,
                            isJson=False)
        self.assertStatus(resp, 403)

        # Test downloading metadata
        resp = self.request(path='/dataset/%s/metadata/%s/download' %
                            (publicDataset['_id'], metadataFileId),
                            method='GET',
                            user=reviewerUser,
                            isJson=False)
        with open(csvPath, 'rb') as csvStream:
            self.assertEqual(csvStream.read(), self.getBody(resp))

        # Test applying metadata
        resp = self.request(path='/dataset/%s/metadata/%s/apply' %
                            (publicDataset['_id'], metadataFileId),
                            method='POST',
                            user=uploaderUser,
                            params={'save': False})
        self.assertStatus(resp, 403)
        resp = self.request(path='/dataset/%s/metadata/%s/apply' %
                            (publicDataset['_id'], metadataFileId),
                            method='POST',
                            user=reviewerUser,
                            params={'save': False})
        self.assertStatusOk(resp)
        self.assertIn('errors', resp.json)
        self.assertIn('warnings', resp.json)
        self.assertEqual(0, len(resp.json['errors']))
        self.assertEqual(resp.json['warnings'], [{
            'description':
            'on CSV row 4: no images found that match u\'filename\': u\'test_1_small_3.jpg\''
        }, {
            'description':
            'on CSV row 6: no images found that match u\'filename\': u\'test_1_large_2.jpg\''
        }, {
            'description':
            'unrecognized field u\'age_approx\' will be added to unstructured metadata'
        }, {
            'description':
            'unrecognized field u\'isic_source_name\' will be added to unstructured metadata'
        }])

        # Test removing metadata as site admin
        resp = self.request(path='/dataset/%s/metadata/%s' %
                            (publicDataset['_id'], metadataFileId),
                            method='DELETE',
                            user=adminUser,
                            isJson=False)
        self.assertStatus(resp, 204)
        resp = self.request(path='/dataset/%s/metadata' % publicDataset['_id'],
                            user=reviewerUser)
        self.assertStatusOk(resp)
        self.assertIsInstance(resp.json, list)
        self.assertEqual(len(resp.json), 0)