예제 #1
0
파일: __init__.py 프로젝트: qyqx/tracim
    def put_delete(self, item_id):
        # TODO - CHECK RIGHTS
        item_id = int(item_id)
        content_api = ContentApi(tmpl_context.current_user)
        item = content_api.get_one(item_id, self._item_type, tmpl_context.workspace)
        try:

            next_url = self._parent_url.format(item.workspace_id, item.parent_id)
            undo_url = self._std_url.format(item.workspace_id, item.parent_id, item.content_id)+'/put_delete_undo'
            msg = _('{} deleted. <a class="alert-link" href="{}">Cancel action</a>').format(self._item_type_label, undo_url)
            with new_revision(item):
                content_api.delete(item)
                content_api.save(item, ActionDescription.DELETION)

            tg.flash(msg, CST.STATUS_OK, no_escape=True)
            tg.redirect(next_url)

        except ValueError as e:
            back_url = self._std_url.format(item.workspace_id, item.parent_id, item.content_id)
            msg = _('{} not deleted: {}').format(self._item_type_label, str(e))
            tg.flash(msg, CST.STATUS_ERROR)
            tg.redirect(back_url)
예제 #2
0
    def download(self, file_id, revision_id=None):
        file_id = int(file_id)
        revision_id = int(revision_id) if revision_id != 'latest' else None
        user = tmpl_context.current_user
        workspace = tmpl_context.workspace

        content_api = ContentApi(user)
        revision_to_send = None
        if revision_id:
            item = content_api.get_one_from_revision(file_id, self._item_type,
                                                     workspace, revision_id)
        else:
            item = content_api.get_one(file_id, self._item_type, workspace)

        revision_to_send = None
        if item.revision_to_serialize <= 0:
            for revision in item.revisions:
                if not revision_to_send:
                    revision_to_send = revision

                if revision.revision_id > revision_to_send.revision_id:
                    revision_to_send = revision
        else:
            for revision in item.revisions:
                if revision.revision_id == item.revision_to_serialize:
                    revision_to_send = revision
                    break

        content_type = 'application/x-download'
        if revision_to_send.file_mimetype:
            content_type = str(revision_to_send.file_mimetype)
            tg.response.headers['Content-type'] = \
                str(revision_to_send.file_mimetype)

        tg.response.headers['Content-Type'] = content_type
        file_name = get_valid_header_file_name(revision_to_send.file_name)
        tg.response.headers['Content-Disposition'] = \
            str('attachment; filename="{}"'.format(file_name))
        return DepotManager.get().get(revision_to_send.depot_file)
예제 #3
0
파일: __init__.py 프로젝트: qyqx/tracim
    def put_delete_undo(self, item_id):
        # TODO - CHECK RIGHTS

        item_id = int(item_id)
        content_api = ContentApi(tmpl_context.current_user, True, True) # Here we do not filter deleted items
        item = content_api.get_one(item_id, self._item_type, tmpl_context.workspace)
        try:
            next_url = self._std_url.format(item.workspace_id, item.parent_id, item.content_id)
            msg = _('{} undeleted.').format(self._item_type_label)
            with new_revision(item):
                content_api.undelete(item)
                content_api.save(item, ActionDescription.UNDELETION)

            tg.flash(msg, CST.STATUS_OK)
            tg.redirect(next_url)

        except ValueError as e:
            logger.debug(self, 'Exception: {}'.format(e.__str__))
            back_url = self._parent_url.format(item.workspace_id, item.parent_id)
            msg = _('{} not un-deleted: {}').format(self._item_type_label, str(e))
            tg.flash(msg, CST.STATUS_ERROR)
            tg.redirect(back_url)
예제 #4
0
    def test_query(self):
        content1 = self.test_create()
        with new_revision(content1):
            content1.description = 'TEST_CONTENT_DESCRIPTION_1_UPDATED'
        DBSession.flush()

        content2 = self.test_create(key='2')
        with new_revision(content2):
            content2.description = 'TEST_CONTENT_DESCRIPTION_2_UPDATED'
        DBSession.flush()

        workspace1 = DBSession.query(Workspace).filter(Workspace.label == 'TEST_WORKSPACE_1').one()
        workspace2 = DBSession.query(Workspace).filter(Workspace.label == 'TEST_WORKSPACE_2').one()

        # To get Content in database we have to join Content and ContentRevisionRO with particular condition:
        # Join have to be on most recent revision
        join_sub_query = DBSession.query(ContentRevisionRO.revision_id)\
            .filter(ContentRevisionRO.content_id == Content.id)\
            .order_by(ContentRevisionRO.revision_id.desc())\
            .limit(1)\
            .correlate(Content)

        base_query = DBSession.query(Content)\
            .join(ContentRevisionRO, and_(Content.id == ContentRevisionRO.content_id,
                                          ContentRevisionRO.revision_id == join_sub_query))

        eq_(2, base_query.count())

        eq_(1, base_query.filter(Content.workspace == workspace1).count())
        eq_(1, base_query.filter(Content.workspace == workspace2).count())

        content1_from_query = base_query.filter(Content.workspace == workspace1).one()
        eq_(content1.id, content1_from_query.id)
        eq_('TEST_CONTENT_DESCRIPTION_1_UPDATED', content1_from_query.description)

        user_admin = DBSession.query(User).filter(User.email == '*****@*****.**').one()
        api = ContentApi(None)

        content1_from_api = api.get_one(content1.id, ContentType.Page, workspace1)
