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_DIR 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) file_suffix = '' if page > -1: file_suffix = '.page-{}'.format(page + 1) tg.response.headers['Content-Disposition'] = \ 'attachment; filename="{}{}.pdf"'.format( file.label, file_suffix, ) with open(path, 'rb') as pdf: return pdf.read()
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)
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 tg.response.headers['Content-Disposition'] = str('attachment; filename="{}"'.format(revision_to_send.file_name)) return revision_to_send.file_content
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) 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)
def put_delete_undo(self, item_id): require_current_user_is_owner(int(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) try: next_url = tg.url('/workspaces/{}/folders/{}/threads/{}').format(tmpl_context.workspace_id, tmpl_context.folder_id, tmpl_context.thread_id) msg = _('{} undeleted.').format(self._item_type_label) 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 = tg.url('/workspaces/{}/folders/{}/threads/{}').format(tmpl_context.workspace_id, tmpl_context.folder_id, tmpl_context.thread_id) msg = _('{} not un-deleted: {}').format(self._item_type_label, str(e)) tg.flash(msg, CST.STATUS_ERROR) tg.redirect(back_url)
def put(self, item_id, label='',content=''): # 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))
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_DIR 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) try: path = preview_manager.get_jpeg_preview(file_path=file_path, page=page, height=size, width=size) with open(path, 'rb') as large: result = large.read() except PreviewGeneratorException: result = None return result
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 ) 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)
def current_folder(cls) -> Content: content_api = ContentApi(tg.tmpl_context.current_user) folder_id = int(tg.request.controller_state.routing_args.get('folder_id')) folder = content_api.get_one(folder_id, ContentType.Folder, tg.tmpl_context.workspace) tg.tmpl_context.folder_id = folder_id tg.tmpl_context.folder = folder return folder
def _current_item_manually(cls, item_id: int, item_type: str) -> Content: # in case thread or page or other stuff is instanciated, then force # the associated item to be available through generic name tmpl_context.item to be available content_api = ContentApi(tg.tmpl_context.current_user) item = content_api.get_one(item_id, item_type, tg.tmpl_context.workspace) tg.tmpl_context.item_id = item.content_id tg.tmpl_context.item = item return item
def put(self, item_id, file_data=None, comment=None, label=''): # TODO - SECURE THIS workspace = tmpl_context.workspace try: item_saved = False api = ContentApi(tmpl_context.current_user) item = api.get_one(int(item_id), self._item_type, workspace) # TODO - D.A. - 2015-03-19 # refactor this method in order to make code easier to understand if comment and label: updated_item = api.update_content( item, label if label else item.label, comment if comment else '' ) 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()) 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: 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))
def put_status(self, item_id, status): item_id = int(item_id) content_api = ContentApi(tmpl_context.current_user) try: item = content_api.get_one(item_id, self._item_type, tmpl_context.workspace) with new_revision(item): content_api.set_status(item, status) content_api.save(item, ActionDescription.STATUS_UPDATE) msg = _('{} status updated').format(self._item_type_label) tg.flash(msg, CST.STATUS_OK) tg.redirect(self._std_url.format(item.workspace_id, item.parent_id, item.content_id)) except ValueError as e: msg = _('{} status not updated: {}').format(self._item_type_label, str(e)) tg.flash(msg, CST.STATUS_ERROR) tg.redirect(self._err_url.format(item.workspace_id, item.parent_id, item.content_id)) except NoResultFound as e: # probably the content is deleted or archived => forbidden to update status content_api = ContentApi( tmpl_context.current_user, show_archived=True, show_deleted=True ) item = content_api.get_one( item_id, self._item_type, tmpl_context.workspace ) next_url = self._std_url.format( item.workspace_id, item.parent_id, item.content_id ) msg = _('{} status not updated: the operation ' 'is not allowed on deleted/archived content').format( self._item_type_label ) tg.flash(msg, CST.STATUS_ERROR) tg.redirect(next_url)
def put_status(self, item_id, status): 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: content_api.set_status(item, status) content_api.save(item, ActionDescription.STATUS_UPDATE) msg = _('{} status updated').format(self._item_type_label) tg.flash(msg, CST.STATUS_OK) tg.redirect(self._std_url.format(item.workspace_id, item.parent_id, item.content_id)) except ValueError as e: msg = _('{} status not updated: {}').format(self._item_type_label, str(e)) tg.flash(msg, CST.STATUS_ERROR) tg.redirect(self._err_url.format(item.workspace_id, item.parent_id, item.content_id))
def get_all_fake(self, context_workspace: Workspace, parent_id=None): """ fake methods are used in other controllers in order to simulate a client/server api. the "client" controller method will include the result into its own fake_api object which will be available in the templates :param context_workspace: the workspace which would be taken from tmpl_context if we were in the normal behavior :return: """ workspace = context_workspace content_api = ContentApi(tmpl_context.current_user) parent_folder = content_api.get_one(parent_id, ContentType.Folder) folders = content_api.get_child_folders(parent_folder, workspace) folders = Context(CTX.FOLDERS).toDict(folders) return DictLikeClass(result = folders)
def edit(self, folder_id): """ Show the edit form (do not really edit the data) :param item_id: :return: """ folder_id = int(folder_id) user = tmpl_context.current_user workspace = tmpl_context.workspace content_api = ContentApi(user) folder = content_api.get_one(folder_id, ContentType.Folder, workspace) dictified_folder = Context(CTX.FOLDER).toDict(folder, 'folder') return DictLikeClass(result = dictified_folder)
def get_one(self, thread_id): 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) 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') return DictLikeClass(result = dictified_thread, fake_api=fake_api)
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)
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) 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) 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: logger.error(self, 'An unexpected exception has been catched. Look at the traceback below.') traceback.print_exc() tg.flash(_('Folder not created: {}').format(e.with_traceback()), 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))
def edit(self, item_id): """ Show the edit form (do not really edit the data) :param item_id: :return: """ current_user_content = Context(CTX.CURRENT_USER).toDict(tmpl_context.current_user) fake_api = Context(CTX.FOLDER).toDict(DictLikeClass(current_user=current_user_content)) item_id = int(item_id) user = tmpl_context.current_user workspace = tmpl_context.workspace content_api = ContentApi(user) item = content_api.get_one(item_id, ContentType.Any, workspace) dictified_item = Context(CTX.DEFAULT).toDict(item, 'item') return DictLikeClass(result = dictified_item, fake_api=fake_api)
def put_archive_undo(self, item_id): # TODO - CHECK RIGHTS item_id = int(item_id) content_api = ContentApi(tmpl_context.current_user, True) # Here we do not filter archived 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 = _('{} unarchived.').format(self._item_type_label) 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.parent_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)
def edit(self, item_id): """ Show the edit form (do not really edit the data) :param item_id: :return: """ # the follwing line allow to define the template to use in child classes. tg.override_template(self.edit, self.TEMPLATE_EDIT) item_id = int(item_id) user = tmpl_context.current_user workspace = tmpl_context.workspace content_api = ContentApi(user) item = content_api.get_one(item_id, self._item_type, workspace) dictified_item = Context(self._get_one_context).toDict(item, 'item') return DictLikeClass(result = dictified_item)
def put_archive(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_archive_undo' msg = _('{} archived. <a class="alert-link" href="{}">Cancel action</a>').format(self._item_type_label, undo_url) content_api.archive(item) content_api.save(item, ActionDescription.ARCHIVING) tg.flash(msg, CST.STATUS_OK, no_escape=True) # TODO allow to come back tg.redirect(next_url) except ValueError as e: next_url = self._std_url.format(item.workspace_id, item.parent_id, item.content_id) msg = _('{} not archived: {}').format(self._item_type_label, str(e)) tg.flash(msg, CST.STATUS_ERROR) tg.redirect(next_url)
def get_one(self, folder_id): folder_id = int(folder_id) user = tmpl_context.current_user workspace = tmpl_context.workspace workspace_id = tmpl_context.workspace_id 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) 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) fake_api.sub_items = Context(CTX.FOLDER_CONTENT_LIST).toDict( folder.get_valid_children([ContentType.Folder, ContentType.File, ContentType.Page, ContentType.Thread])) 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)
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)
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) 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)
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)
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)
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
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)
def get_one(self, file_id, revision_id=None): file_id = int(file_id) user = tmpl_context.current_user workspace = tmpl_context.workspace workspace_id = tmpl_context.workspace_id 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) 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) 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') return DictLikeClass(result = dictified_file, fake_api=fake_api)
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) api.update_content(item, label, content) 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))
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()
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: not_updated = '{} not updated: the content did not change' msg = _(not_updated).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: not_updated = '{} not updated - error: {}' msg = _(not_updated).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))
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)
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)
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()
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))
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, )
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)
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))
def post(self) -> Response: cfg = CFG.get_instance() try: json = request.json_body except ValueError: return Response( status=400, json_body={'msg': 'Bad json'}, ) if json.get('token', None) != cfg.EMAIL_REPLY_TOKEN: # TODO - G.M - 2017-11-23 - Switch to status 403 ? # 403 is a better status code in this case. # 403 status response can't now return clean json, because they are # handled somewhere else to return html. return Response( status=400, json_body={'msg': 'Invalid token'} ) if 'user_mail' not in json: return Response( status=400, json_body={'msg': 'Bad json: user_mail is required'} ) if 'content_id' not in json: return Response( status=400, json_body={'msg': 'Bad json: content_id is required'} ) if 'payload' not in json: return Response( status=400, json_body={'msg': 'Bad json: payload is required'} ) uapi = UserApi(None) try: user = uapi.get_one_by_email(json['user_mail']) except NoResultFound: return Response( status=400, json_body={'msg': 'Unknown user email'}, ) api = ContentApi(user) try: thread = api.get_one(json['content_id'], content_type=ContentType.Any) except NoResultFound: return Response( status=400, json_body={'msg': 'Unknown content_id'}, ) # INFO - G.M - 2017-11-17 # When content_id is a sub-elem of a main content like Comment, # Attach the thread to the main content. if thread.type == ContentType.Comment: thread = thread.parent if thread.type == ContentType.Folder: return Response( status=400, json_body={'msg': 'comment for folder not allowed'}, ) if 'content' in json['payload']: api.create_comment( workspace=thread.workspace, parent=thread, content=json['payload']['content'], do_save=True, ) return Response( status=204, ) else: return Response( status=400, json_body={'msg': 'No content to add new comment'}, )
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)
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
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)
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)
def get_one(self, file_id, revision_id=None): user = tmpl_context.current_user file_id = int(file_id) user = tmpl_context.current_user workspace = tmpl_context.workspace content_api = ContentApi( user, show_archived=True, show_deleted=True, ) if revision_id: file_content = content_api.get_one_from_revision( file_id, self._item_type, workspace, revision_id).file_content else: file_content = content_api.get_one(file_id, self._item_type, workspace).file_content file_name = content_api.get_one(file_id, self._item_type).file_name cache_path = '/home/alexis/Pictures/cache/' file = BytesIO() file.write(file_content) current_user_content = Context(CTX.CURRENT_USER, current_user=user).toDict(user) current_user_content.roles.sort(key=lambda role: role.workspace.name) with open('{}{}'.format(cache_path, file_name), 'wb') as temp_file: file.seek(0, 0) buffer = file.read(1024) while buffer: temp_file.write(buffer) buffer = file.read(1024) preview_manager = PreviewManager(cache_path, create_folder=True) nb_page = preview_manager.get_nb_page( file_path='/home/alexis/Pictures/cache/{}'.format(file_name), ) 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) 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) dictified_file = Context(self._get_one_context, current_user=user).toDict(file, 'file') url = [] for i in range(int(nb_page)): url.append('/previews/{}/pages/{}'.format(file_id, i)) return DictLikeClass( result=dictified_file, fake_api=fake_api, nb_page=nb_page, url=url, )
def get_content_from_revision(self, revision: ContentRevisionRO, api: ContentApi) -> Content: try: return api.get_one(revision.content_id, ContentType.Any) except: return None