def parse_documents(request, context, action): documents = [] if (request['REQUEST_METHOD'] == 'GET' or request['REQUEST_METHOD'] == 'POST' and ('BODY' not in request or isinstance(json.loads(request['BODY']), list))): # Feature enabled for the wrong content type if not IBaseDocument.providedBy(context): raise NotFound # for checkout and attach actions, the document needs to have a file # for the oneoffixx action or checkout action fetched from # OfficeConnectorOneOffixxPayload, the document should be in the shadow state if not (context.has_file() or context.is_shadow_document()): raise NotFound documents.append(context) elif request['REQUEST_METHOD'] == 'POST' and 'BODY' in request: payload = json.loads(request['BODY']) paths = payload.get('documents', None) for path in paths: # Restricted traversal does not handle unicode paths document = api.content.get(path=str(path)) if document.has_file(): documents.append(document) return documents
def _recursive_rename(self, obj): """Recursively rename object and its children. Children are renamed/moved postorder, i.e. children are renamed before their parents. This is important to avoid race-conditions with the move optimization from ftw.copymovepatches: - When moving multiple items plone dispatches the move event to children in an event handler. This event handler is registered earlier than the handler from `ftw.copymovepatches`. Thus it is called before the parent item is "moved" in the catalog by `ftw.copymovepatches`. - The optimization in `ftw.copymovepatches` trips up if one of the children somehow cause their parent to be reindexed while it is moved as the catalog then treats it as a new entry. """ # We update the docproperties only when renaming a document # not when renaming the containing dossiers if IBaseDocument.providedBy(obj): getRequest().set(DISABLE_DOCPROPERTY_UPDATE_FLAG, False) else: getRequest().set(DISABLE_DOCPROPERTY_UPDATE_FLAG, True) for child in obj.getFolderContents(): self._recursive_rename(child.getObject()) return api.content.rename(obj, new_id=self.get_new_id(obj))
def parse_documents(request, context, action): documents = [] if ( request['REQUEST_METHOD'] == 'GET' or request['REQUEST_METHOD'] == 'POST' and ('BODY' not in request or isinstance(json.loads(request['BODY']), list)) ): # Feature enabled for the wrong content type if not IBaseDocument.providedBy(context): raise NotFound # for checkout and attach actions, the document needs to have a file # for the oneoffixx action or checkout action fetched from # OfficeConnectorOneOffixxPayload, the document should be in the shadow state if not (context.has_file() or context.is_shadow_document()): raise NotFound documents.append(context) elif request['REQUEST_METHOD'] == 'POST' and 'BODY' in request: payload = json.loads(request['BODY']) paths = payload.get('documents', None) for path in paths: # Restricted traversal does not handle unicode paths document = api.content.get(path=str(path)) if document.has_file(): documents.append(document) return documents
def _add_descendants(self): objs = self.obj.objectValues() for obj in objs: if IDossierMarker.providedBy(obj): self.dossiers.append(Dossier(obj, self.path)) elif IBaseDocument.providedBy(obj) and obj.get_file(): self.documents.append(Document(obj, self.path))
def parse_documents(request, context): documents = [] if (request['REQUEST_METHOD'] == 'GET' or request['REQUEST_METHOD'] == 'POST' and 'BODY' not in request): # Feature enabled for the wrong content type if not IBaseDocument.providedBy(context): raise NotFound if not context.has_file(): raise NotFound documents.append(context) if request['REQUEST_METHOD'] == 'POST' and 'BODY' in request: payload = json.loads(request['BODY']) paths = payload.get('documents', None) for path in paths: # Restricted traversal does not handle unicode paths document = api.content.get(path=str(path)) if document.has_file(): documents.append(document) return documents
def can_access_archival_file_form(user, content): """Returns True if the user has 'Modify portal content' permission in any open dossier state. And the containing dossier is - not a templatefolder - not inactive """ assert IBaseDocument.providedBy( content), 'Content needs to provide IBaseDocument' dossier = find_parent_dossier(content) if ITemplateFolder.providedBy(dossier): return False if api.content.get_state(obj=dossier) == 'dossier-state-inactive': return False wftool = api.portal.get_tool('portal_workflow') workflow_id = wftool.getChainForPortalType(dossier.portal_type)[0] user_roles = user.getRolesInContext(dossier) for open_state in DOSSIER_STATES_OPEN: state = wftool.get(workflow_id).states.get(open_state) roles_with_modify = state.permission_roles['Modify portal content'] return bool(set(roles_with_modify).intersection(user_roles)) return False
def create_subtask_response(context, event): """When adding a new task object within a task(subtask), it adds a response to the maintask. """ # the event is fired multiple times when the task was transported, so we # need to verify that the request was not called by another client. request = context.REQUEST if request.get_header('X-OGDS-AC', None) or \ request.get_header('X-OGDS-AUID', None) or \ request.get('X-CREATING-SUCCESSOR', None): return parent = aq_parent(aq_inner(context)) if ITask.providedBy(parent): if ITask.providedBy(context): transition = 'transition-add-subtask' # If the the added object is a subtask we have to make sure # that the subtask is already synced to the globalindex if not context.get_sql_object(): TaskSqlSyncer(context, event).sync() elif IBaseDocument.providedBy(context): transition = 'transition-add-document' # add a response with a link to the object add_simple_response(parent, added_object=context, transition=transition)
def validate_token(self, user, oc_url, documents, action): if IBaseDocument.providedBy(documents): documents = (documents, ) raw_token = oc_url.split(':')[-1] token = jwt.decode(raw_token, verify=False) self.assertEquals(action, token.get('action', None)) url = token.get('url', None) expected_url = '/'.join(( api.portal.get().absolute_url(), 'oc_' + action, )) self.assertEquals(expected_url, url) parsed_documents = token.get('documents', []) self.assertEquals(len(parsed_documents), len(documents)) for i, document in enumerate(documents): self.assertEquals( api.content.get_uuid(document), parsed_documents[i], ) self.assertEquals(user.id, token.get('sub', None)) expiry = int(token.get('exp', 0)) self.assertLess(int(time()), expiry) tokens = { 'raw_token': raw_token, 'token': token, } return tokens
def validate_token(self, user, oc_url, documents, action): if IBaseDocument.providedBy(documents): documents = (documents,) raw_token = oc_url.split(':')[-1] token = jwt.decode(raw_token, verify=False) self.assertEquals(action, token.get('action', None)) url = token.get('url', None) expected_url = '/'.join(( api.portal.get().absolute_url(), 'oc_' + action, )) self.assertEquals(expected_url, url) parsed_documents = token.get('documents', []) self.assertEquals(len(parsed_documents), len(documents)) for i, document in enumerate(documents): self.assertEquals( api.content.get_uuid(document), parsed_documents[i], ) self.assertEquals(user.id, token.get('sub', None)) expiry = int(token.get('exp', 0)) self.assertLess(int(time()), expiry) tokens = { 'raw_token': raw_token, 'token': token, } return tokens
def checked_out_by(item): """Return user ID of user that the document is currently checked out by, or None if the document isn't checked out (for both brains and objects). """ checked_out_by = getattr(item, 'checked_out', None) if IBaseDocument.providedBy(item): checked_out_by = item.checked_out_by() return checked_out_by
def is_or_contains_any_checked_out_document(obj): if IBaseDocument.providedBy(obj): return obj.is_checked_out() if not IContainer.providedBy(obj): return False catalog = api.portal.get_tool("portal_catalog") results = catalog(path=obj.absolute_url_path(), portal_type="opengever.document.document") return any(brain.checked_out for brain in results)
def can_access_public_trial_edit_form(user, content): """Returns True if the user has 'Modify portal content' permission in any open dossier state. And the containing dossier is - not a templatefolder - not inactive - not an inbox """ assert IBaseDocument.providedBy( content), 'Content needs to provide IBaseDocument' wftool = getToolByName(content, 'portal_workflow') dossier = find_parent_dossier(content) if ITemplateFolder.providedBy(dossier): return False if IInbox.providedBy(dossier): return False if wftool.getInfoFor(dossier, 'review_state') == 'dossier-state-inactive': return False workflow_id = wftool.getChainForPortalType(dossier.portal_type)[0] user_roles = user.getRolesInContext(dossier) has_role = False for open_state in DOSSIER_STATES_OPEN: state = wftool.get(workflow_id).states.get(open_state) if state is None: continue roles_with_modify = state.permission_roles['Modify portal content'] has_role = bool(set(roles_with_modify) & set(user_roles)) if has_role: break else: continue return has_role
def related_items(self, bidirectional=False, documents_only=False): _related_items = [] relations = IRelatedDocuments(self).relatedItems if relations: _related_items += [rel.to_object for rel in relations] if bidirectional: catalog = getUtility(ICatalog) doc_id = getUtility(IIntIds).getId(aq_inner(self)) relations = catalog.findRelations( {'to_id': doc_id, 'from_attribute': 'relatedItems'}) if documents_only: relations = filter( lambda rel: IBaseDocument.providedBy(rel.from_object), relations) _related_items += [rel.from_object for rel in relations] return _related_items
def add_object(self, obj): if IDossierMarker.providedBy(obj): self.dossiers.append(Dossier(obj, u'files')) elif IBaseDocument.providedBy(obj) and obj.get_file(): self.documents.append(Document(obj, u'files'))
def _verifyObjectPaste(self, object, validate_src=1): # Verify whether the current user is allowed to paste the # passed object into self. This is determined by checking # to see if the user could create a new object of the same # meta_type of the object passed in and checking that the # user actually is allowed to access the passed in object # in its existing context. # # Passing a false value for the validate_src argument will skip # checking the passed in object in its existing context. This is # mainly useful for situations where the passed in object has no # existing context, such as checking an object during an import # (the object will not yet have been connected to the acquisition # heirarchy). # # We also make sure that we are not pasting a checked-out document if IBaseDocument.providedBy(object) and object.is_checked_out(): raise CopyError('Checked out documents cannot be copied.') if not hasattr(object, 'meta_type'): raise CopyError(MessageDialog( title = 'Not Supported', message = ('The object <em>%s</em> does not support this' \ ' operation' % escape(absattr(object.id))), action = 'manage_main')) if not hasattr(self, 'all_meta_types'): raise CopyError( MessageDialog(title='Not Supported', message='Cannot paste into this object.', action='manage_main')) mt_permission = None meta_types = absattr(self.all_meta_types) for d in meta_types: if d['name'] == object.meta_type: mt_permission = d.get('permission') break if mt_permission is not None: sm = getSecurityManager() if sm.checkPermission(mt_permission, self): if validate_src: # Ensure the user is allowed to access the object on the # clipboard. try: parent = aq_parent(aq_inner(object)) except ConflictError: raise except Exception: parent = None if not sm.validate(None, parent, None, object): raise Unauthorized(absattr(object.id)) # --- Patch --- # Disable checking for `Delete objects` permission # if validate_src == 2: # moving # if not sm.checkPermission(delete_objects, parent): # raise Unauthorized('Delete not allowed.') # --- End Patch --- else: raise CopyError( MessageDialog( title='Insufficient Privileges', message=( 'You do not possess the %s permission in the ' 'context of the container into which you are ' 'pasting, thus you are not able to perform ' 'this operation.' % mt_permission), action='manage_main')) else: raise CopyError( MessageDialog( title='Not Supported', message=( 'The object <em>%s</em> does not support this ' 'operation.' % escape(absattr(object.id))), action='manage_main'))