예제 #5
0
    def post(self, label='', file_data=None):
        # TODO - SECURE THIS
        workspace = tmpl_context.workspace
        folder = tmpl_context.folder

        api = ContentApi(tmpl_context.current_user)
        with DBSession.no_autoflush:
            file = api.create(ContentType.File, workspace, folder, label)
            api.update_file_data(file, file_data.filename, file_data.type,
                                 file_data.file.read())
            # Display error page to user if chosen label is in conflict
            if not self._path_validation.validate_new_content(file):
                DBSession.rollback()
                return render_invalid_integrity_chosen_path(
                    file.get_label_as_file(), )
        api.save(file, ActionDescription.CREATION)

        tg.flash(_('File created'), CST.STATUS_OK)
        redirect = '/workspaces/{}/folders/{}/files/{}'
        tg.redirect(
            tg.url(redirect).format(tmpl_context.workspace_id,
                                    tmpl_context.folder_id, file.content_id))
예제 #6
0
    def put(self, item_id, label='', content=''):
        # INFO - D.A. This method is a raw copy of
        # TODO - SECURE THIS
        workspace = tmpl_context.workspace

        try:
            api = ContentApi(tmpl_context.current_user)
            item = api.get_one(int(item_id), self._item_type, workspace)
            with new_revision(item):
                api.update_content(item, label, content)

                if not self._path_validation.validate_new_content(item):
                    return render_invalid_integrity_chosen_path(
                        item.get_label(), )

                api.save(item, ActionDescription.REVISION)

            msg = _('{} updated').format(self._item_type_label)
            tg.flash(msg, CST.STATUS_OK)
            tg.redirect(
                self._std_url.format(tmpl_context.workspace_id,
                                     tmpl_context.folder_id, item.content_id))

        except SameValueError as e:
            msg = _('{} not updated: the content did not change').format(
                self._item_type_label)
            tg.flash(msg, CST.STATUS_WARNING)
            tg.redirect(
                self._err_url.format(tmpl_context.workspace_id,
                                     tmpl_context.folder_id, item_id))

        except ValueError as e:
            msg = _('{} not updated - error: {}').format(
                self._item_type_label, str(e))
            tg.flash(msg, CST.STATUS_ERROR)
            tg.redirect(
                self._err_url.format(tmpl_context.workspace_id,
                                     tmpl_context.folder_id, item_id))
예제 #7
0
파일: content.py 프로젝트: qyqx/tracim
    def get_one(self, thread_id, **kwargs):
        """
        :param thread_id: content_id of Thread
        :param inverted: fill with True equivalent to invert order of comments
                         NOTE: This parameter is in kwargs because prevent URL
                         changes.
        """
        inverted = kwargs.get('inverted')
        thread_id = int(thread_id)
        user = tmpl_context.current_user
        workspace = tmpl_context.workspace

        current_user_content = Context(CTX.CURRENT_USER).toDict(user)
        current_user_content.roles.sort(key=lambda role: role.workspace.name)

        content_api = ContentApi(
            user,
            show_deleted=True,
            show_archived=True,
        )
        thread = content_api.get_one(thread_id, ContentType.Thread, workspace)

        fake_api_breadcrumb = self.get_breadcrumb(thread_id)
        fake_api_content = DictLikeClass(breadcrumb=fake_api_breadcrumb,
                                         current_user=current_user_content)
        fake_api = Context(CTX.FOLDER).toDict(fake_api_content)

        dictified_thread = Context(CTX.THREAD).toDict(thread, 'thread')

        if inverted:
            dictified_thread.thread.history = \
                reversed(dictified_thread.thread.history)

        return DictLikeClass(
            result=dictified_thread,
            fake_api=fake_api,
            inverted=inverted,
        )
예제 #8
0
    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()
예제 #9
0
    def download_pdf_full(self, *args, **kwargs):
        file_id = int(tg.request.controller_state.routing_args.get('file_id'))

        # For now it's done through database content
        # but soon it'll be with disk access

        user = tmpl_context.current_user
        content_api = ContentApi(
            user,
            show_archived=True,
            show_deleted=True,
        )
        file_name = content_api.get_one(file_id, self._item_type).file_name
        cache_path = '/home/alexis/Pictures/cache/'

        preview_manager = PreviewManager(cache_path, create_folder=True)
        path = preview_manager.get_pdf_preview(
            file_path='/home/alexis/Pictures/cache/{}'.format(file_name), )

        tg.response.headers['Content-Disposition'] = \
            str('attachment; filename="{}"'.format(file_name))
        with open(path, 'rb') as pdf:
            return pdf.read()
