Ejemplo n.º 1
0
    def put(self, item_id, folder_id='0'):
        """
        :param item_id:
        :param folder_id: id of the folder, in a style like 'workspace_14__content_1586'
        :return:
        """
        # TODO - SECURE THIS
        workspace = tmpl_context.workspace
        item_id = int(item_id)
        new_workspace, new_parent = convert_id_into_instances(folder_id)

        if new_workspace != workspace:
            # check that user is at least
            # - content manager in current workspace
            # - content manager in new workspace
            user = tmpl_context.current_user

            if user.get_role(workspace) < UserRoleInWorkspace.CONTENT_MANAGER:
                tg.flash(_('You are not allowed '
                           'to move this folder'), CST.STATUS_ERROR)
                tg.redirect(self.parent_controller.url(item_id))

            if user.get_role(new_workspace) < UserRoleInWorkspace.CONTENT_MANAGER:
                tg.flash(_('You are not allowed to move '
                           'this folder to this workspace'), CST.STATUS_ERROR)
                tg.redirect(self.parent_controller.url(item_id))

            api = ContentApi(tmpl_context.current_user)
            item = api.get_one(item_id, ContentType.Any, workspace)
            api.move_recursively(item, new_parent, new_workspace)

            next_url = tg.url('/workspaces/{}/folders/{}'.format(
                new_workspace.workspace_id, item_id))
            if new_parent:
                tg.flash(_('Item moved to {} (workspace {})').format(
                    new_parent.label,
                    new_workspace.label), CST.STATUS_OK)
            else:
                tg.flash(_('Item moved to workspace {}').format(
                    new_workspace.label))

            tg.redirect(next_url)

        else:
            # Default move inside same workspace
            api = ContentApi(tmpl_context.current_user)
            item = api.get_one(item_id, ContentType.Any, workspace)
            api.move(item, new_parent)
            next_url = self.parent_controller.url(item_id)
            if new_parent:
                tg.flash(_('Item moved to {}').format(new_parent.label), CST.STATUS_OK)
            else:
                tg.flash(_('Item moved to workspace root'))

            tg.redirect(next_url)
Ejemplo n.º 2
0
    def put(self, item_id, folder_id='0'):
        """
        :param item_id:
        :param folder_id: id of the folder, in a style like
                          'workspace_14__content_1586'
        :return:
        """
        # TODO - SECURE THIS
        workspace = tmpl_context.workspace
        item_id = int(item_id)
        new_workspace, new_parent = convert_id_into_instances(folder_id)

        if new_workspace != workspace:
            # check that user is at least
            # - content manager in current workspace
            # - content manager in new workspace
            user = tmpl_context.current_user

            if user.get_role(workspace) < UserRoleInWorkspace.CONTENT_MANAGER:
                tg.flash(_('You are not allowed '
                           'to move this folder'), CST.STATUS_ERROR)
                tg.redirect(self.parent_controller.url(item_id))

            if user.get_role(
                    new_workspace) < UserRoleInWorkspace.CONTENT_MANAGER:
                tg.flash(
                    _('You are not allowed to move '
                      'this folder to this workspace'), CST.STATUS_ERROR)
                tg.redirect(self.parent_controller.url(item_id))

            api = ContentApi(tmpl_context.current_user)
            item = api.get_one(item_id, ContentType.Any, workspace)

            with new_revision(item):
                api.move_recursively(item, new_parent, new_workspace)

            next_url = tg.url('/workspaces/{}/folders/{}'.format(
                new_workspace.workspace_id, item_id))
            if new_parent:
                tg.flash(
                    _('Item moved to {} (workspace {})').format(
                        new_parent.label, new_workspace.label), CST.STATUS_OK)
            else:
                tg.flash(
                    _('Item moved to workspace {}').format(
                        new_workspace.label))

            tg.redirect(next_url)

        else:
            # Default move inside same workspace
            api = ContentApi(tmpl_context.current_user)
            item = api.get_one(item_id, ContentType.Any, workspace)
            with new_revision(item):
                api.move(item, new_parent)
            next_url = self.parent_controller.url(item_id)
            if new_parent:
                tg.flash(
                    _('Item moved to {}').format(new_parent.label),
                    CST.STATUS_OK)
            else:
                tg.flash(_('Item moved to workspace root'))

            tg.redirect(next_url)
