content.py 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. # -*- coding: utf-8 -*-
  2. __author__ = 'damien'
  3. import tg
  4. from sqlalchemy.orm.attributes import get_history
  5. from tracim.model import DBSession
  6. from tracim.model.auth import User
  7. from tracim.model.data import ContentStatus, ContentRevisionRO, ActionDescription
  8. from tracim.model.data import PBNode
  9. from tracim.model.data import PBNodeType
  10. from tracim.model.data import Workspace
  11. class ContentApi(object):
  12. def __init__(self, current_user: User, show_archived=False, show_deleted=False):
  13. self._user = current_user
  14. self._show_archived = show_archived
  15. self._show_deleted = show_deleted
  16. def _base_query(self, workspace: Workspace=None):
  17. result = DBSession.query(PBNode)
  18. if workspace:
  19. result = result.filter(PBNode.workspace_id==workspace.workspace_id)
  20. if not self._show_deleted:
  21. result = result.filter(PBNode.is_deleted==False)
  22. if not self._show_archived:
  23. result = result.filter(PBNode.is_archived==False)
  24. return result
  25. def get_child_folders(self, parent: PBNode=None, workspace: Workspace=None, filter_by_allowed_content_types: list=[], removed_item_ids: list=[]) -> [PBNode]:
  26. # assert parent is None or isinstance(parent, PBNode) # DYN_REMOVE
  27. # assert workspace is None or isinstance(workspace, Workspace) # DYN_REMOVE
  28. parent_id = parent.node_id if parent else None
  29. folders = self._base_query(workspace).\
  30. filter(PBNode.parent_id==parent_id).\
  31. filter(PBNode.node_type==PBNodeType.Folder).\
  32. filter(PBNode.node_id.notin_(removed_item_ids)).\
  33. all()
  34. if not filter_by_allowed_content_types or len(filter_by_allowed_content_types)<=0:
  35. return folders
  36. # Now, the case is to filter folders by the content that they are allowed to contain
  37. result = []
  38. for folder in folders:
  39. for allowed_content_type in filter_by_allowed_content_types:
  40. print('ALLOWED = ', filter_by_allowed_content_types)
  41. print('CONTENT = ', folder.properties['allowed_content'])
  42. # exit()
  43. if folder.properties['allowed_content'][allowed_content_type]==True:
  44. result.append(folder)
  45. return result
  46. def create(self, content_type: str, workspace: Workspace=None, parent: PBNode=None, label:str ='', do_save=False) -> PBNode:
  47. assert content_type in PBNodeType.allowed_types()
  48. content = PBNode()
  49. content.owner = self._user
  50. content.parent = parent
  51. content.workspace = workspace
  52. content.node_type = content_type
  53. content.data_label = label
  54. content.last_action = ActionDescription.CREATION
  55. if do_save:
  56. self.save(content)
  57. return content
  58. def create_comment(self, workspace: Workspace=None, parent: PBNode=None, content:str ='', do_save=False) -> PBNode:
  59. assert parent and parent.node_type!=PBNodeType.Folder
  60. item = PBNode()
  61. item.owner = self._user
  62. item.parent = parent
  63. item.workspace = workspace
  64. item.node_type = PBNodeType.Comment
  65. item.data_content = content
  66. item.data_label = ''
  67. item.last_action = ActionDescription.COMMENT
  68. if do_save:
  69. self.save(item)
  70. return content
  71. def get_one_from_revision(self, content_id: int, content_type: str, workspace: Workspace=None, revision_id=None) -> PBNode:
  72. """
  73. This method is a hack to convert a node revision item into a node
  74. :param content_id:
  75. :param content_type:
  76. :param workspace:
  77. :param revision_id:
  78. :return:
  79. """
  80. content = self.get_one(content_id, content_type, workspace)
  81. revision = DBSession.query(ContentRevisionRO).filter(ContentRevisionRO.version_id==revision_id).one()
  82. if revision.node_id==content.node_id:
  83. content.revision_to_serialize = revision.version_id
  84. else:
  85. raise ValueError('Revision not found for given content')
  86. return content
  87. def get_one(self, content_id: int, content_type: str, workspace: Workspace=None) -> PBNode:
  88. assert content_id is None or isinstance(content_id, int) # DYN_REMOVE
  89. assert content_type is not None # DYN_REMOVE
  90. assert isinstance(content_type, str) # DYN_REMOVE
  91. if not content_id:
  92. return
  93. if content_type==PBNodeType.Any:
  94. return self._base_query(workspace).\
  95. filter(PBNode.node_id==content_id).\
  96. one()
  97. return self._base_query(workspace).\
  98. filter(PBNode.node_id==content_id).\
  99. filter(PBNode.node_type==content_type).\
  100. one()
  101. def get_all(self, parent_id: int, content_type: str, workspace: Workspace=None) -> PBNode:
  102. assert parent_id is None or isinstance(parent_id, int) # DYN_REMOVE
  103. assert content_type is not None # DYN_REMOVE
  104. assert isinstance(content_type, str) # DYN_REMOVE
  105. if not parent_id:
  106. return
  107. return self._base_query(workspace).\
  108. filter(PBNode.parent_id==parent_id).\
  109. filter(PBNode.node_type==content_type).\
  110. all()
  111. def set_allowed_content(self, folder: PBNode, allowed_content_dict:dict):
  112. """
  113. :param folder: the given folder instance
  114. :param allowed_content_dict: must be something like this:
  115. dict(
  116. folder = True
  117. thread = True,
  118. file = False,
  119. page = True
  120. )
  121. :return:
  122. """
  123. assert folder.node_type==PBNodeType.Folder
  124. assert 'file' in allowed_content_dict.keys()
  125. assert 'folder' in allowed_content_dict.keys()
  126. assert 'page' in allowed_content_dict.keys()
  127. assert 'thread' in allowed_content_dict.keys()
  128. properties = dict(allowed_content = allowed_content_dict)
  129. folder.properties = properties
  130. def set_status(self, content: PBNode, new_status: str):
  131. if new_status in ContentStatus.allowed_values():
  132. content.node_status = new_status
  133. content.last_action = ActionDescription.STATUS_UPDATE
  134. else:
  135. raise ValueError('The given value {} is not allowed'.format(new_status))
  136. def move(self, item: PBNode, new_parent: PBNode, must_stay_in_same_workspace:bool=True):
  137. if must_stay_in_same_workspace:
  138. if new_parent and new_parent.workspace_id!=item.workspace_id:
  139. raise ValueError('the item should stay in the same workspace')
  140. item.parent = new_parent
  141. item.last_action = ActionDescription.EDITION
  142. def update_content(self, item: PBNode, new_label: str, new_content: str) -> PBNode:
  143. item.data_label = new_label
  144. item.data_content = new_content # TODO: convert urls into links
  145. item.last_action = ActionDescription.EDITION
  146. return item
  147. def update_file_data(self, item: PBNode, new_filename: str, new_mimetype: str, new_file_content) -> PBNode:
  148. item.data_file_name = new_filename
  149. item.data_file_mime_type = new_mimetype
  150. item.data_file_content = new_file_content
  151. return item
  152. def archive(self, content: PBNode):
  153. content.is_archived = True
  154. content.last_action = ActionDescription.ARCHIVING
  155. def unarchive(self, content: PBNode):
  156. content.is_archived = False
  157. content.last_action = ActionDescription.UNARCHIVING
  158. def delete(self, content: PBNode):
  159. content.is_deleted = True
  160. content.last_action = ActionDescription.DELETION
  161. def undelete(self, content: PBNode):
  162. content.is_deleted = False
  163. content.last_action = ActionDescription.UNDELETION
  164. def save(self, content: PBNode, action_description: str=None, do_flush=True):
  165. """
  166. Save an object, flush the session and set the last_action property
  167. :param content:
  168. :param action_description:
  169. :return:
  170. """
  171. assert action_description is None or action_description in ActionDescription.allowed_values()
  172. if not action_description:
  173. # See if the last action has been modified
  174. if content.last_action==None or len(get_history(content, 'last_action'))<=0:
  175. # The action has not been modified, so we set it to default edition
  176. action_description = ActionDescription.EDITION
  177. content.last_action = action_description
  178. if do_flush:
  179. DBSession.flush()