예제 #10
0
파일: root.py 프로젝트: norsig/tracim
    def search(self, keywords=''):
        from tracim.lib.content import ContentApi

        user = tmpl_context.current_user
        api = ContentApi(user)

        items = []
        keyword_list = api.get_keywords(keywords)

        result = api.search(keyword_list)
        if result:
            items = result.limit(ContentApi.SEARCH_DEFAULT_RESULT_NB).all()
        api.exclude_unavailable(items)

        current_user_content = Context(CTX.CURRENT_USER).toDict(user)
        fake_api = Context(CTX.CURRENT_USER).toDict(
            {'current_user': current_user_content})

        search_results = Context(CTX.SEARCH).toDict(items, 'results',
                                                    'result_nb')
        search_results.keywords = keyword_list

        return DictLikeClass(fake_api=fake_api, search=search_results)
예제 #11
0
    def get_one(self, page_id, revision_id=None):
        page_id = int(page_id)
        user = tmpl_context.current_user
        workspace = tmpl_context.workspace
        workspace_id = tmpl_context.workspace_id

        current_user_content = Context(CTX.CURRENT_USER).toDict(user)
        current_user_content.roles.sort(key=lambda role: role.workspace.name)

        content_api = ContentApi(user)
        if revision_id:
            page = content_api.get_one_from_revision(page_id, ContentType.Page,
                                                     workspace, revision_id)
        else:
            page = content_api.get_one(page_id, ContentType.Page, workspace)

        fake_api_breadcrumb = self.get_breadcrumb(page_id)
        fake_api_content = DictLikeClass(breadcrumb=fake_api_breadcrumb,
                                         current_user=current_user_content)
        fake_api = Context(CTX.FOLDER).toDict(fake_api_content)

        dictified_page = Context(CTX.PAGE).toDict(page, 'page')
        return DictLikeClass(result=dictified_page, fake_api=fake_api)
예제 #12
0
    def treeview_children(self, id='#',
                          ignore_id=None,
                          allowed_content_types = None):
        """
        id must be "#" or something like "workspace_3__document_8"
        """
        if id=='#':
            return self.treeview_root()

        ignore_item_ids = [int(ignore_id)] if ignore_id else []
        workspace, content = convert_id_into_instances(id)

        viewable_content_types = []
        if allowed_content_types:
            viewable_content_types = allowed_content_types.split(',')
        else:
            viewable_content_types = self._get_treeviewable_content_types_or_none()
        contents = ContentApi(tmpl_context.current_user).get_child_folders(content, workspace, [], ignore_item_ids, viewable_content_types)
        # This allow to show contents and folders group by type
        sorted_contents = ContentApi.sort_content(contents)

        dictified_contents = Context(CTX.MENU_API).toDict(sorted_contents, 'd')
        return dictified_contents
예제 #13
0
    def put_unread(self, item_id):
        item_id = int(item_id)
        content_api = ContentApi(tmpl_context.current_user, True,
                                 True)  # Here we do not filter deleted items
        item = content_api.get_one(item_id, self._item_type,
                                   tmpl_context.workspace)

        item_url = self._std_url.format(item.workspace_id, item.parent_id,
                                        item.content_id)

        try:
            msg = _('{} marked unread.').format(self._item_type_label)
            content_api.mark_unread(item)

            tg.flash(msg, CST.STATUS_OK)
            tg.redirect(item_url)

        except ValueError as e:
            logger.debug(self, 'Exception: {}'.format(e.__str__))
            msg = _('{} not marked unread: {}').format(self._item_type_label,
                                                       str(e))
            tg.flash(msg, CST.STATUS_ERROR)
            tg.redirect(item_url)
예제 #14
0
 def download_pdf_one(self,
                      page_id: str,
                      revision_id: str = None,
                      *args,
                      **kwargs):
     file_id = int(tg.request.controller_state.routing_args.get('file_id'))
     revision_id = int(revision_id) if revision_id != 'latest' else None
     page = int(page_id)
     cache_path = CFG.get_instance().PREVIEW_CACHE
     preview_manager = PreviewManager(cache_path, create_folder=True)
     user = tmpl_context.current_user
     content_api = ContentApi(user, show_archived=True, show_deleted=True)
     file = content_api.get_one(file_id, self._item_type)
     if revision_id:
         file_path = content_api.get_one_revision_filepath(revision_id)
     else:
         file = content_api.get_one(file_id, self._item_type)
         file_path = content_api.get_one_revision_filepath(file.revision_id)
     path = preview_manager.get_pdf_preview(file_path=file_path, page=page)
     tg.response.headers['Content-Disposition'] = \
         'attachment; filename="{}"'.format(file.file_name)
     with open(path, 'rb') as pdf:
         return pdf.read()
예제 #15
0
파일: helpers.py 프로젝트: macntouch/tracim
def convert_id_into_instances(id: str) -> (Workspace, Content):
    """
    TODO - D.A. - 2014-10-18 - Refactor and move this function where it must be placed
    convert an id like 'workspace_<workspace_id>|content_<content_id>'
    into two objects: the given workspace instance and the given content instance
    """

    if id == '#':
        return None, None

    workspace_str = ''
    content_str = ''
    try:
        workspace_str, content_str = id.split(CST.TREEVIEW_MENU.ITEM_SEPARATOR)
    except:
        pass

    workspace = None
    content = None

    try:
        workspace_data = workspace_str.split(CST.TREEVIEW_MENU.ID_SEPARATOR)
        workspace_id = workspace_data[1]
        workspace = WorkspaceApi(
            tg.tmpl_context.current_user).get_one(workspace_id)
    except:
        workspace = None

    try:
        content_data = content_str.split(CST.TREEVIEW_MENU.ID_SEPARATOR)
        content_id = int(content_data[1])
        content = ContentApi(tg.tmpl_context.current_user).get_one(
            content_id, ContentType.Any)
    except (IndexError, ValueError) as e:
        content = None

    return workspace, content
