Example #1
0
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
Example #2
0
    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))
Example #3
0
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
Example #4
0
 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))
Example #5
0
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
Example #6
0
    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 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
Example #8
0
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)
Example #9
0
    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
Example #10
0
 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))
Example #11
0
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)
Example #12
0
    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
Example #13
0
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
Example #14
0
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
Example #17
0
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
Example #18
0
    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
Example #19
0
    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
Example #20
0
 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'))
Example #21
0
 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'))