Ejemplo n.º 3
0
class File(DAVNonCollection):
    """
    File resource corresponding to tracim's files
    """
    def __init__(self, path: str, environ: dict, content: Content):
        super(File, self).__init__(path, environ)

        self.content = content
        self.user = UserApi(None).get_one_by_email(environ['http_authenticator.username'])
        self.content_api = ContentApi(self.user)

        # this is the property that windows client except to check if the file is read-write or read-only,
        # but i wasn't able to set this property so you'll have to look into it >.>
        # self.setPropertyValue('Win32FileAttributes', '00000021')

    def __repr__(self) -> str:
        return "<DAVNonCollection: File (%d)>" % self.content.revision_id

    def getContentLength(self) -> int:
        return self.content.depot_file.file.content_length

    def getContentType(self) -> str:
        return self.content.file_mimetype

    def getCreationDate(self) -> float:
        return mktime(self.content.created.timetuple())

    def getDisplayName(self) -> str:
        return self.content.file_name

    def getLastModified(self) -> float:
        return mktime(self.content.updated.timetuple())

    def getContent(self) -> typing.BinaryIO:
        filestream = compat.BytesIO()
        filestream.write(self.content.depot_file.file.read())
        filestream.seek(0)

        return filestream

    def beginWrite(self, contentType: str=None) -> FakeFileStream:
        return FakeFileStream(
            content=self.content,
            content_api=self.content_api,
            file_name=self.content.get_label_as_file(),
            workspace=self.content.workspace,
            path=self.path
        )

    def moveRecursive(self, destpath):
        """As we support recursive move, copymovesingle won't be called, though with copy it'll be called
            but i have to check if the client ever call that function..."""
        destpath = normpath(destpath)

        invalid_path = False

        # if content is either deleted or archived, we'll check that we try moving it to the parent
        # if yes, then we'll unarchive / undelete them, else the action's not allowed
        if self.content.is_deleted or self.content.is_archived:
            # we remove all archived and deleted from the path and we check to the destpath
            # has to be equal or else path not valid
            # ex: /a/b/.deleted/resource, to be valid destpath has to be = /a/b/resource (no other solution)
            current_path = re.sub(r'/\.(deleted|archived)', '', self.path)

            if current_path == destpath:
                ManageActions(
                    ActionDescription.UNDELETION if self.content.is_deleted else ActionDescription.UNARCHIVING,
                    self.content_api,
                    self.content
                ).action()
            else:
                invalid_path = True
        # if the content is not deleted / archived, check if we're trying to delete / archive it by
        # moving it to a .deleted / .archived folder
        elif basename(dirname(destpath)) in ['.deleted', '.archived']:
            # same test as above ^
            dest_path = re.sub(r'/\.(deleted|archived)', '', destpath)

            if dest_path == self.path:
                ManageActions(
                    ActionDescription.DELETION if '.deleted' in destpath else ActionDescription.ARCHIVING,
                    self.content_api,
                    self.content
                ).action()
            else:
                invalid_path = True
        # else we check if the path is good (not at the root path / not in a deleted/archived path)
        # and we move the content
        else:
            invalid_path = any(x in destpath for x in ['.deleted', '.archived'])
            invalid_path = invalid_path or any(x in self.path for x in ['.deleted', '.archived'])
            invalid_path = invalid_path or dirname(destpath) == self.environ['http_authenticator.realm']

            if not invalid_path:
                self.move_file(destpath)

        if invalid_path:
            raise DAVError(HTTP_FORBIDDEN)

    def move_file(self, destpath):

        workspace = self.content.workspace
        parent = self.content.parent

        with new_revision(self.content):
            if basename(destpath) != self.getDisplayName():
                new_given_file_name = transform_to_bdd(basename(destpath))
                new_file_name, new_file_extension = \
                    os.path.splitext(new_given_file_name)

                self.content_api.update_content(
                    self.content,
                    new_file_name,
                )
                self.content.file_extension = new_file_extension
                self.content_api.save(self.content)
            else:
                workspace_api = WorkspaceApi(self.user)
                content_api = ContentApi(self.user)

                destination_workspace = self.provider.get_workspace_from_path(
                    destpath,
                    workspace_api,
                )

                destination_parent = self.provider.get_parent_from_path(
                    destpath,
                    content_api,
                    destination_workspace,
                )

                self.content_api.move(
                    item=self.content,
                    new_parent=destination_parent,
                    must_stay_in_same_workspace=False,
                    new_workspace=destination_workspace
                )

        transaction.commit()

    def supportRecursiveMove(self, destPath):
        return True

    def delete(self):
        ManageActions(ActionDescription.DELETION, self.content_api, self.content).action()