예제 #16
0
    def put(self,
            folder_id,
            label,
            can_contain_folders=False,
            can_contain_threads=False,
            can_contain_files=False,
            can_contain_pages=False):
        # TODO - SECURE THIS
        workspace = tmpl_context.workspace

        api = ContentApi(tmpl_context.current_user)
        next_url = ''

        try:
            folder = api.get_one(int(folder_id), ContentType.Folder, workspace)
            subcontent = dict(
                folder=True if can_contain_folders == 'on' else False,
                thread=True if can_contain_threads == 'on' else False,
                file=True if can_contain_files == 'on' else False,
                page=True if can_contain_pages == 'on' else False)
            with new_revision(folder):
                if label != folder.label:
                    # TODO - D.A. - 2015-05-25 - Allow to set folder description
                    api.update_content(folder, label, folder.description)
                api.set_allowed_content(folder, subcontent)
                api.save(folder)

            tg.flash(_('Folder updated'), CST.STATUS_OK)

            next_url = self.url(folder.content_id)

        except Exception as e:
            tg.flash(
                _('Folder not updated: {}').format(str(e)), CST.STATUS_ERROR)
            next_url = self.url(int(folder_id))

        tg.redirect(next_url)
예제 #17
0
파일: content.py 프로젝트: qyqx/tracim
    def get_one(self, file_id, revision_id=None):
        file_id = int(file_id)
        cache_path = CFG.get_instance().PREVIEW_CACHE
        preview_manager = PreviewManager(cache_path, create_folder=True)
        user = tmpl_context.current_user
        workspace = tmpl_context.workspace
        current_user_content = Context(CTX.CURRENT_USER,
                                       current_user=user).toDict(user)
        current_user_content.roles.sort(key=lambda role: role.workspace.name)
        content_api = ContentApi(user, show_archived=True, show_deleted=True)
        if revision_id:
            file = content_api.get_one_from_revision(file_id, self._item_type,
                                                     workspace, revision_id)
        else:
            file = content_api.get_one(file_id, self._item_type, workspace)
            revision_id = file.revision_id

        file_path = content_api.get_one_revision_filepath(revision_id)
        nb_page = preview_manager.get_nb_page(file_path=file_path)
        preview_urls = []
        for page in range(int(nb_page)):
            url_str = '/previews/{}/pages/{}?revision_id={}'
            url = url_str.format(file_id, page, revision_id)
            preview_urls.append(url)

        fake_api_breadcrumb = self.get_breadcrumb(file_id)
        fake_api_content = DictLikeClass(breadcrumb=fake_api_breadcrumb,
                                         current_user=current_user_content)
        fake_api = Context(CTX.FOLDER,
                           current_user=user).toDict(fake_api_content)
        dictified_file = Context(self._get_one_context,
                                 current_user=user).toDict(file, 'file')
        result = DictLikeClass(result=dictified_file,
                               fake_api=fake_api,
                               nb_page=nb_page,
                               url=preview_urls)
        return result
예제 #18
0
    def put_delete(self, item_id):
        require_current_user_is_owner(int(item_id))

        # TODO - CHECK RIGHTS
        item_id = int(item_id)
        content_api = ContentApi(tmpl_context.current_user)
        item = content_api.get_one(item_id, self._item_type,
                                   tmpl_context.workspace)

        try:

            next_url = tg.url('/workspaces/{}/folders/{}/threads/{}').format(
                tmpl_context.workspace_id, tmpl_context.folder_id,
                tmpl_context.thread_id)
            undo_url = tg.url(
                '/workspaces/{}/folders/{}/threads/{}/comments/{}/put_delete_undo'
            ).format(tmpl_context.workspace_id, tmpl_context.folder_id,
                     tmpl_context.thread_id, item_id)

            msg = _(
                '{} deleted. <a class="alert-link" href="{}">Cancel action</a>'
            ).format(self._item_type_label, undo_url)
            with new_revision(item):
                content_api.delete(item)
                content_api.save(item, ActionDescription.DELETION)

            tg.flash(msg, CST.STATUS_OK, no_escape=True)
            tg.redirect(next_url)

        except ValueError as e:
            back_url = tg.url('/workspaces/{}/folders/{}/threads/{}').format(
                tmpl_context.workspace_id, tmpl_context.folder_id,
                tmpl_context.thread_id)
            msg = _('{} not deleted: {}').format(self._item_type_label, str(e))
            tg.flash(msg, CST.STATUS_ERROR)
            tg.redirect(back_url)
