def getExportJSONObject(self): sessionsFolder = self.findSessionsFolder() items = list(Folder().childItems(sessionsFolder, filters={'name': 'json'})) if not len(items): raise RestException('doesn\'t contain a json item', code=404) jsonItem = items[0] # Next TODO: read, format, and stream back the json version of the export original_json_object = json.loads(jsonItem['description']) for scan in original_json_object['scans']: experiment = Folder().findOne({ 'name': scan['experiment_id'], 'parentId': sessionsFolder['_id'] }) if not experiment: continue session = Folder().findOne({ 'name': '{0}_{1}'.format(scan['id'], scan['type']), 'parentId': experiment['_id'] }) if not session: continue scan['decision'] = convertRatingToDecision( session.get('meta', {}).get('rating', None)) scan['note'] = session.get('meta', {}).get('note', None) return original_json_object
def path_from_id(object_id): if str(object_id).startswith("wtlocal:"): decoded = base64.b64decode(object_id[8:]).decode() path, root_id = decoded.split("|") else: root_folder = Folder().load(object_id, force=True) or {} path = root_folder.get("fsPath") # only exists on virtual folders root_id = str(root_folder.get("_id")) if path: path = pathlib.Path(path) return path, root_id
def _virtualChildItems(self, event): params = event.info['params'] if 'folderId' not in params: return # This is not a child listing request user = self.getCurrentUser() folder = Folder().load(params['folderId'], user=user, level=AccessType.READ) if not folder.get('isVirtual') or 'virtualItemsQuery' not in folder: return # Parent is not a virtual folder, proceed as normal limit, offset, sort = self.getPagingParameters(params, defaultSortField='name') q = json_util.loads(folder['virtualItemsQuery']) if 'virtualItemsSort' in folder: sort = json.loads(folder['virtualItemsSort']) item = Item() # These items may reside in folders that the user cannot read, so we must filter items = item.filterResultsByPermission(item.find(q, sort=sort), user, level=AccessType.READ, limit=limit, offset=offset) event.preventDefault().addResponse([item.filter(i, user) for i in items])
def _copyAnnotationsFromOtherItem(self, srcItemId, destItem): # Copy annotations from the original item to this one query = {'_active': {'$ne': False}, 'itemId': srcItemId} annotations = Annotation().find(query) total = annotations.count() if not total: return destItemId = destItem['_id'] folder = Folder().load(destItem['folderId'], force=True) count = 0 for annotation in annotations: logger.info('Copying annotation %d of %d from %s to %s', count + 1, total, srcItemId, destItemId) # Make sure we have the elements annotation = Annotation().load(annotation['_id'], force=True) # This could happen, for instance, if the annotation were deleted # while we are copying other annotations. if annotation is None: continue annotation['itemId'] = destItemId del annotation['_id'] # Remove existing permissionsi, then give it the same permissions # as the item's folder. annotation.pop('access', None) self.copyAccessPolicies(destItem, annotation, save=False) self.setPublic(annotation, folder.get('public'), save=False) Annotation().save(annotation) count += 1 logger.info('Copied %d annotations from %s to %s ', count, srcItemId, destItemId)
def validate(self, tale): if 'iframe' not in tale: tale['iframe'] = False if tale.get('format', 0) < 2: dataFolder = getOrCreateRootFolder(DATADIRS_NAME) try: origFolder = Folder().load(tale['folderId'], force=True, exc=True) except ValidationException: raise GirderException( ('Tale ({_id}) references folder ({folderId}) ' 'that does not exist').format(**tale)) if origFolder.get('creatorId'): creator = User().load(origFolder['creatorId'], force=True) else: creator = None tale['involatileData'] = [{ 'type': 'folder', 'id': tale.pop('folderId') }] newFolder = Folder().copyFolder(origFolder, parent=dataFolder, name=str(tale['_id']), creator=creator, progress=False) tale['folderId'] = newFolder['_id'] tale['format'] = _currentTaleFormat return tale
def _virtualChildItemsFind(self, params): if not params.get('folderId'): return # This is not a child listing request user = self.getCurrentUser() folder = Folder().load(params['folderId'], user=user, level=AccessType.READ) if not folder or not folder.get( 'isVirtual') or 'virtualItemsQuery' not in folder: return # Parent is not a virtual folder, proceed as normal limit, offset, sort = self.getPagingParameters(params, defaultSortField='name') q = json_util.loads(folder['virtualItemsQuery']) if 'virtualItemsSort' in folder: sort = json.loads(folder['virtualItemsSort']) # Add other parameter options with $and to ensure they don't clobber the # virtual items query. if params.get('text'): q = {'$and': [q, {'$text': {'$search': params['text']}}]} if params.get('name'): q = {'$and': [q, {'name': params['name']}]} return q, sort, user, limit, offset
def _virtualChildItems(self, event): params = event.info['params'] if not params.get('folderId'): return # This is not a child listing request user = self.getCurrentUser() folder = Folder().load(params['folderId'], user=user, level=AccessType.READ) if not folder or not folder.get('isVirtual') or 'virtualItemsQuery' not in folder: return # Parent is not a virtual folder, proceed as normal limit, offset, sort = self.getPagingParameters(params, defaultSortField='name') q = json_util.loads(folder['virtualItemsQuery']) # Add other parameter options with $and to ensure they don't clobber the # virtual items query. if params.get('text'): q = {'$and': [q, {'$text': {'$search': params['text']}}]} if params.get('name'): q = {'$and': [q, {'name': params['name']}]} if 'virtualItemsSort' in folder: sort = json.loads(folder['virtualItemsSort']) item = Item() # These items may reside in folders that the user cannot read, so we must # find with permissions items = item.findWithPermissions( q, sort=sort, user=user, level=AccessType.READ, limit=limit, offset=offset) # We have to add this here, as we can't use filtermodel since we return the # results in addResponse. if callable(getattr(items, 'count', None)): cherrypy.response.headers['Girder-Total-Count'] = items.count() items = [item.filter(i, user) for i in items] event.preventDefault().addResponse(items)
def createAnnotation(self, item, creator, annotation, public=None): now = datetime.datetime.utcnow() doc = { 'itemId': item['_id'], 'creatorId': creator['_id'], 'created': now, 'updatedId': creator['_id'], 'updated': now, 'annotation': annotation, } # copy access control from the folder containing the image folder = Folder().load(item['folderId'], force=True) self.copyAccessPolicies(src=folder, dest=doc, save=False) if public is None: public = folder.get('public', False) self.setPublic(doc, public, save=False) # give the current user admin access self.setUserAccess(doc, user=creator, level=AccessType.ADMIN, save=False) return self.save(doc)
def getExportCSV(self): def convertRatingToDecision(rating): return { None: 0, 'questionable': 0, 'good': 1, 'usableExtra': 2, 'bad': -1 }[rating] sessionsFolder = self.findSessionsFolder() items = list(Folder().childItems(sessionsFolder, filters={'name': 'csv'})) if not len(items): raise RestException('doesn\'t contain a csv item', code=404) csvItem = items[0] reader = csv.DictReader(io.StringIO(csvItem['description'])) output = io.StringIO() writer = csv.DictWriter(output, fieldnames=reader.fieldnames) writer.writeheader() for row in reader: experience = Folder().findOne({ 'name': row['xnat_experiment_id'], 'parentId': sessionsFolder['_id'] }) if not experience: continue session = Folder().findOne({ 'name': row['scan_id'] + '_' + row['scan_type'], 'parentId': experience['_id'] }) if not session: continue row['decision'] = convertRatingToDecision( session.get('meta', {}).get('rating', None)) row['scan_note'] = session.get('meta', {}).get('note', None) writer.writerow(row) return output
def tryGetExistingSessionMeta(self, sessionsFolder, experimentId, scan): experimentFolder = Folder().findOne({ 'name': experimentId, 'parentId': sessionsFolder['_id'] }) if not experimentFolder: return None sessionFolder = Folder().findOne({ 'name': scan, 'parentId': experimentFolder['_id'] }) if not sessionFolder: return None return sessionFolder.get('meta', {})
def _virtualFolderDetails(self, event): folderId = event.info['id'] user = self.getCurrentUser() folder = Folder().load(folderId, user=user, level=AccessType.READ) if not folder or not folder.get('isVirtual') or 'virtualItemsQuery' not in folder: return # Parent is not a virtual folder, proceed as normal q = json_util.loads(folder['virtualItemsQuery']) item = Item() # Virtual folders can't contain subfolders result = { 'nFolders': 0, 'nItems': item.findWithPermissions(q, user=user, level=AccessType.READ).count() } event.preventDefault().addResponse(result)
def _migrateACL(self, annotation): """ Add access control information to an annotation model. Originally annotation models were not access controlled. This function performs the migration for annotations created before this change was made. The access object is copied from the folder containing the image the annotation is attached to. In addition, the creator is given admin access. """ if annotation is None or 'access' in annotation: return annotation item = Item().load(annotation['itemId'], force=True) if item is None: logger.warning( 'Could not generate annotation ACL due to missing item %s', annotation['_id']) return annotation folder = Folder().load(item['folderId'], force=True) if folder is None: logger.warning( 'Could not generate annotation ACL due to missing folder %s', annotation['_id']) return annotation user = User().load(annotation['creatorId'], force=True) if user is None: logger.warning( 'Could not generate annotation ACL %s due to missing user %s', annotation['_id']) return annotation self.copyAccessPolicies(item, annotation, save=False) self.setUserAccess(annotation, user, AccessType.ADMIN, force=True, save=False) self.setPublic(annotation, folder.get('public'), save=False) # call the super class save method to avoid messing with elements super().save(annotation) logger.info('Generated annotation ACL for %s', annotation['_id']) return annotation
def _validateFolder(event): doc = event.info if 'isVirtual' in doc and not isinstance(doc['isVirtual'], bool): raise ValidationException('The isVirtual field must be boolean.', field='isVirtual') if doc.get('isVirtual'): # Make sure it doesn't have children if list(Folder().childItems(doc, limit=1)): raise ValidationException( 'Virtual folders may not contain child items.', field='isVirtual') if list(Folder().find( { 'parentId': doc['_id'], 'parentCollection': 'folder' }, limit=1)): raise ValidationException( 'Virtual folders may not contain child folders.', field='isVirtual') if doc['parentCollection'] == 'folder': parent = Folder().load(event.info['parentId'], force=True, exc=True) if parent.get('isVirtual'): raise ValidationException( 'You may not place folders under a virtual folder.', field='folderId') if 'virtualItemsQuery' in doc: try: json.loads(doc['virtualItemsQuery']) except (TypeError, ValueError): raise ValidationException( 'The virtual items query must be valid JSON.', field='virtualItemsQuery') if 'virtualItemsSort' in doc: try: json.loads(doc['virtualItemsSort']) except (TypeError, ValueError): raise ValidationException( 'The virtual items sort must be valid JSON.', field='virtualItemsSort')
def updateFolderAccess(self, phase, submissions): """ Synchronize access control between the phase and submission folders for the phase. Phase admins should have read access on the submission folders. """ # Get phase admin users phaseAcl = Phase().getFullAccessList(phase) phaseAdminUserIds = set([user['id'] for user in phaseAcl.get('users') if user['level'] >= AccessType.WRITE]) phaseAdminUsers = [User().load(userId, force=True, exc=True) for userId in phaseAdminUserIds] # Update submission folder ACL for current phase admins try: for sub in submissions: folder = Folder().load(sub['folderId'], force=True) if not folder: continue folderAcl = Folder().getFullAccessList(folder) # Revoke access to users who are not phase admins; ignore folder # owner usersToRemove = [User().load(user['id'], force=True, exc=True) for user in folderAcl.get('users') if (user['id'] not in phaseAdminUserIds and user['id'] != folder['creatorId'])] for user in usersToRemove: Folder().setUserAccess(folder, user, None) # Add access to phase admins; ignore folder owner usersToAdd = [user for user in phaseAdminUsers if user['_id'] != folder['creatorId']] for user in usersToAdd: Folder().setUserAccess(folder, user, AccessType.READ) # Save folder if access changed if usersToRemove or usersToAdd: Folder().save(folder, validate=False) except TypeError: raise ValidationException('A list of submissions is required.')
def _virtualChildItems(self, event): params = event.info['params'] if 'folderId' not in params: return # This is not a child listing request user = self.getCurrentUser() folder = Folder().load(params['folderId'], user=user, level=AccessType.READ) if not folder.get('isVirtual') or 'virtualItemsQuery' not in folder: return # Parent is not a virtual folder, proceed as normal limit, offset, sort = self.getPagingParameters(params, defaultSortField='name') q = json_util.loads(folder['virtualItemsQuery']) if 'virtualItemsSort' in folder: sort = json.loads(folder['virtualItemsSort']) item = Item() # These items may reside in folders that the user cannot read, so we must filter items = item.filterResultsByPermission( item.find(q, sort=sort), user, level=AccessType.READ, limit=limit, offset=offset) event.preventDefault().addResponse([item.filter(i, user) for i in items])
def updateRunStatus(self, event): """ Event handler that updates the run status based on the recorded_run task. """ job = event.info['job'] if job['title'] == 'Recorded Run' and job.get('status') is not None: status = int(job['status']) rfolder = Folder().load(job['args'][0], force=True) # Store the previous status, if present. previousStatus = rfolder.get(FIELD_STATUS_CODE, -1) if status == JobStatus.SUCCESS: rfolder[FIELD_STATUS_CODE] = RunStatus.COMPLETED.code elif status == JobStatus.ERROR: rfolder[FIELD_STATUS_CODE] = RunStatus.FAILED.code elif status in (JobStatus.QUEUED, JobStatus.RUNNING): rfolder[FIELD_STATUS_CODE] = RunStatus.RUNNING.code # If the status changed, save the object if FIELD_STATUS_CODE in rfolder and rfolder[ FIELD_STATUS_CODE] != previousStatus: Folder().save(rfolder)
def _validateFolder(event): doc = event.info if 'isVirtual' in doc and not isinstance(doc['isVirtual'], bool): raise ValidationException('The isVirtual field must be boolean.', field='isVirtual') if doc.get('isVirtual'): # Make sure it doesn't have children if list(Folder().childItems(doc, limit=1)): raise ValidationException( 'Virtual folders may not contain child items.', field='isVirtual') if list(Folder().find({ 'parentId': doc['_id'], 'parentCollection': 'folder' }, limit=1)): raise ValidationException( 'Virtual folders may not contain child folders.', field='isVirtual') if doc['parentCollection'] == 'folder': parent = Folder().load(event.info['parentId'], force=True, exc=True) if parent.get('isVirtual'): raise ValidationException( 'You may not place folders under a virtual folder.', field='folderId') if 'virtualItemsQuery' in doc: try: json.loads(doc['virtualItemsQuery']) except (TypeError, ValueError): raise ValidationException( 'The virtual items query must be valid JSON.', field='virtualItemsQuery') if 'virtualItemsSort' in doc: try: json.loads(doc['virtualItemsSort']) except (TypeError, ValueError): raise ValidationException( 'The virtual items sort must be valid JSON.', field='virtualItemsSort')
def testCuration(self): admin, user = self.users # create a collection and a folder c1 = Collection().createCollection('c1', admin, public=True) f1 = Folder().createFolder(c1, 'f1', parentType='collection', public=False) f2 = Folder().createFolder(c1, 'f2', parentType='collection', public=False) Folder().setUserAccess(f2, user, AccessType.WRITE, True) # test initial curation values path = '/folder/%s/curation' % f1.get('_id') resp = self.request(path=path, user=admin) self.assertStatusOk(resp) self.assertEqual(resp.json['enabled'], False) self.assertEqual(resp.json['timeline'], []) # test non-admin access to private folder path = '/folder/%s/curation' % f1.get('_id') resp = self.request(path=path, user=user) self.assertStatus(resp, 403) # test non-admin access to folder with permissions path = '/folder/%s/curation' % f2.get('_id') resp = self.request(path=path, user=user) self.assertStatusOk(resp) self.assertEqual(resp.json['enabled'], False) self.assertEqual(resp.json['timeline'], []) # test non-admin unable to enable curation path = '/folder/%s/curation' % f2.get('_id') params = dict(enabled='true') resp = self.request(path=path, user=user, method='PUT', params=params) self.assertStatus(resp, 403) # test admin able to enable curation path = '/folder/%s/curation' % f2.get('_id') params = dict(enabled='true') resp = self.request(path=path, user=admin, method='PUT', params=params) self.assertStatusOk(resp) self.assertEqual(resp.json['enabled'], True) self.assertEqual(resp.json['status'], 'construction') # test non-admin unable to disable curation path = '/folder/%s/curation' % f2.get('_id') params = dict(enabled='false') resp = self.request(path=path, user=user, method='PUT', params=params) self.assertStatus(resp, 403) # test non-admin able to request approval path = '/folder/%s/curation' % f2.get('_id') params = dict(status='requested') resp = self.request(path=path, user=user, method='PUT', params=params) self.assertStatusOk(resp) self.assertEqual(resp.json['enabled'], True) self.assertEqual(resp.json['status'], 'requested') # test non-admin unable to change status path = '/folder/%s/curation' % f2.get('_id') params = dict(status='approved') resp = self.request(path=path, user=user, method='PUT', params=params) self.assertStatus(resp, 403) path = '/folder/%s/curation' % f2.get('_id') params = dict(status='construction') resp = self.request(path=path, user=user, method='PUT', params=params) self.assertStatus(resp, 403) # test admin able to approve path = '/folder/%s/curation' % f2.get('_id') params = dict(status='approved') resp = self.request(path=path, user=admin, method='PUT', params=params) self.assertStatusOk(resp) self.assertEqual(resp.json['enabled'], True) self.assertEqual(resp.json['status'], 'approved') # test timeline is correct path = '/folder/%s/curation' % f2.get('_id') resp = self.request(path=path, user=user) self.assertStatusOk(resp) self.assertEqual(len(resp.json['timeline']), 3) self.assertEqual(resp.json['timeline'][0]['oldEnabled'], False) self.assertEqual(resp.json['timeline'][0]['enabled'], True) self.assertEqual(resp.json['timeline'][0]['oldStatus'], 'construction') self.assertEqual(resp.json['timeline'][0]['status'], 'construction') self.assertEqual(resp.json['timeline'][1]['oldEnabled'], True) self.assertEqual(resp.json['timeline'][1]['enabled'], True) self.assertEqual(resp.json['timeline'][1]['oldStatus'], 'construction') self.assertEqual(resp.json['timeline'][1]['status'], 'requested') self.assertEqual(resp.json['timeline'][2]['oldEnabled'], True) self.assertEqual(resp.json['timeline'][2]['enabled'], True) self.assertEqual(resp.json['timeline'][2]['oldStatus'], 'requested') self.assertEqual(resp.json['timeline'][2]['status'], 'approved')
def _validateItem(event): parent = Folder().load(event.info['folderId'], force=True, exc=True) if parent.get('isVirtual'): raise ValidationException( 'You may not place items under a virtual folder.', field='folderId')
def testFolderAccessAndDetails(self): # create a folder to work with folder = Folder().createFolder( parent=self.admin, parentType='user', creator=self.admin, name='Folder') resp = self.request( path='/folder/%s/access' % folder['_id'], method='GET', user=self.admin) self.assertStatusOk(resp) access = resp.json self.assertEqual(access, { 'users': [{ 'login': self.admin['login'], 'level': AccessType.ADMIN, 'id': str(self.admin['_id']), 'flags': [], 'name': '%s %s' % ( self.admin['firstName'], self.admin['lastName'])}], 'groups': [] }) self.assertTrue(not folder.get('public')) # Setting the access list with bad json should throw an error resp = self.request( path='/folder/%s/access' % folder['_id'], method='PUT', user=self.admin, params={'access': 'badJSON'}) self.assertStatus(resp, 400) # Change the access to public resp = self.request( path='/folder/%s/access' % folder['_id'], method='PUT', user=self.admin, params={'access': json.dumps(access), 'public': True}) self.assertStatusOk(resp) resp = self.request( path='/folder/%s' % folder['_id'], method='GET', user=self.admin) self.assertStatusOk(resp) self.assertEqual(resp.json['public'], True) # Create an item in the folder Item().createItem(folder=folder, creator=self.admin, name='Item') # Create a public and private folder within the folder Folder().createFolder( parent=folder, parentType='folder', creator=self.admin, name='Public', public=True) Folder().createFolder( parent=folder, parentType='folder', creator=self.admin, name='Private', public=False) # Test folder details as anonymous resp = self.request( path='/folder/%s/details' % str(folder['_id'])) self.assertStatusOk(resp) self.assertEqual(resp.json['nItems'], 1) self.assertEqual(resp.json['nFolders'], 1) # Test folder details as admin resp = self.request( path='/folder/%s/details' % str(folder['_id']), user=self.admin) self.assertStatusOk(resp) self.assertEqual(resp.json['nItems'], 1) self.assertEqual(resp.json['nFolders'], 2)
def setCuration(self, folder, params): user = self.getCurrentUser() if CURATION not in folder: folder[CURATION] = dict(DEFAULTS) curation = folder[CURATION] oldCuration = dict(curation) # update enabled oldEnabled = curation.get(ENABLED, False) if ENABLED in params: self.requireAdmin(user) curation[ENABLED] = self.boolParam(ENABLED, params) enabled = curation.get(ENABLED, False) # update status oldStatus = curation.get(STATUS) if STATUS in params: # verify valid status if params[STATUS] not in [CONSTRUCTION, REQUESTED, APPROVED]: raise RestException('Invalid status parameter') # regular users can only do construction -> requested transition if curation.get(STATUS) != CONSTRUCTION or \ params[STATUS] != REQUESTED: self.requireAdmin(user) curation[STATUS] = params[STATUS] status = curation.get(STATUS) # admin enabling curation if enabled and not oldEnabled: # TODO: check if writers exist? # TODO: email writers? with self._progressContext(folder, TITLE_PRIVATE) as pc: self._setPublic(folder, False, pc) curation[ENABLE_USER_ID] = user.get('_id') self._addTimeline(oldCuration, curation, 'enabled curation') # admin reopening folder if enabled and oldStatus == APPROVED and status == CONSTRUCTION: with self._progressContext(folder, TITLE_PRIVATE) as pc: self._setPublic(folder, False, pc) curation[ENABLE_USER_ID] = user.get('_id') with self._progressContext(folder, TITLE_WRITEABLE) as pc: self._makeWriteable(folder, pc) self._addTimeline(oldCuration, curation, 'reopened folder') # admin disabling curation if not enabled and oldEnabled: self._addTimeline(oldCuration, curation, 'disabled curation') # user requesting approval if enabled and oldStatus == CONSTRUCTION and status == REQUESTED: curation[REQUEST_USER_ID] = user.get('_id') with self._progressContext(folder, TITLE_READ_ONLY) as pc: self._makeReadOnly(folder, pc) self._addTimeline(oldCuration, curation, 'requested approval') # send email to admin requesting approval self._sendMail( folder, curation.get(ENABLE_USER_ID), 'REQUEST FOR APPROVAL: ' + folder['name'], 'curation.requested.mako') # admin approving request if enabled and oldStatus == REQUESTED and status == APPROVED: with self._progressContext(folder, TITLE_PUBLIC) as pc: self._setPublic(folder, True, pc) curation[REVIEW_USER_ID] = user.get('_id') self._addTimeline(oldCuration, curation, 'approved request') # send approval notification to requestor self._sendMail( folder, curation.get(REQUEST_USER_ID), 'APPROVED: ' + folder['name'], 'curation.approved.mako') # admin rejecting request if enabled and oldStatus == REQUESTED and status == CONSTRUCTION: curation[REVIEW_USER_ID] = user.get('_id') with self._progressContext(folder, TITLE_WRITEABLE) as pc: self._makeWriteable(folder, pc) self._addTimeline(oldCuration, curation, 'rejected request') # send rejection notification to requestor self._sendMail( folder, curation.get(REQUEST_USER_ID), 'REJECTED: ' + folder['name'], 'curation.rejected.mako') folder = Folder().save(folder) curation['public'] = folder.get('public') return curation
def setCuration(self, folder, params): user = self.getCurrentUser() if CURATION not in folder: folder[CURATION] = dict(DEFAULTS) curation = folder[CURATION] oldCuration = dict(curation) # update enabled oldEnabled = curation.get(ENABLED, False) if ENABLED in params: self.requireAdmin(user) curation[ENABLED] = self.boolParam(ENABLED, params) enabled = curation.get(ENABLED, False) # update status oldStatus = curation.get(STATUS) if STATUS in params: # verify valid status if params[STATUS] not in [CONSTRUCTION, REQUESTED, APPROVED]: raise RestException('Invalid status parameter') # regular users can only do construction -> requested transition if curation.get(STATUS) != CONSTRUCTION or \ params[STATUS] != REQUESTED: self.requireAdmin(user) curation[STATUS] = params[STATUS] status = curation.get(STATUS) # admin enabling curation if enabled and not oldEnabled: # TODO: check if writers exist? # TODO: email writers? with self._progressContext(folder, TITLE_PRIVATE) as pc: self._setPublic(folder, False, pc) curation[ENABLE_USER_ID] = user.get('_id') self._addTimeline(oldCuration, curation, 'enabled curation') # admin reopening folder if enabled and oldStatus == APPROVED and status == CONSTRUCTION: with self._progressContext(folder, TITLE_PRIVATE) as pc: self._setPublic(folder, False, pc) curation[ENABLE_USER_ID] = user.get('_id') with self._progressContext(folder, TITLE_WRITEABLE) as pc: self._makeWriteable(folder, pc) self._addTimeline(oldCuration, curation, 'reopened folder') # admin disabling curation if not enabled and oldEnabled: self._addTimeline(oldCuration, curation, 'disabled curation') # user requesting approval if enabled and oldStatus == CONSTRUCTION and status == REQUESTED: curation[REQUEST_USER_ID] = user.get('_id') with self._progressContext(folder, TITLE_READ_ONLY) as pc: self._makeReadOnly(folder, pc) self._addTimeline(oldCuration, curation, 'requested approval') # send email to admin requesting approval self._sendMail(folder, curation.get(ENABLE_USER_ID), 'REQUEST FOR APPROVAL: ' + folder['name'], 'curation.requested.mako') # admin approving request if enabled and oldStatus == REQUESTED and status == APPROVED: with self._progressContext(folder, TITLE_PUBLIC) as pc: self._setPublic(folder, True, pc) curation[REVIEW_USER_ID] = user.get('_id') self._addTimeline(oldCuration, curation, 'approved request') # send approval notification to requestor self._sendMail(folder, curation.get(REQUEST_USER_ID), 'APPROVED: ' + folder['name'], 'curation.approved.mako') # admin rejecting request if enabled and oldStatus == REQUESTED and status == CONSTRUCTION: curation[REVIEW_USER_ID] = user.get('_id') with self._progressContext(folder, TITLE_WRITEABLE) as pc: self._makeWriteable(folder, pc) self._addTimeline(oldCuration, curation, 'rejected request') # send rejection notification to requestor self._sendMail(folder, curation.get(REQUEST_USER_ID), 'REJECTED: ' + folder['name'], 'curation.rejected.mako') folder = Folder().save(folder) curation['public'] = folder.get('public') return curation