Ejemplo n.º 4
0
class File(DAVNonCollection):
    """
    File resource corresponding to tracim's files
    """
    def __init__(self, path: str, environ: dict, content: Content):
        super(File, self).__init__(path, environ)

        self.content = content
        self.user = UserApi(None).get_one_by_email(
            environ['http_authenticator.username'])
        self.content_api = ContentApi(self.user)

        # this is the property that windows client except to check if the file is read-write or read-only,
        # but i wasn't able to set this property so you'll have to look into it >.>
        # self.setPropertyValue('Win32FileAttributes', '00000021')

    def getPreferredPath(self):
        fix_txt = '.txt' if self.getContentType(
        ) == 'text/plain' else mimetypes.guess_extension(self.getContentType())

        if self.content.label == '' or self.path.endswith(fix_txt):
            return self.path
        else:
            return self.path + fix_txt

    def __repr__(self) -> str:
        return "<DAVNonCollection: File (%d)>" % self.content.revision_id

    def getContentLength(self) -> int:
        return len(self.content.file_content)

    def getContentType(self) -> str:
        return self.content.file_mimetype

    def getCreationDate(self) -> float:
        return mktime(self.content.created.timetuple())

    def getDisplayName(self) -> str:
        return self.content.get_label()

    def getLastModified(self) -> float:
        return mktime(self.content.updated.timetuple())

    def getContent(self):
        filestream = compat.BytesIO()
        filestream.write(self.content.file_content)
        filestream.seek(0)

        return filestream

    def beginWrite(self, contentType: str = None) -> FakeFileStream:
        return FakeFileStream(content=self.content,
                              content_api=self.content_api,
                              file_name=self.content.get_label(),
                              workspace=self.content.workspace,
                              path=self.path)

    def moveRecursive(self, destpath):
        """As we support recursive move, copymovesingle won't be called, though with copy it'll be called
            but i have to check if the client ever call that function..."""
        destpath = normpath(destpath)

        invalid_path = False

        # if content is either deleted or archived, we'll check that we try moving it to the parent
        # if yes, then we'll unarchive / undelete them, else the action's not allowed
        if self.content.is_deleted or self.content.is_archived:
            # we remove all archived and deleted from the path and we check to the destpath
            # has to be equal or else path not valid
            # ex: /a/b/.deleted/resource, to be valid destpath has to be = /a/b/resource (no other solution)
            current_path = re.sub(r'/\.(deleted|archived)', '', self.path)

            if current_path == destpath:
                ManageActions(
                    ActionDescription.UNDELETION if self.content.is_deleted
                    else ActionDescription.UNARCHIVING, self.content_api,
                    self.content).action()
            else:
                invalid_path = True
        # if the content is not deleted / archived, check if we're trying to delete / archive it by
        # moving it to a .deleted / .archived folder
        elif basename(dirname(destpath)) in ['.deleted', '.archived']:
            # same test as above ^
            dest_path = re.sub(r'/\.(deleted|archived)', '', destpath)

            if dest_path == self.path:
                ManageActions(
                    ActionDescription.DELETION
                    if '.deleted' in destpath else ActionDescription.ARCHIVING,
                    self.content_api, self.content).action()
            else:
                invalid_path = True
        # else we check if the path is good (not at the root path / not in a deleted/archived path)
        # and we move the content
        else:
            invalid_path = any(x in destpath
                               for x in ['.deleted', '.archived'])
            invalid_path = invalid_path or any(
                x in self.path for x in ['.deleted', '.archived'])
            invalid_path = invalid_path or dirname(
                destpath) == self.environ['http_authenticator.realm']

            if not invalid_path:
                self.move_file(destpath)

        if invalid_path:
            raise DAVError(HTTP_FORBIDDEN)

    def move_file(self, destpath):

        workspace = self.provider.get_workspace_from_path(
            normpath(destpath), WorkspaceApi(self.user))

        parent = self.provider.get_parent_from_path(normpath(destpath),
                                                    self.content_api,
                                                    workspace)

        with new_revision(self.content):
            if basename(destpath) != self.getDisplayName():
                self.content_api.update_content(
                    self.content,
                    re.sub('\.[^\.]+$', '',
                           self.provider.transform_to_bdd(basename(destpath))))
                self.content_api.save(self.content)
            else:
                self.content_api.move(item=self.content,
                                      new_parent=parent,
                                      must_stay_in_same_workspace=False,
                                      new_workspace=workspace)

        transaction.commit()

    def supportRecursiveMove(self, destPath):
        return True

    def delete(self):
        ManageActions(ActionDescription.DELETION, self.content_api,
                      self.content).action()