예제 #19
0
    def _build_sibling_list_of_tree_items(
            self,
            workspace: Workspace,
            content: Content,
            children: [NodeTreeItem],
            select_active_node=False,
            allowed_content_types: list = [],
            ignored_item_ids: list = []) -> (Content, [NodeTreeItem]):
        api = ContentApi(tmpl_context.current_user)
        tree_items = []

        parent = content.parent if content else None

        viewable_content_types = self._get_treeviewable_content_types_or_none()
        child_contents = api.get_child_folders(parent, workspace,
                                               allowed_content_types,
                                               ignored_item_ids,
                                               viewable_content_types)
        for child in child_contents:
            children_to_add = children if child == content else []
            if child == content and select_active_node:
                # The item is the requested node, so we select it
                is_selected = True
            elif content not in child_contents and select_active_node and child == content:
                # The item is not present in the list, so we select its parent node
                is_selected = True
            else:
                is_selected = False

            new_item = NodeTreeItem(child, children_to_add, is_selected)
            tree_items.append(new_item)

        # This allow to show contents and folders group by type
        tree_items = ContentApi.sort_tree_items(tree_items)

        return parent, tree_items
예제 #20
0
    def high_quality(self, page_id, *args, **kwargs):
        file_id = int(tg.request.controller_state.routing_args.get('file_id'))

        # For now it's done through database content
        # but soon it'll be with disk access

        user = tmpl_context.current_user
        content_api = ContentApi(
            user,
            show_archived=True,
            show_deleted=True,
        )
        file_name = content_api.get_one(file_id, self._item_type).file_name
        cache_path = '/home/alexis/Pictures/cache/'

        preview_manager = PreviewManager(cache_path, create_folder=True)
        path = preview_manager.get_jpeg_preview(
            file_path='/home/alexis/Pictures/cache/{}'.format(file_name),
            page=page_id,
            height=5000,
            width=5000)

        with open(path, 'rb') as large:
            return large.read()
예제 #21
0
 def get_one(self,
             page_id: str = '-1',
             revision_id: str = None,
             size: int = 300,
             *args,
             **kwargs):
     file_id = int(tg.request.controller_state.routing_args.get('file_id'))
     page = int(page_id)
     revision_id = int(revision_id) if revision_id != 'latest' else None
     cache_path = CFG.get_instance().PREVIEW_CACHE
     preview_manager = PreviewManager(cache_path, create_folder=True)
     user = tmpl_context.current_user
     content_api = ContentApi(user, show_archived=True, show_deleted=True)
     if revision_id:
         file_path = content_api.get_one_revision_filepath(revision_id)
     else:
         file = content_api.get_one(file_id, self._item_type)
         file_path = content_api.get_one_revision_filepath(file.revision_id)
     path = preview_manager.get_jpeg_preview(file_path=file_path,
                                             page=page,
                                             height=size,
                                             width=size)
     with open(path, 'rb') as large:
         return large.read()
예제 #22
0
파일: content.py 프로젝트: qyqx/tracim
    def put_archive_undo(self, item_id):
        # TODO - CHECK RIGHTS
        item_id = int(item_id)
        # Here we do not filter deleted items
        content_api = ContentApi(tmpl_context.current_user, True, True)
        item = content_api.get_one(item_id, self._item_type,
                                   tmpl_context.workspace)
        try:
            next_url = self._std_url.format(item.workspace_id, item.content_id)
            msg = _('{} unarchived.').format(self._item_type_label)
            with new_revision(item):
                content_api.unarchive(item)
                content_api.save(item, ActionDescription.UNARCHIVING)

            tg.flash(msg, CST.STATUS_OK)
            tg.redirect(next_url)

        except ValueError as e:
            msg = _('{} not un-archived: {}').format(self._item_type_label,
                                                     str(e))
            next_url = self._std_url.format(item.workspace_id, item.content_id)
            # We still use std url because the item has not been archived
            tg.flash(msg, CST.STATUS_ERROR)
            tg.redirect(next_url)
예제 #23
0
파일: content.py 프로젝트: qyqx/tracim
    def post(self,
             label,
             parent_id=None,
             can_contain_folders=False,
             can_contain_threads=False,
             can_contain_files=False,
             can_contain_pages=False):
        # TODO - SECURE THIS
        workspace = tmpl_context.workspace

        api = ContentApi(tmpl_context.current_user)

        redirect_url_tmpl = '/workspaces/{}/folders/{}'
        redirect_url = ''

        try:
            parent = None
            if parent_id:
                parent = api.get_one(int(parent_id), ContentType.Folder,
                                     workspace)

            with DBSession.no_autoflush:
                folder = api.create(ContentType.Folder, workspace, parent,
                                    label)

                subcontent = dict(
                    folder=True if can_contain_folders == 'on' else False,
                    thread=True if can_contain_threads == 'on' else False,
                    file=True if can_contain_files == 'on' else False,
                    page=True if can_contain_pages == 'on' else False)
                api.set_allowed_content(folder, subcontent)

                if not self._path_validation.validate_new_content(folder):
                    return render_invalid_integrity_chosen_path(
                        folder.get_label(), )

            api.save(folder)

            tg.flash(_('Folder created'), CST.STATUS_OK)
            redirect_url = redirect_url_tmpl.format(tmpl_context.workspace_id,
                                                    folder.content_id)
        except Exception as e:
            error_msg = 'An unexpected exception has been catched. ' \
                        'Look at the traceback below.'
            logger.error(self, error_msg)
            traceback.print_exc()

            tb = sys.exc_info()[2]
            tg.flash(
                _('Folder not created: {}').format(e.with_traceback(tb)),
                CST.STATUS_ERROR)
            if parent_id:
                redirect_url = \
                    redirect_url_tmpl.format(tmpl_context.workspace_id,
                                             parent_id)
            else:
                redirect_url = \
                    '/workspaces/{}'.format(tmpl_context.workspace_id)

        ####
        #
        # INFO - D.A. - 2014-10-22 - Do not put redirect in a
        # try/except block as redirect is using exceptions!
        #
        tg.redirect(tg.url(redirect_url))
