123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- # -*- coding: utf-8 -*-
-
- import tg
- from tg import tmpl_context
- from tg.i18n import ugettext as _
- from tg.predicates import not_anonymous
-
- from tracim.config.app_cfg import CFG
-
- from tracim.controllers import TIMRestController
- from tracim.controllers.content import UserWorkspaceFolderRestController
- from tracim.controllers.jitsi_meet import JitsiMeetController
-
- from tracim.lib.helpers import convert_id_into_instances
- from tracim.lib.content import ContentApi
- from tracim.lib.utils import str_as_bool
- from tracim.lib.workspace import WorkspaceApi
-
- from tracim.model.data import NodeTreeItem
- from tracim.model.data import Content
- from tracim.model.data import ContentType
- from tracim.model.data import Workspace
-
- from tracim.model.serializers import Context, CTX, DictLikeClass
-
- from urllib.parse import urlparse
-
- class UserWorkspaceRestController(TIMRestController):
-
- allow_only = not_anonymous()
-
- folders = UserWorkspaceFolderRestController()
- videoconference = JitsiMeetController()
-
- @property
- def _base_url(self):
- return '/dashboard/workspaces'
-
- @classmethod
- def current_item_id_key_in_context(cls) -> str:
- return 'workspace_id'
-
-
- @tg.expose()
- def get_all(self, *args, **kw):
- tg.redirect(tg.url('/home'))
-
- @tg.expose()
- def mark_read(self, workspace_id, **kwargs):
-
- user = tmpl_context.current_user
- workspace_api = WorkspaceApi(user)
- workspace = workspace_api.get_one(workspace_id)
-
- content_api = ContentApi(user)
- content_api.mark_read__workspace(workspace)
-
- tg.redirect('/workspaces/{}'.format(workspace_id))
- return DictLikeClass(fake_api=fake_api)
-
- @tg.expose('tracim.templates.workspace.getone')
- def get_one(self, workspace_id, **kwargs):
- """
- :param workspace_id: Displayed workspace 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', False))
- show_archived = str_as_bool(kwargs.get('show_archived', ''))
- user = tmpl_context.current_user
-
- workspace_api = WorkspaceApi(user)
- workspace = workspace_api.get_one(workspace_id)
-
- unread_contents = ContentApi(user).get_last_unread(None,
- ContentType.Any,
- workspace=workspace)
- current_user_content = Context(CTX.CURRENT_USER).toDict(user)
- current_user_content.roles.sort(key=lambda role: role.workspace.name)
-
-
-
- dictified_current_user = Context(CTX.CURRENT_USER).toDict(user)
- dictified_folders = self.folders.get_all_fake(workspace).result
- fake_api = DictLikeClass(
- last_unread=Context(CTX.CONTENT_LIST).toDict(unread_contents,
- 'contents',
- 'nb'),
- current_user=dictified_current_user,
- current_workspace_folders=dictified_folders,
- current_user_workspace_role=workspace.get_user_role(user)
- )
-
- fake_api.sub_items = Context(CTX.FOLDER_CONTENT_LIST).toDict(
- # TODO BS 20161209: Is the correct way to grab folders? No use API?
- workspace.get_valid_children(
- ContentApi.DISPLAYABLE_CONTENTS,
- show_deleted=show_deleted,
- show_archived=show_archived,
- )
- )
- videoconf_enabled = CFG.get_instance().JITSI_MEET_ACTIVATED
-
- dictified_workspace = Context(CTX.WORKSPACE).toDict(workspace, 'workspace')
-
- webdav_url = CFG.get_instance().WSGIDAV_CLIENT_BASE_URL
- website_protocol = urlparse(CFG.get_instance().WEBSITE_BASE_URL).scheme
- dav_protocol = 'dav'
- if website_protocol == "https":
- dav_protocol = 'davs'
-
- return DictLikeClass(
- result=dictified_workspace,
- fake_api=fake_api,
- webdav_url=webdav_url,
- videoconf_enabled=videoconf_enabled,
- website_protocol = website_protocol,
- dav_protocol = dav_protocol,
- show_deleted=show_deleted,
- show_archived=show_archived,
- )
-
- @tg.expose('json')
- def treeview_root(self, id='#',
- current_id=None,
- all_workspaces=True,
- folder_allowed_content_types='',
- ignore_id=None,
- ignore_workspace_id=None):
- all_workspaces = bool(int(all_workspaces))
-
- # ignore_workspace_id is a string like 3,12,78,15
- ignored_ids = [int(id) for id in ignore_workspace_id.split(',')] if ignore_workspace_id else None
-
- if not current_id:
- # Default case is to return list of workspaces
- api = WorkspaceApi(tmpl_context.current_user)
- workspaces = api.get_all_for_user(tmpl_context.current_user,
- ignored_ids)
- dictified_workspaces = Context(CTX.MENU_API).toDict(workspaces, 'd')
- return dictified_workspaces
-
- allowed_content_types = ContentType.allowed_types_from_str(folder_allowed_content_types)
- ignored_item_ids = [int(ignore_id)] if ignore_id else []
-
- # Now complex case: we must return a structured tree
- # including the selected node, all parents (and their siblings)
- workspace, content = convert_id_into_instances(current_id)
-
- # The following step allow to select the parent folder when content itself is not visible in the treeview
- if content and content.type!=ContentType.Folder and CFG.CST.TREEVIEW_ALL!=CFG.get_instance().WEBSITE_TREEVIEW_CONTENT:
- content = content.parent if content.parent else None
-
- # This is the init of the recursive-like build of the tree
- content_parent = content
- tree_items = []
-
- # The first step allow to load child of selected item
- # (for example, when you select a folder in the windows explorer,
- # then the selected folder is expanded by default)
- content_api = ContentApi(tmpl_context.current_user)
- child_folders = content_api.get_child_folders(content_parent, workspace, allowed_content_types, ignored_item_ids)
-
- if len(child_folders)>0:
- first_child = child_folders[0]
- content_parent, tree_items = self._build_sibling_list_of_tree_items(workspace, first_child, tree_items, False, allowed_content_types, ignored_item_ids)
-
- content_parent, tree_items = self._build_sibling_list_of_tree_items(workspace, content_parent, tree_items, True, allowed_content_types, ignored_item_ids)
- while content_parent:
- # Do the same for the parent level
- content_parent, tree_items = self._build_sibling_list_of_tree_items(workspace, content_parent, tree_items)
- # Now, we have a tree_items list that is the root folders list,
- # so we now have to put it as a child of a list of workspaces
- should_select_workspace = not content
-
- full_tree = self._build_sibling_list_of_workspaces(workspace, tree_items, should_select_workspace, all_workspaces)
-
- return Context(CTX.MENU_API_BUILD_FROM_TREE_ITEM).toDict(full_tree, 'd')
-
- def _build_sibling_list_of_workspaces(self, workspace: Workspace, child_contents: [NodeTreeItem], select_active_workspace = False, all_workspaces = True) -> [NodeTreeItem]:
-
- root_items = []
- api = WorkspaceApi(tmpl_context.current_user)
- workspaces = api.get_all_for_user(tmpl_context.current_user)
-
- if not all_workspaces:
- # Show only current workspace - this is used for "move item" screen
- # which must not allow to move from a workspace to another
- item = NodeTreeItem(workspace, child_contents)
- item.is_selected = select_active_workspace
- root_items.append(item)
- else:
- for workspace_cursor in workspaces:
- item = None
- if workspace_cursor==workspace:
- item = NodeTreeItem(workspace_cursor, child_contents)
- else:
- item = NodeTreeItem(workspace_cursor, [])
-
- item.is_selected = select_active_workspace and workspace_cursor==workspace
-
- root_items.append(item)
-
- return root_items
-
-
- 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
-
-
- @tg.expose('json')
- 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
-
- def _get_treeviewable_content_types_or_none(self):
- if CFG.get_instance().WEBSITE_TREEVIEW_CONTENT==CFG.CST.TREEVIEW_ALL:
- return ContentType.Any
- return None # None means "workspaces and folders"
|