def delete_access_perms(node, access_list): """ same input as for set_access_perms """ access_diff_d = Diff(operation=Diff.DELETE) # by the user for access_item in node.access_set.all(): if access_item.user: name = access_item.user.username model_type = 'user' elif access_item.group: name = access_item.group.name model_type = 'group' # if node's access list contains items # which are in access_list - delete respective # node's access filtered = [ x for x in access_list if x['model'] == model_type and x['name'] == name ] if len(filtered) > 0: # further propagation is done via pre_delete # signals for Access models access_diff_d.add(access_item) access_item.delete() return [access_diff_d]
def node_post_save(sender, node, created, *kwargs): if created: # New node instance was created. # Create associated Access Model: # node creater has full access. create_access( node=node, model_type=Access.MODEL_USER, name=node.user.username, access_type=Access.ALLOW, access_inherited=False, permissions=Access.OWNER_PERMS_MAP # full access ) # Consider this two persons use case: # User uploader uploads scans for user margaret. # Initially document is in uploader's Inbox folder. # Afterwards, uploader moves new document X into common shared_folder. # shared_folder has full access permissions for # boths uploader and margaret. # When margaret sees document X, she copies it into # her private folder X_margaret_fld. X_margaret_fld is # owned only by margaret. # Now document X's path is margaret//X_margaret_fld/X.pdf # If X.pdf access permissions stay same, then uploader will # still have access to X.pdf (via search) which means, # that margaret will need to change manually X.pdf's # access permissions. To avoid manual change of access # permissions from margaret side - papermerge feature # is that X.pdf inherits access permissions from new # parent (X_margaret_fld). Thus, just by copying it, # X.pdf becomes margaret private doc - and uploader # lose its access to it. if node.parent: # current node has a parent? # Following statement covers case when node # is moved from one parent to another parent. # When node moved from one parent to another # it get all its access replaced by access list of the # parent access_diff = Diff(operation=Diff.REPLACE, instances_set=node.parent.access_set.all()) node.propagate_changes(diffs_set=[access_diff], apply_to_self=True) else: # In case node has no parent, all its access permission # remain the same. pass
def test_changes_resursive_inheritance(self): """ 1. uploader creates: F1 -> L1a -> L2a -> L3a F1 -> L1b -> L2b 2. Uploader gives read access to margaret on F1 3. Margaret will have read access on L1a, L1b, L2a, L2b, L3a as well (because of recursive inheritance) """ F1 = Folder.objects.create(title="F1", user=self.uploader_user) L1a = Folder.objects.create(title="L1a", user=self.uploader_user, parent=F1) L2a = Folder.objects.create(title="L2a", user=self.uploader_user, parent=L1a) L3a = Folder.objects.create(title="L3a", user=self.uploader_user, parent=L2a) L1b = Folder.objects.create(title="L1b", user=self.uploader_user, parent=F1) L2b = Folder.objects.create(title="L2b", user=self.uploader_user, parent=L1b) # give margaret read access on topmost folder new_access = create_access( node=F1, model_type=Access.MODEL_USER, name=self.margaret_user, access_type=Access.ALLOW, access_inherited=False, permissions={READ: True} # allow read access to margaret ) # function which does the trick access_diff = Diff(operation=Diff.ADD, instances_set=[new_access]) F1.propagate_changes(diffs_set=[access_diff], apply_to_self=True) # and assert for folder in [F1, L1a, L1b, L2a, L3a, L2b]: self.assertTrue(self.margaret_user.has_perm(READ, folder), f"margaret: Failed for folder {folder.title}") # uploader still has full access ? self.assertTrue(self.uploader_user.has_perms(FULL_ACCESS, folder), f"uploader: Failed for folder {folder.title}")
def set_access_perms(node, access_list): """ node is an instance of core.models.BaseTreeNode access is an array/list of hashes of following format: access = [ { 'model': 'user', 'access_type': 'allow', 'name': 'margaret', 'permissions': { 'read': true, 'write': true, 'delete': true, 'change_perm': true, 'take_ownership': true } }, { 'model': 'group', 'access_type': 'allow', 'name': 'employee', 'permissions': { 'read': true, 'write': true, 'delete': true, 'change_perm': true, 'take_ownership': true } }, ... ] """ # first, add new access entries to the node # or update existing onces. access_diff_u = Diff(operation=Diff.UPDATE) access_diff_a = Diff(operation=Diff.ADD) for access_hash in access_list: access = get_access_for( node=node, model_type=access_hash['model'], name=access_hash['name'] ) if access: if access.perm_diff(access_hash['permissions']): access.set_perms(access_hash['permissions']) access_diff_u.add(access) else: access = create_access( node=node, model_type=access_hash['model'], name=access_hash['name'], access_type=access_hash['access_type'], access_inherited=False, permissions=access_hash['permissions'] ) access_diff_a.add(access) ret = [] if len(access_diff_a) > 0: ret.append(access_diff_a) if len(access_diff_u) > 0: ret.append(access_diff_u) return ret