예제 #24
0
파일: content.py 프로젝트: qyqx/tracim
    def get_one(self, folder_id, **kwargs):
        """
        :param folder_id: Displayed folder id
        :param kwargs:
          * show_deleted: bool: Display deleted contents or hide them if False
          * show_archived: bool: Display archived contents or hide them
            if False
        """
        show_deleted = str_as_bool(kwargs.get('show_deleted', ''))
        show_archived = str_as_bool(kwargs.get('show_archived', ''))
        folder_id = int(folder_id)
        user = tmpl_context.current_user
        workspace = tmpl_context.workspace

        current_user_content = Context(CTX.CURRENT_USER,
                                       current_user=user).toDict(user)
        current_user_content.roles.sort(key=lambda role: role.workspace.name)

        content_api = ContentApi(
            user,
            show_deleted=show_deleted,
            show_archived=show_archived,
        )
        with content_api.show(show_deleted=True, show_archived=True):
            folder = content_api.get_one(
                folder_id,
                ContentType.Folder,
                workspace,
            )

        fake_api_breadcrumb = self.get_breadcrumb(folder_id)
        fake_api_subfolders = self.get_all_fake(workspace,
                                                folder.content_id).result
        fake_api_pages = self.pages.get_all_fake(workspace, folder).result
        fake_api_files = self.files.get_all_fake(workspace, folder).result
        fake_api_threads = self.threads.get_all_fake(workspace, folder).result

        fake_api_content = DictLikeClass(
            current_user=current_user_content,
            breadcrumb=fake_api_breadcrumb,
            current_folder_subfolders=fake_api_subfolders,
            current_folder_pages=fake_api_pages,
            current_folder_files=fake_api_files,
            current_folder_threads=fake_api_threads,
        )

        fake_api = Context(CTX.FOLDER).toDict(fake_api_content)

        sub_items = content_api.get_children(
            parent_id=folder.content_id,
            content_types=[
                ContentType.Folder,
                ContentType.File,
                ContentType.Page,
                ContentType.Thread,
            ],
        )
        fake_api.sub_items = Context(CTX.FOLDER_CONTENT_LIST).toDict(sub_items)

        fake_api.content_types = Context(CTX.DEFAULT).toDict(
            content_api.get_all_types())

        dictified_folder = Context(CTX.FOLDER).toDict(folder, 'folder')
        return DictLikeClass(
            result=dictified_folder,
            fake_api=fake_api,
            show_deleted=show_deleted,
            show_archived=show_archived,
        )
예제 #25
0
파일: content.py 프로젝트: qyqx/tracim
    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)
예제 #26
0
    def test_update_file_data(self):
        uapi = UserApi(None)
        groups = [
            GroupApi(None).get_one(Group.TIM_USER),
            GroupApi(None).get_one(Group.TIM_MANAGER),
            GroupApi(None).get_one(Group.TIM_ADMIN)
        ]

        user1 = uapi.create_user(email='this.is@user',
                                 groups=groups,
                                 save_now=True)

        workspace = WorkspaceApi(user1).create_workspace('test workspace',
                                                         save_now=True)
        wid = workspace.workspace_id

        user2 = uapi.create_user()
        user2.email = '*****@*****.**'
        uapi.save(user2)

        RoleApi(user1).create_one(user2,
                                  workspace,
                                  UserRoleInWorkspace.CONTENT_MANAGER,
                                  with_notif=True,
                                  flush=True)

        # Test starts here

        api = ContentApi(user1)
        p = api.create(ContentType.File, workspace, None, 'this_is_a_page',
                       True)

        u1id = user1.user_id
        u2id = user2.user_id
        pcid = p.content_id
        poid = p.owner_id

        api.save(p)
        transaction.commit()

        # Refresh instances after commit
        user1 = uapi.get_one(u1id)
        workspace = WorkspaceApi(user1).get_one(wid)
        api = ContentApi(user1)

        content = api.get_one(pcid, ContentType.Any, workspace)
        eq_(u1id, content.owner_id)
        eq_(poid, content.owner_id)

        u2 = UserApi(None).get_one(u2id)
        api2 = ContentApi(u2)
        content2 = api2.get_one(pcid, ContentType.Any, workspace)
        with new_revision(content2):
            api2.update_file_data(content2, 'index.html', 'text/html',
                                  b'<html>hello world</html>')
        api2.save(content2)
        transaction.commit()

        # Refresh instances after commit
        user1 = uapi.get_one(u1id)
        workspace = WorkspaceApi(user1).get_one(wid)

        updated = api.get_one(pcid, ContentType.Any, workspace)
        eq_(
            u2id, updated.owner_id,
            'the owner id should be {} (found {})'.format(
                u2id, updated.owner_id))
        eq_('index.html', updated.file_name)
        eq_('text/html', updated.file_mimetype)
        eq_(b'<html>hello world</html>', updated.file_content)
        eq_(ActionDescription.REVISION, updated.revision_type)
