|  | @@ -0,0 +1,497 @@
 | 
	
		
			
			|  | 1 | +# coding: utf8
 | 
	
		
			
			|  | 2 | +
 | 
	
		
			
			|  | 3 | +from tracim.lib.webdav import HistoryType
 | 
	
		
			
			|  | 4 | +from tracim.lib.webdav.lock_storage import LockStorage
 | 
	
		
			
			|  | 5 | +
 | 
	
		
			
			|  | 6 | +import re
 | 
	
		
			
			|  | 7 | +from os.path import basename, dirname, normpath
 | 
	
		
			
			|  | 8 | +from tracim.lib.content import ContentApi
 | 
	
		
			
			|  | 9 | +from tracim.lib.webdav import sql_resources
 | 
	
		
			
			|  | 10 | +from tracim.lib.user import UserApi
 | 
	
		
			
			|  | 11 | +from tracim.lib.workspace import WorkspaceApi
 | 
	
		
			
			|  | 12 | +from wsgidav import util
 | 
	
		
			
			|  | 13 | +from wsgidav.dav_provider import DAVProvider
 | 
	
		
			
			|  | 14 | +from wsgidav.lock_manager import LockManager
 | 
	
		
			
			|  | 15 | +from tracim.model.data import ContentType
 | 
	
		
			
			|  | 16 | +
 | 
	
		
			
			|  | 17 | +######################################
 | 
	
		
			
			|  | 18 | +
 | 
	
		
			
			|  | 19 | +__docformat__ = "reStructuredText"
 | 
	
		
			
			|  | 20 | +_logger = util.getModuleLogger(__name__)
 | 
	
		
			
			|  | 21 | +
 | 
	
		
			
			|  | 22 | +
 | 
	
		
			
			|  | 23 | +def wsgi_decode(s):
 | 
	
		
			
			|  | 24 | +    return s.encode('latin1').decode()
 | 
	
		
			
			|  | 25 | +
 | 
	
		
			
			|  | 26 | +def wsgi_encode(s):
 | 
	
		
			
			|  | 27 | +    if isinstance(s, bytes):
 | 
	
		
			
			|  | 28 | +        return s.decode('latin1')
 | 
	
		
			
			|  | 29 | +    return s.encode().decode('latin1')
 | 
	
		
			
			|  | 30 | +
 | 
	
		
			
			|  | 31 | +
 | 
	
		
			
			|  | 32 | +# ============================================================
 | 
	
		
			
			|  | 33 | +# PostgreSQLProvider
 | 
	
		
			
			|  | 34 | +# ============================================================
 | 
	
		
			
			|  | 35 | +class Provider(DAVProvider):
 | 
	
		
			
			|  | 36 | +    def __init__(self, manage_lock=True):
 | 
	
		
			
			|  | 37 | +        super(Provider, self).__init__()
 | 
	
		
			
			|  | 38 | +
 | 
	
		
			
			|  | 39 | +        if manage_lock:
 | 
	
		
			
			|  | 40 | +            self.lockManager = LockManager(LockStorage())
 | 
	
		
			
			|  | 41 | +
 | 
	
		
			
			|  | 42 | +    def __repr__(self):
 | 
	
		
			
			|  | 43 | +        return 'Provider'
 | 
	
		
			
			|  | 44 | +
 | 
	
		
			
			|  | 45 | +    #########################################################
 | 
	
		
			
			|  | 46 | +    # Everything override from DAVProvider
 | 
	
		
			
			|  | 47 | +    def getResourceInst(self, path, environ):
 | 
	
		
			
			|  | 48 | +
 | 
	
		
			
			|  | 49 | +        working_path = path
 | 
	
		
			
			|  | 50 | +
 | 
	
		
			
			|  | 51 | +        if not self.exists(path, environ):
 | 
	
		
			
			|  | 52 | +            return None
 | 
	
		
			
			|  | 53 | +
 | 
	
		
			
			|  | 54 | +        if path == "/":
 | 
	
		
			
			|  | 55 | +            return sql_resources.Root(path, environ)
 | 
	
		
			
			|  | 56 | +
 | 
	
		
			
			|  | 57 | +        norm_path = normpath(working_path)
 | 
	
		
			
			|  | 58 | +
 | 
	
		
			
			|  | 59 | +        user = UserApi(None).get_one_by_email(environ['http_authenticator.username'])
 | 
	
		
			
			|  | 60 | +        workspace_api = WorkspaceApi(user)
 | 
	
		
			
			|  | 61 | +
 | 
	
		
			
			|  | 62 | +        if dirname(norm_path) == "/":
 | 
	
		
			
			|  | 63 | +            workspace = self.get_workspace_from_path(norm_path, workspace_api)
 | 
	
		
			
			|  | 64 | +            return sql_resources.Workspace(path, environ, workspace)
 | 
	
		
			
			|  | 65 | +
 | 
	
		
			
			|  | 66 | +
 | 
	
		
			
			|  | 67 | +        api = ContentApi(user, show_archived=True, show_deleted=True)
 | 
	
		
			
			|  | 68 | +
 | 
	
		
			
			|  | 69 | +        working_path = self.reduce_path(path)
 | 
	
		
			
			|  | 70 | +
 | 
	
		
			
			|  | 71 | +        content = self.get_content_from_path(working_path, api, workspace_api)
 | 
	
		
			
			|  | 72 | +
 | 
	
		
			
			|  | 73 | +        # is archive
 | 
	
		
			
			|  | 74 | +        is_archived_folder = re.search(r'/\.archived$', norm_path) is not None
 | 
	
		
			
			|  | 75 | +
 | 
	
		
			
			|  | 76 | +        if is_archived_folder:
 | 
	
		
			
			|  | 77 | +            return sql_resources.ArchivedFolder(path, environ, content)
 | 
	
		
			
			|  | 78 | +
 | 
	
		
			
			|  | 79 | +        # is delete
 | 
	
		
			
			|  | 80 | +        is_deleted_folder = re.search(r'/\.deleted$', norm_path) is not None
 | 
	
		
			
			|  | 81 | +
 | 
	
		
			
			|  | 82 | +        if is_deleted_folder:
 | 
	
		
			
			|  | 83 | +            return sql_resources.DeletedFolder(path, environ, content)
 | 
	
		
			
			|  | 84 | +
 | 
	
		
			
			|  | 85 | +        # is history
 | 
	
		
			
			|  | 86 | +        is_history_folder = re.search(r'/\.history$', norm_path) is not None
 | 
	
		
			
			|  | 87 | +
 | 
	
		
			
			|  | 88 | +        if is_history_folder:
 | 
	
		
			
			|  | 89 | +            is_deleted_folder = re.search(r'/\.deleted/\.history$', norm_path) is not None
 | 
	
		
			
			|  | 90 | +            is_archived_folder = re.search(r'/\.archived/\.history$', norm_path) is not None
 | 
	
		
			
			|  | 91 | +
 | 
	
		
			
			|  | 92 | +            type = HistoryType.Deleted if is_deleted_folder \
 | 
	
		
			
			|  | 93 | +                else HistoryType.Archived if is_archived_folder \
 | 
	
		
			
			|  | 94 | +                else HistoryType.Standard
 | 
	
		
			
			|  | 95 | +
 | 
	
		
			
			|  | 96 | +            return sql_resources.HistoryFolder(path, environ, content, type)
 | 
	
		
			
			|  | 97 | +
 | 
	
		
			
			|  | 98 | +        # is history
 | 
	
		
			
			|  | 99 | +        is_history_file_folder = re.search(r'/\.history/([^/]+)$', norm_path) is not None
 | 
	
		
			
			|  | 100 | +
 | 
	
		
			
			|  | 101 | +        if is_history_file_folder:
 | 
	
		
			
			|  | 102 | +            return sql_resources.HistoryFileFolder(path, environ, content)
 | 
	
		
			
			|  | 103 | +
 | 
	
		
			
			|  | 104 | +        # is history
 | 
	
		
			
			|  | 105 | +        is_history_file = re.search(r'/\.history/[^/]+/(\d+)-.+', norm_path) is not None
 | 
	
		
			
			|  | 106 | +
 | 
	
		
			
			|  | 107 | +        if is_history_file:
 | 
	
		
			
			|  | 108 | +            content = api.get_one_revision2(re.search(r'/\.history/[^/]+/(\d+)-.+', norm_path).group(1))
 | 
	
		
			
			|  | 109 | +            content_revision = self.get_content_from_revision(re.search(r'/\.history/[^/]+/(\d+)-.+', norm_path).group(1), api)
 | 
	
		
			
			|  | 110 | +
 | 
	
		
			
			|  | 111 | +            if content.type == ContentType.File:
 | 
	
		
			
			|  | 112 | +                return sql_resources.HistoryFile(path, environ, content, content_revision)
 | 
	
		
			
			|  | 113 | +            else:
 | 
	
		
			
			|  | 114 | +                return sql_resources.HistoryOtherFile(path, environ, content, content_revision)
 | 
	
		
			
			|  | 115 | +
 | 
	
		
			
			|  | 116 | +        # other
 | 
	
		
			
			|  | 117 | +        if content.type == ContentType.Folder:
 | 
	
		
			
			|  | 118 | +            return sql_resources.Folder(path, environ, content)
 | 
	
		
			
			|  | 119 | +
 | 
	
		
			
			|  | 120 | +        if content.type == ContentType.File:
 | 
	
		
			
			|  | 121 | +            return sql_resources.File(path, environ, content, False)
 | 
	
		
			
			|  | 122 | +        else:
 | 
	
		
			
			|  | 123 | +            return sql_resources.OtherFile(path, environ, content)
 | 
	
		
			
			|  | 124 | +
 | 
	
		
			
			|  | 125 | +    def exists(self, path, environ):
 | 
	
		
			
			|  | 126 | +        path = normpath(path)
 | 
	
		
			
			|  | 127 | +        if path == "/":
 | 
	
		
			
			|  | 128 | +            return True
 | 
	
		
			
			|  | 129 | +        elif dirname(path) == "/":
 | 
	
		
			
			|  | 130 | +            return self.get_workspace_from_path(
 | 
	
		
			
			|  | 131 | +                path,
 | 
	
		
			
			|  | 132 | +                WorkspaceApi(UserApi(None).get_one_by_email(environ['http_authenticator.username']))
 | 
	
		
			
			|  | 133 | +            ) is not None
 | 
	
		
			
			|  | 134 | +
 | 
	
		
			
			|  | 135 | +        api = ContentApi(
 | 
	
		
			
			|  | 136 | +            current_user=UserApi(None).get_one_by_email(environ['http_authenticator.username']),
 | 
	
		
			
			|  | 137 | +            show_archived=True,
 | 
	
		
			
			|  | 138 | +            show_deleted=True
 | 
	
		
			
			|  | 139 | +        )
 | 
	
		
			
			|  | 140 | +        wapi = WorkspaceApi(UserApi(None).get_one_by_email(environ['http_authenticator.username']))
 | 
	
		
			
			|  | 141 | +
 | 
	
		
			
			|  | 142 | +        norm_path = normpath(path)
 | 
	
		
			
			|  | 143 | +
 | 
	
		
			
			|  | 144 | +        is_archived = re.search(r'/\.archived/(\.history/)?(?!\.history)[^/]*(/\.)?(history|deleted|archived)?$', norm_path) is not None
 | 
	
		
			
			|  | 145 | +
 | 
	
		
			
			|  | 146 | +        is_deleted = re.search(r'/\.deleted/(\.history/)?(?!\.history)[^/]*(/\.)?(history|deleted|archived)?$', norm_path) is not None
 | 
	
		
			
			|  | 147 | +
 | 
	
		
			
			|  | 148 | +        revision_id = re.search(r'/\.history/[^/]+/(\d+)-([^/].+)$', norm_path)
 | 
	
		
			
			|  | 149 | +
 | 
	
		
			
			|  | 150 | +        if revision_id:
 | 
	
		
			
			|  | 151 | +            revision_id = revision_id.group(1)
 | 
	
		
			
			|  | 152 | +            return self.get_content_from_revision(revision_id, api) is not None
 | 
	
		
			
			|  | 153 | +
 | 
	
		
			
			|  | 154 | +        working_path = self.reduce_path(path)
 | 
	
		
			
			|  | 155 | +
 | 
	
		
			
			|  | 156 | +        content = self.get_content_from_path(working_path, api, wapi)
 | 
	
		
			
			|  | 157 | +
 | 
	
		
			
			|  | 158 | +        return content is not None \
 | 
	
		
			
			|  | 159 | +            and content.is_deleted == is_deleted \
 | 
	
		
			
			|  | 160 | +            and content.is_archived == is_archived \
 | 
	
		
			
			|  | 161 | +            and (revision_id is None or content.revision_id == revision_id)
 | 
	
		
			
			|  | 162 | +
 | 
	
		
			
			|  | 163 | +    def reduce_path(self, path):
 | 
	
		
			
			|  | 164 | +        path = re.sub(r'/\.archived', r'', path)
 | 
	
		
			
			|  | 165 | +        path = re.sub(r'/\.deleted', r'', path)
 | 
	
		
			
			|  | 166 | +        path = re.sub(r'/\.history/[^/]+/(\d+)-.+', r'/\1', path)
 | 
	
		
			
			|  | 167 | +        path = re.sub(r'/\.history/([^/]+)', r'/\1', path)
 | 
	
		
			
			|  | 168 | +        path = re.sub(r'/\.history', r'', path)
 | 
	
		
			
			|  | 169 | +
 | 
	
		
			
			|  | 170 | +        return path
 | 
	
		
			
			|  | 171 | +
 | 
	
		
			
			|  | 172 | +    def get_content_from_path(self, path, api: ContentApi, workspace_api: WorkspaceApi):
 | 
	
		
			
			|  | 173 | +        path = normpath(path)
 | 
	
		
			
			|  | 174 | +        workspace = self.get_workspace_from_path(path, workspace_api)
 | 
	
		
			
			|  | 175 | +
 | 
	
		
			
			|  | 176 | +        if basename(dirname(path)) == workspace.label:
 | 
	
		
			
			|  | 177 | +            return api.get_one_by_label_and_parent(basename(path), workspace=workspace)
 | 
	
		
			
			|  | 178 | +        else:
 | 
	
		
			
			|  | 179 | +            parent = self.get_parent_from_path(path, api, workspace_api)
 | 
	
		
			
			|  | 180 | +            if parent is not None:
 | 
	
		
			
			|  | 181 | +                return api.get_one_by_label_and_parent(basename(path), content_parent=parent)
 | 
	
		
			
			|  | 182 | +            return None
 | 
	
		
			
			|  | 183 | +
 | 
	
		
			
			|  | 184 | +    def get_content_from_revision(self, revision_id: int, api:ContentApi):
 | 
	
		
			
			|  | 185 | +        return api.get_one_revision(revision_id)
 | 
	
		
			
			|  | 186 | +
 | 
	
		
			
			|  | 187 | +    def get_parent_from_path(self, path, api: ContentApi, workspace_api: WorkspaceApi):
 | 
	
		
			
			|  | 188 | +        return self.get_content_from_path(dirname(path), api, workspace_api)
 | 
	
		
			
			|  | 189 | +
 | 
	
		
			
			|  | 190 | +    def get_workspace_from_path(self, path: str, api: WorkspaceApi):
 | 
	
		
			
			|  | 191 | +        assert path.startswith('/')
 | 
	
		
			
			|  | 192 | +
 | 
	
		
			
			|  | 193 | +        return api.get_one_by_label(path.split('/')[1])
 | 
	
		
			
			|  | 194 | +
 | 
	
		
			
			|  | 195 | +    #########################################################
 | 
	
		
			
			|  | 196 | +    # Everything that transform path
 | 
	
		
			
			|  | 197 | +    '''
 | 
	
		
			
			|  | 198 | +    def from_id_to_name(self, path):
 | 
	
		
			
			|  | 199 | +        path_ret = ''
 | 
	
		
			
			|  | 200 | +
 | 
	
		
			
			|  | 201 | +        for item_id in path.split('/'):
 | 
	
		
			
			|  | 202 | +            if item_id == '':
 | 
	
		
			
			|  | 203 | +                pass
 | 
	
		
			
			|  | 204 | +            elif path_ret == '':
 | 
	
		
			
			|  | 205 | +                path_ret += '/' + self.get_workspace({'workspace_id': item_id}).label
 | 
	
		
			
			|  | 206 | +            else:
 | 
	
		
			
			|  | 207 | +                path_ret += '/' + self.get_item({'id': item_id}).item_name
 | 
	
		
			
			|  | 208 | +
 | 
	
		
			
			|  | 209 | +        return path_ret
 | 
	
		
			
			|  | 210 | +
 | 
	
		
			
			|  | 211 | +    def from_name_to_id(self, path):
 | 
	
		
			
			|  | 212 | +        if path == '/':
 | 
	
		
			
			|  | 213 | +            return '/'
 | 
	
		
			
			|  | 214 | +        path_ret = ""
 | 
	
		
			
			|  | 215 | +        last_id = None
 | 
	
		
			
			|  | 216 | +        workspace_id = None
 | 
	
		
			
			|  | 217 | +
 | 
	
		
			
			|  | 218 | +        for item_name in path.split("/"):
 | 
	
		
			
			|  | 219 | +            if item_name == '':
 | 
	
		
			
			|  | 220 | +                pass
 | 
	
		
			
			|  | 221 | +            elif path_ret == '':
 | 
	
		
			
			|  | 222 | +                workspace = self.get_workspace({'label': item_name})
 | 
	
		
			
			|  | 223 | +                if workspace is None:
 | 
	
		
			
			|  | 224 | +                    return None
 | 
	
		
			
			|  | 225 | +
 | 
	
		
			
			|  | 226 | +                workspace_id = workspace.workspace_id
 | 
	
		
			
			|  | 227 | +                path_ret += '/' + str(workspace_id)
 | 
	
		
			
			|  | 228 | +            else:
 | 
	
		
			
			|  | 229 | +                item = self.get_item(
 | 
	
		
			
			|  | 230 | +                    {
 | 
	
		
			
			|  | 231 | +                        'parent_id': last_id,
 | 
	
		
			
			|  | 232 | +                        'item_name': item_name,
 | 
	
		
			
			|  | 233 | +                        'workspace_id': workspace_id,
 | 
	
		
			
			|  | 234 | +                        'child_revision_id': None
 | 
	
		
			
			|  | 235 | +                    }
 | 
	
		
			
			|  | 236 | +                )
 | 
	
		
			
			|  | 237 | +
 | 
	
		
			
			|  | 238 | +                if item is None:
 | 
	
		
			
			|  | 239 | +                    return None
 | 
	
		
			
			|  | 240 | +
 | 
	
		
			
			|  | 241 | +                last_id = item.id
 | 
	
		
			
			|  | 242 | +                path_ret += '/' + str(last_id)
 | 
	
		
			
			|  | 243 | +
 | 
	
		
			
			|  | 244 | +        return path_ret
 | 
	
		
			
			|  | 245 | +
 | 
	
		
			
			|  | 246 | +    #########################################################
 | 
	
		
			
			|  | 247 | +    # Everything that check things (lol) ...
 | 
	
		
			
			|  | 248 | +    def has_right(self, username, workspace_id, expected=0):
 | 
	
		
			
			|  | 249 | +        ret = self.session.query(UserRoleInWorkspace.role).filter(
 | 
	
		
			
			|  | 250 | +            UserRoleInWorkspace.workspace_id == workspace_id,
 | 
	
		
			
			|  | 251 | +            User.user_id == UserRoleInWorkspace.user_id,
 | 
	
		
			
			|  | 252 | +            User.display_name == username
 | 
	
		
			
			|  | 253 | +        ).one_or_none()
 | 
	
		
			
			|  | 254 | +
 | 
	
		
			
			|  | 255 | +        return ret is not None and role[ret.role] >= expected
 | 
	
		
			
			|  | 256 | +
 | 
	
		
			
			|  | 257 | +    def exist_revision(self, item_name, item_id):
 | 
	
		
			
			|  | 258 | +        return self.get_item({'id': item_id, 'item_name': item_name}) is not None
 | 
	
		
			
			|  | 259 | +
 | 
	
		
			
			|  | 260 | +    @staticmethod
 | 
	
		
			
			|  | 261 | +    def is_history(path):
 | 
	
		
			
			|  | 262 | +        return normpath(path).endswith('.history')
 | 
	
		
			
			|  | 263 | +
 | 
	
		
			
			|  | 264 | +    #########################################################
 | 
	
		
			
			|  | 265 | +    # Everything that goes with "delete"
 | 
	
		
			
			|  | 266 | +    def delete_item(self, element):
 | 
	
		
			
			|  | 267 | +        self.session.delete(element)
 | 
	
		
			
			|  | 268 | +        self.session.commit()
 | 
	
		
			
			|  | 269 | +
 | 
	
		
			
			|  | 270 | +    #########################################################
 | 
	
		
			
			|  | 271 | +    # Everything that goes with "add"
 | 
	
		
			
			|  | 272 | +    def add_item(self, item_name, item_type, workspace_id, parent_id=None, parent_revision_id=None,
 | 
	
		
			
			|  | 273 | +                 child_revision_id=None, item_content=None, created=None, updated=None):
 | 
	
		
			
			|  | 274 | +
 | 
	
		
			
			|  | 275 | +        item = ItemRevision(
 | 
	
		
			
			|  | 276 | +            item_name=to_unicode(item_name),
 | 
	
		
			
			|  | 277 | +            item_type=to_unicode(item_type),
 | 
	
		
			
			|  | 278 | +            item_content=item_content,
 | 
	
		
			
			|  | 279 | +            workspace_id=workspace_id,
 | 
	
		
			
			|  | 280 | +            parent_id=parent_id,
 | 
	
		
			
			|  | 281 | +            created=created,
 | 
	
		
			
			|  | 282 | +            updated=updated,
 | 
	
		
			
			|  | 283 | +            parent_revision_id=parent_revision_id,
 | 
	
		
			
			|  | 284 | +            child_revision_id=child_revision_id
 | 
	
		
			
			|  | 285 | +        )
 | 
	
		
			
			|  | 286 | +
 | 
	
		
			
			|  | 287 | +        self.session.add(item)
 | 
	
		
			
			|  | 288 | +        self.session.commit()
 | 
	
		
			
			|  | 289 | +
 | 
	
		
			
			|  | 290 | +        return item
 | 
	
		
			
			|  | 291 | +
 | 
	
		
			
			|  | 292 | +    def add_workspace(self, environ, label):
 | 
	
		
			
			|  | 293 | +        workspace = Workspace(label=label)
 | 
	
		
			
			|  | 294 | +
 | 
	
		
			
			|  | 295 | +        self.session.add(workspace)
 | 
	
		
			
			|  | 296 | +
 | 
	
		
			
			|  | 297 | +        user = self.get_user_with_name(environ['http_authenticator.username'])
 | 
	
		
			
			|  | 298 | +
 | 
	
		
			
			|  | 299 | +        user_workspace = UserRoleInWorkspace(
 | 
	
		
			
			|  | 300 | +            role='WORKSPACE_MANAGER',
 | 
	
		
			
			|  | 301 | +            workspace_id=workspace.workspace_id,
 | 
	
		
			
			|  | 302 | +            user_id=user.user_id
 | 
	
		
			
			|  | 303 | +        )
 | 
	
		
			
			|  | 304 | +
 | 
	
		
			
			|  | 305 | +        self.session.add(user_workspace)
 | 
	
		
			
			|  | 306 | +        self.session.commit()
 | 
	
		
			
			|  | 307 | +
 | 
	
		
			
			|  | 308 | +        return workspace
 | 
	
		
			
			|  | 309 | +
 | 
	
		
			
			|  | 310 | +    #########################################################
 | 
	
		
			
			|  | 311 | +    # Everything that goes with "set"
 | 
	
		
			
			|  | 312 | +    def set_workspace_label(self, workspace, label):
 | 
	
		
			
			|  | 313 | +        workspace.label = label
 | 
	
		
			
			|  | 314 | +        self.session.commit()
 | 
	
		
			
			|  | 315 | +
 | 
	
		
			
			|  | 316 | +    #########################################################
 | 
	
		
			
			|  | 317 | +    # Everything that goes with "get"
 | 
	
		
			
			|  | 318 | +    def get_all_revisions_from_item(self, item, only_id=False):
 | 
	
		
			
			|  | 319 | +        ret = []
 | 
	
		
			
			|  | 320 | +        current_item = item
 | 
	
		
			
			|  | 321 | +        while current_item is not None:
 | 
	
		
			
			|  | 322 | +            if only_id:
 | 
	
		
			
			|  | 323 | +                ret.insert(0,current_item.id)
 | 
	
		
			
			|  | 324 | +            else:
 | 
	
		
			
			|  | 325 | +                ret.insert(0,current_item)
 | 
	
		
			
			|  | 326 | +
 | 
	
		
			
			|  | 327 | +            current_item = self.get_item(
 | 
	
		
			
			|  | 328 | +                {
 | 
	
		
			
			|  | 329 | +                    'child_revision_id': current_item.id
 | 
	
		
			
			|  | 330 | +                }
 | 
	
		
			
			|  | 331 | +            )
 | 
	
		
			
			|  | 332 | +
 | 
	
		
			
			|  | 333 | +        return ret
 | 
	
		
			
			|  | 334 | +
 | 
	
		
			
			|  | 335 | +    def get_item(self, keys_dict):
 | 
	
		
			
			|  | 336 | +        query = self.session.query(ItemRevision)
 | 
	
		
			
			|  | 337 | +
 | 
	
		
			
			|  | 338 | +        for key, value in keys_dict.items():
 | 
	
		
			
			|  | 339 | +            query = query.filter(getattr(ItemRevision, key) == value)
 | 
	
		
			
			|  | 340 | +        return query.first()
 | 
	
		
			
			|  | 341 | +
 | 
	
		
			
			|  | 342 | +    def get_item_children(self, item_id):
 | 
	
		
			
			|  | 343 | +        items_result = self.session.query(ItemRevision.id).filter(
 | 
	
		
			
			|  | 344 | +            ItemRevision.parent_id == item_id,
 | 
	
		
			
			|  | 345 | +            ItemRevision.child_revision_id.is_(None)
 | 
	
		
			
			|  | 346 | +        )
 | 
	
		
			
			|  | 347 | +
 | 
	
		
			
			|  | 348 | +        ret_id = []
 | 
	
		
			
			|  | 349 | +        for item in items_result:
 | 
	
		
			
			|  | 350 | +            ret_id.append(item.id)
 | 
	
		
			
			|  | 351 | +
 | 
	
		
			
			|  | 352 | +        return ret_id
 | 
	
		
			
			|  | 353 | +
 | 
	
		
			
			|  | 354 | +    def get_workspace_id_from_path(self, path):
 | 
	
		
			
			|  | 355 | +        return int(self.get_id_from_path('/' + path.split('/')[1]))
 | 
	
		
			
			|  | 356 | +
 | 
	
		
			
			|  | 357 | +    def get_workspace_children_id(self, workspace):
 | 
	
		
			
			|  | 358 | +        items_result = self.session.query(ItemRevision.id).filter(
 | 
	
		
			
			|  | 359 | +            ItemRevision.parent_id.is_(None),
 | 
	
		
			
			|  | 360 | +            ItemRevision.workspace_id == workspace.workspace_id
 | 
	
		
			
			|  | 361 | +        )
 | 
	
		
			
			|  | 362 | +
 | 
	
		
			
			|  | 363 | +        ret = []
 | 
	
		
			
			|  | 364 | +        for item in items_result:
 | 
	
		
			
			|  | 365 | +            ret.append(item.id)
 | 
	
		
			
			|  | 366 | +
 | 
	
		
			
			|  | 367 | +        return ret
 | 
	
		
			
			|  | 368 | +
 | 
	
		
			
			|  | 369 | +    # on workspaces
 | 
	
		
			
			|  | 370 | +    def get_workspace(self, keys_dict):
 | 
	
		
			
			|  | 371 | +        query = self.session.query(Workspace)
 | 
	
		
			
			|  | 372 | +
 | 
	
		
			
			|  | 373 | +        for key, value in keys_dict.items():
 | 
	
		
			
			|  | 374 | +            query = query.filter(getattr(Workspace, key) == value)
 | 
	
		
			
			|  | 375 | +        return query.one_or_none()
 | 
	
		
			
			|  | 376 | +
 | 
	
		
			
			|  | 377 | +    def get_all_workspaces(self, only_name=False):
 | 
	
		
			
			|  | 378 | +        retlist = []
 | 
	
		
			
			|  | 379 | +        for workspace in self.session.query(Workspace).all():
 | 
	
		
			
			|  | 380 | +            if only_name:
 | 
	
		
			
			|  | 381 | +                retlist.append(workspace.label)
 | 
	
		
			
			|  | 382 | +            else:
 | 
	
		
			
			|  | 383 | +                retlist.append(workspace)
 | 
	
		
			
			|  | 384 | +
 | 
	
		
			
			|  | 385 | +        return retlist
 | 
	
		
			
			|  | 386 | +
 | 
	
		
			
			|  | 387 | +    # on users
 | 
	
		
			
			|  | 388 | +    def get_user_with_name(self, username):
 | 
	
		
			
			|  | 389 | +        return self.session.query(User).filter(
 | 
	
		
			
			|  | 390 | +            User.display_name == username
 | 
	
		
			
			|  | 391 | +        ).one_or_none()
 | 
	
		
			
			|  | 392 | +
 | 
	
		
			
			|  | 393 | +    # on path
 | 
	
		
			
			|  | 394 | +    def get_id_from_path(self, path):
 | 
	
		
			
			|  | 395 | +        path_id = self.from_name_to_id(path)
 | 
	
		
			
			|  | 396 | +
 | 
	
		
			
			|  | 397 | +        if path_id == '/':
 | 
	
		
			
			|  | 398 | +            return None
 | 
	
		
			
			|  | 399 | +        else:
 | 
	
		
			
			|  | 400 | +            return int(basename(path_id))
 | 
	
		
			
			|  | 401 | +
 | 
	
		
			
			|  | 402 | +    def get_parent_id_from_path(self, path):
 | 
	
		
			
			|  | 403 | +        return self.get_id_from_path(dirname(path))
 | 
	
		
			
			|  | 404 | +
 | 
	
		
			
			|  | 405 | +    #########################################################
 | 
	
		
			
			|  | 406 | +    # Everything that goes with "move"
 | 
	
		
			
			|  | 407 | +    def move_item(self, item, destpath):
 | 
	
		
			
			|  | 408 | +        path = normpath(destpath)
 | 
	
		
			
			|  | 409 | +
 | 
	
		
			
			|  | 410 | +        if dirname(dirname(path)) == '/':
 | 
	
		
			
			|  | 411 | +            new_parent = None
 | 
	
		
			
			|  | 412 | +        else:
 | 
	
		
			
			|  | 413 | +            new_parent = self.get_parent_id_from_path(path)
 | 
	
		
			
			|  | 414 | +
 | 
	
		
			
			|  | 415 | +        item.parent_id = new_parent
 | 
	
		
			
			|  | 416 | +        item.workspace_id = self.get_workspace_id_from_path(path)
 | 
	
		
			
			|  | 417 | +        item.item_name = basename(path)
 | 
	
		
			
			|  | 418 | +        self.session.commit()
 | 
	
		
			
			|  | 419 | +
 | 
	
		
			
			|  | 420 | +    def move_all_revisions(self, item, destpath):
 | 
	
		
			
			|  | 421 | +        path = normpath(destpath)
 | 
	
		
			
			|  | 422 | +        new_parent = self.get_parent_id_from_path(path)
 | 
	
		
			
			|  | 423 | +        new_workspace = self.get_workspace_id_from_path(destpath)
 | 
	
		
			
			|  | 424 | +
 | 
	
		
			
			|  | 425 | +        items = self.get_all_revisions_from_item(item)
 | 
	
		
			
			|  | 426 | +
 | 
	
		
			
			|  | 427 | +        for current_item in items:
 | 
	
		
			
			|  | 428 | +            current_item.parent_id = new_parent
 | 
	
		
			
			|  | 429 | +            current_item.workspace_id = new_workspace
 | 
	
		
			
			|  | 430 | +
 | 
	
		
			
			|  | 431 | +        new_name = basename(normpath(destpath))
 | 
	
		
			
			|  | 432 | +
 | 
	
		
			
			|  | 433 | +        new_item = self.add_item(
 | 
	
		
			
			|  | 434 | +            item_name=new_name,
 | 
	
		
			
			|  | 435 | +            item_type=item.item_type,
 | 
	
		
			
			|  | 436 | +            workspace_id=item.workspace_id,
 | 
	
		
			
			|  | 437 | +            parent_id=item.parent_id,
 | 
	
		
			
			|  | 438 | +            parent_revision_id=item.id,
 | 
	
		
			
			|  | 439 | +            child_revision_id=None,
 | 
	
		
			
			|  | 440 | +            item_content=item.item_content,
 | 
	
		
			
			|  | 441 | +            created=item.created,
 | 
	
		
			
			|  | 442 | +            updated=datetime.now()
 | 
	
		
			
			|  | 443 | +        )
 | 
	
		
			
			|  | 444 | +
 | 
	
		
			
			|  | 445 | +        item.child_revision_id = new_item.id
 | 
	
		
			
			|  | 446 | +
 | 
	
		
			
			|  | 447 | +        self.session.commit()
 | 
	
		
			
			|  | 448 | +
 | 
	
		
			
			|  | 449 | +    #########################################################
 | 
	
		
			
			|  | 450 | +    # Everything that goes with "copy"
 | 
	
		
			
			|  | 451 | +    def copy_item(self, item, destpath):
 | 
	
		
			
			|  | 452 | +        path = normpath(destpath)
 | 
	
		
			
			|  | 453 | +
 | 
	
		
			
			|  | 454 | +        new_parent = self.get_parent_id_from_path(path)
 | 
	
		
			
			|  | 455 | +        new_workspace = self.get_workspace_id_from_path(path)
 | 
	
		
			
			|  | 456 | +        items = self.get_all_revisions_from_item(item)
 | 
	
		
			
			|  | 457 | +
 | 
	
		
			
			|  | 458 | +        first = True
 | 
	
		
			
			|  | 459 | +        last_item = None
 | 
	
		
			
			|  | 460 | +
 | 
	
		
			
			|  | 461 | +        for current_item in items:
 | 
	
		
			
			|  | 462 | +            new_item = self.add_item(
 | 
	
		
			
			|  | 463 | +                item_name=current_item.item_name,
 | 
	
		
			
			|  | 464 | +                item_type=current_item.item_type,
 | 
	
		
			
			|  | 465 | +                workspace_id=new_workspace,
 | 
	
		
			
			|  | 466 | +                parent_id=new_parent,
 | 
	
		
			
			|  | 467 | +                parent_revision_id=None,
 | 
	
		
			
			|  | 468 | +                child_revision_id=None,
 | 
	
		
			
			|  | 469 | +                item_content=current_item.item_content,
 | 
	
		
			
			|  | 470 | +                created=current_item.created,
 | 
	
		
			
			|  | 471 | +                updated=current_item.updated
 | 
	
		
			
			|  | 472 | +            )
 | 
	
		
			
			|  | 473 | +
 | 
	
		
			
			|  | 474 | +            if not first:
 | 
	
		
			
			|  | 475 | +                last_item.child_revision_id = new_item.id
 | 
	
		
			
			|  | 476 | +                new_item.parent_revision_id = last_item.id
 | 
	
		
			
			|  | 477 | +
 | 
	
		
			
			|  | 478 | +            first = False
 | 
	
		
			
			|  | 479 | +            last_item = new_item
 | 
	
		
			
			|  | 480 | +
 | 
	
		
			
			|  | 481 | +        new_name = basename(destpath)
 | 
	
		
			
			|  | 482 | +        
 | 
	
		
			
			|  | 483 | +        new_item = self.add_item(
 | 
	
		
			
			|  | 484 | +            item_name=new_name,
 | 
	
		
			
			|  | 485 | +            item_type=item.item_type,
 | 
	
		
			
			|  | 486 | +            workspace_id=new_workspace,
 | 
	
		
			
			|  | 487 | +            parent_id=new_parent,
 | 
	
		
			
			|  | 488 | +            parent_revision_id=last_item.id,
 | 
	
		
			
			|  | 489 | +            child_revision_id=None,
 | 
	
		
			
			|  | 490 | +            item_content=item.item_content,
 | 
	
		
			
			|  | 491 | +            created=datetime.now(),
 | 
	
		
			
			|  | 492 | +            updated=datetime.now()
 | 
	
		
			
			|  | 493 | +        )
 | 
	
		
			
			|  | 494 | +
 | 
	
		
			
			|  | 495 | +        last_item.child_revision_id = new_item.id
 | 
	
		
			
			|  | 496 | +
 | 
	
		
			
			|  | 497 | +        self.session.commit()'''
 |