예제 #27
0
파일: content.py 프로젝트: qyqx/tracim
    def put(self, item_id, file_data=None, comment=None, label=None):
        # TODO - SECURE THIS
        workspace = tmpl_context.workspace

        try:
            api = ContentApi(tmpl_context.current_user)
            item = api.get_one(int(item_id), self._item_type, workspace)
            label_changed = False
            if label is not None and label != item.label:
                label_changed = True

            if label is None:
                label = ''

            # TODO - D.A. - 2015-03-19
            # refactor this method in order to make code easier to understand

            with new_revision(item):

                if (comment and label) or (not comment and label_changed):
                    updated_item = api.update_content(
                        item, label if label else item.label,
                        comment if comment else '')

                    # Display error page to user if chosen label is in conflict
                    if not self._path_validation.validate_new_content(
                            updated_item, ):
                        return render_invalid_integrity_chosen_path(
                            updated_item.get_label_as_file(), )

                    api.save(updated_item, ActionDescription.EDITION)

                    # This case is the default "file title and description
                    # update" In this case the file itself is not revisionned

                else:
                    # So, now we may have a comment and/or a file revision
                    if comment and '' == label:
                        comment_item = api.create_comment(workspace,
                                                          item,
                                                          comment,
                                                          do_save=False)

                        if not isinstance(file_data, FieldStorage):
                            api.save(comment_item, ActionDescription.COMMENT)
                        else:
                            # The notification is only sent
                            # if the file is NOT updated
                            #
                            # If the file is also updated,
                            # then a 'file revision' notification will be sent.
                            api.save(comment_item,
                                     ActionDescription.COMMENT,
                                     do_notify=False)

                    if isinstance(file_data, FieldStorage):
                        api.update_file_data(item, file_data.filename,
                                             file_data.type,
                                             file_data.file.read())

                        # Display error page to user if chosen label is in
                        # conflict
                        if not self._path_validation.validate_new_content(
                                item, ):
                            return render_invalid_integrity_chosen_path(
                                item.get_label_as_file(), )

                        api.save(item, ActionDescription.REVISION)

            msg = _('{} updated').format(self._item_type_label)
            tg.flash(msg, CST.STATUS_OK)
            tg.redirect(
                self._std_url.format(tmpl_context.workspace_id,
                                     tmpl_context.folder_id, item.content_id))

        except ValueError as e:
            error = '{} not updated - error: {}'
            msg = _(error).format(self._item_type_label, str(e))
            tg.flash(msg, CST.STATUS_ERROR)
            tg.redirect(
                self._err_url.format(tmpl_context.workspace_id,
                                     tmpl_context.folder_id, item_id))
예제 #28
0
    def test_delete_undelete(self):
        uapi = UserApi(None)
        groups = [
            GroupApi(None).get_one(Group.TIM_USER),
            GroupApi(None).get_one(Group.TIM_MANAGER),
            GroupApi(None).get_one(Group.TIM_ADMIN)
        ]

        user1 = uapi.create_user(email='this.is@user',
                                 groups=groups,
                                 save_now=True)
        u1id = user1.user_id

        workspace = WorkspaceApi(user1).create_workspace('test workspace',
                                                         save_now=True)
        wid = workspace.workspace_id

        user2 = uapi.create_user()
        user2.email = '*****@*****.**'
        uapi.save(user2)

        RoleApi(user1).create_one(user2,
                                  workspace,
                                  UserRoleInWorkspace.CONTENT_MANAGER,
                                  with_notif=True,
                                  flush=True)

        # show archived is used at the top end of the test
        api = ContentApi(user1, show_deleted=True)
        p = api.create(ContentType.File, workspace, None, 'this_is_a_page',
                       True)

        u1id = user1.user_id
        u2id = user2.user_id
        pcid = p.content_id
        poid = p.owner_id

        transaction.commit()

        ####
        user1 = UserApi(None).get_one(u1id)
        workspace = WorkspaceApi(user1).get_one(wid)

        content = api.get_one(pcid, ContentType.Any, workspace)
        eq_(u1id, content.owner_id)
        eq_(poid, content.owner_id)

        u2 = UserApi(None).get_one(u2id)
        api2 = ContentApi(u2, show_deleted=True)
        content2 = api2.get_one(pcid, ContentType.Any, workspace)
        with new_revision(content2):
            api2.delete(content2)
        api2.save(content2)
        transaction.commit()

        ####

        user1 = UserApi(None).get_one(u1id)
        workspace = WorkspaceApi(user1).get_one(wid)
        # show archived is used at the top end of the test
        api = ContentApi(user1, show_deleted=True)
        u2 = UserApi(None).get_one(u2id)
        api2 = ContentApi(u2, show_deleted=True)

        updated = api2.get_one(pcid, ContentType.Any, workspace)
        eq_(
            u2id, updated.owner_id,
            'the owner id should be {} (found {})'.format(
                u2id, updated.owner_id))
        eq_(True, updated.is_deleted)
        eq_(ActionDescription.DELETION, updated.revision_type)

        ####

        updated2 = api.get_one(pcid, ContentType.Any, workspace)
        with new_revision(updated2):
            api.undelete(updated2)
        api.save(updated2)
        eq_(False, updated2.is_deleted)
        eq_(ActionDescription.UNDELETION, updated2.revision_type)
        eq_(u1id, updated2.owner_id)
예제 #29
0
    def test_search_in_label_or_description(self):
        # HACK - D.A. - 2015-03-09
        # This test is based on a bug which does NOT return results found
        # at root of a workspace (eg a folder)

        uapi = UserApi(None)
        groups = [
            GroupApi(None).get_one(Group.TIM_USER),
            GroupApi(None).get_one(Group.TIM_MANAGER),
            GroupApi(None).get_one(Group.TIM_ADMIN)
        ]

        user = uapi.create_user(email='this.is@user',
                                groups=groups,
                                save_now=True)

        workspace = WorkspaceApi(user).create_workspace('test workspace',
                                                        save_now=True)

        api = ContentApi(user)

        a = api.create(ContentType.Folder, workspace, None,
                       'this is randomized folder', True)
        p1 = api.create(ContentType.Page, workspace, a,
                        'this is dummy label content', True)
        p2 = api.create(ContentType.Page, workspace, a, 'Hey ! Jon !', True)

        with new_revision(p1):
            p1.description = 'This is some amazing test'

        with new_revision(p2):
            p2.description = 'What\'s up ?'

        api.save(p1)
        api.save(p2)

        id1 = p1.content_id
        id2 = p2.content_id

        eq_(
            1,
            DBSession.query(Workspace).filter(
                Workspace.label == 'test workspace').count())
        eq_(
            1,
            DBSession.query(ContentRevisionRO).filter(
                ContentRevisionRO.label ==
                'this is randomized folder').count())
        eq_(
            2,
            DBSession.query(ContentRevisionRO).filter(
                ContentRevisionRO.label ==
                'this is dummy label content').count())
        eq_(
            1,
            DBSession.query(ContentRevisionRO).filter(
                ContentRevisionRO.description ==
                'This is some amazing test').count())
        eq_(
            2,
            DBSession.query(ContentRevisionRO).filter(
                ContentRevisionRO.label == 'Hey ! Jon !').count())
        eq_(
            1,
            DBSession.query(ContentRevisionRO).filter(
                ContentRevisionRO.description == 'What\'s up ?').count())

        res = api.search(['dummy', 'jon'])
        eq_(2, len(res.all()))

        eq_(True, id1 in [o.content_id for o in res.all()])
        eq_(True, id2 in [o.content_id for o in res.all()])
예제 #30
0
    def get_one(self, file_id, revision_id=None):
        file_id = int(file_id)
        cache_path = CFG.get_instance().PREVIEW_CACHE_DIR
        preview_manager = PreviewManager(cache_path, create_folder=True)
        user = tmpl_context.current_user
        workspace = tmpl_context.workspace
        current_user_content = Context(CTX.CURRENT_USER,
                                       current_user=user).toDict(user)
        current_user_content.roles.sort(key=lambda role: role.workspace.name)
        content_api = ContentApi(user, show_archived=True, show_deleted=True)
        if revision_id:
            file = content_api.get_one_from_revision(file_id, self._item_type,
                                                     workspace, revision_id)
        else:
            file = content_api.get_one(file_id, self._item_type, workspace)
            revision_id = file.revision_id

        file_path = content_api.get_one_revision_filepath(revision_id)

        nb_page = 0
        enable_pdf_buttons = False  # type: bool
        preview_urls = []

        try:
            nb_page = preview_manager.get_page_nb(file_path=file_path)
            for page in range(int(nb_page)):
                url_str = '/previews/{}/pages/{}?revision_id={}'
                url = url_str.format(file_id, page, revision_id)
                preview_urls.append(url)

            enable_pdf_buttons = \
                preview_manager.has_pdf_preview(file_path=file_path)

        except PreviewGeneratorException as e:
            # INFO - A.P - Silently intercepts preview exception
            # As preview generation isn't mandatory, just register it
            logger.debug(self,
                         'Preview Generator Exception: {}'.format(e.__str__))
        except Exception as e:
            # INFO - D.A - 2017-08-11 - Make Tracim robust to pg exceptions
            # Preview generator may potentially raise any type of exception
            # so we prevent user interface crashes by catching all exceptions
            logger.error(
                self,
                'Preview Generator Generic Exception: {}'.format(e.__str__))

        pdf_available = 'true' if enable_pdf_buttons else 'false'  # type: str

        fake_api_breadcrumb = self.get_breadcrumb(file_id)
        fake_api_content = DictLikeClass(breadcrumb=fake_api_breadcrumb,
                                         current_user=current_user_content)
        fake_api = Context(CTX.FOLDER, current_user=user)\
            .toDict(fake_api_content)

        dictified_file = Context(self._get_one_context,
                                 current_user=user).toDict(file, 'file')
        result = DictLikeClass(result=dictified_file,
                               fake_api=fake_api,
                               nb_page=nb_page,
                               url=preview_urls,
                               pdf_available=pdf_available)
        return result