-
Notifications
You must be signed in to change notification settings - Fork 74
[#505] create an atomic ACLs endpoint #808
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7a81184
228bf86
d277eb7
64b8701
1803dda
d419d0e
a746e2a
ef0fe69
b70413d
8a656a0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -91,6 +91,19 @@ | |
| self.user_zone = user_zone | ||
| self.user_type = user_type | ||
|
|
||
| def __lt__(self, other): | ||
| return ( | ||
| self.access_name, | ||
| self.user_name, | ||
| self.user_zone, | ||
| iRODSPath(self.path) | ||
| ) < ( | ||
| other.access_name, | ||
| other.user_name, | ||
| other.user_zone, | ||
| iRODSPath(other.path) | ||
| ) | ||
|
|
||
| def __eq__(self, other): | ||
| return ( | ||
| self.access_name == other.access_name | ||
|
|
@@ -102,8 +115,9 @@ | |
| def __hash__(self): | ||
| return hash((self.access_name, iRODSPath(self.path), self.user_name, self.user_zone)) | ||
|
|
||
| def copy(self, decanonicalize=False): | ||
| def copy(self, decanonicalize=False, implied_zone=''): | ||
| other = copy.deepcopy(self) | ||
|
|
||
| if decanonicalize: | ||
| replacement_string = { | ||
| "read object": "read", | ||
|
|
@@ -112,6 +126,11 @@ | |
| "modify_object": "write", | ||
| }.get(self.access_name) | ||
| other.access_name = replacement_string if replacement_string is not None else self.access_name | ||
|
|
||
| # Useful if we wish to force an explicitly specified local zone to null length for equality testing: | ||
| if '' != implied_zone == other.user_zone: | ||
| other.user_zone = '' | ||
|
|
||
| return other | ||
|
|
||
| def __repr__(self): | ||
|
|
@@ -121,6 +140,43 @@ | |
| return f"<iRODSAccess {access_name} {self.path} {self.user_name}{user_type_hint} {self.user_zone}>" | ||
|
|
||
|
|
||
| class ACLOperation(iRODSAccess): | ||
|
Check failure on line 143 in irods/access.py
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the reason behind inheriting from
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The benefits are basically that we can test equality and therefore is I think the only other benefit is code reuse. |
||
|
|
||
| def __init__(self, access_name: str, user_name: str="", user_zone: str=""): | ||
| super().__init__( | ||
| access_name=access_name, | ||
| path="", | ||
| user_name=user_name, | ||
| user_zone=user_zone, | ||
| ) | ||
|
|
||
| def __eq__(self, other): | ||
| return ( | ||
| self.access_name, | ||
| self.user_name, | ||
| self.user_zone, | ||
| ) == ( | ||
| other.access_name, | ||
| other.user_name, | ||
| other.user_zone, | ||
| ) | ||
|
|
||
| def __lt__(self, other): | ||
| return ( | ||
| self.access_name, | ||
| self.user_name, | ||
| self.user_zone, | ||
| ) < ( | ||
| other.access_name, | ||
| other.user_name, | ||
| other.user_zone, | ||
| ) | ||
|
|
||
| def __repr__(self): | ||
| return f"<ACLOperation: access_name={self.access_name!r} "\ | ||
| f"user_name={self.user_name!r} "\ | ||
| f"user_zone={self.user_zone!r}>" | ||
|
Check failure on line 178 in irods/access.py
|
||
|
|
||
| class _iRODSAccess_pre_4_3_0(iRODSAccess): | ||
| codes = collections.OrderedDict( | ||
| (key.replace("_", " "), value) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,7 @@ | |
| import sys | ||
| import unittest | ||
|
|
||
| from irods.access import iRODSAccess | ||
| from irods.access import iRODSAccess, ACLOperation | ||
| from irods.collection import iRODSCollection | ||
| from irods.column import In, Like | ||
| from irods.exception import UserDoesNotExist | ||
|
|
@@ -497,6 +497,44 @@ | |
| self.sess, | ||
| ) | ||
|
|
||
| def test_atomic_acls_505(self): | ||
| ses = self.sess | ||
| zone = user1 = user2 = user3 = group = None | ||
| try: | ||
| zone = ses.zones.create("twilight","remote") | ||
| user1 = ses.users.create("test_user_505", "rodsuser") | ||
| user2 = ses.users.create("rod_serling_505#twilight", "rodsuser") | ||
| user3 = ses.users.create("local_test_user_505", "rodsuser") | ||
| group = ses.groups.create("test_group_505") | ||
| ses.acls.apply_atomic_acl_operations( | ||
| self.coll_path, | ||
| a1:=ACLOperation("write", user1.name, user1.zone), | ||
| a2:=ACLOperation("read", user2.name, user2.zone), | ||
| a3:=ACLOperation("read", user3.name, user3.zone), | ||
| a4:=ACLOperation("read", group.name), | ||
| ) | ||
|
|
||
| normalize = lambda access: access.copy(decanonicalize=True, implied_zone=ses.zone) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does this line do?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is used to "flatten" iRODSAccess and ACLOperations to render common values into the appropriate fields to satisfy eq , ie. allow them to be "de facto equal" for test's purposes when they should be considered equivalent. THus we can effectively satisfy, for instance: |
||
|
|
||
| accesses = [normalize(acl) for acl in ses.acls.get(self.coll)] | ||
|
|
||
| # Assert that the ACLs we added are among those listed for the object in the catalog. | ||
| self.assertIn(normalize(a1), accesses) | ||
| self.assertIn(normalize(a2), accesses) | ||
| self.assertIn(normalize(a3), accesses) | ||
| self.assertIn(normalize(a4), accesses) | ||
|
|
||
| finally: | ||
| if user1: | ||
| user1.remove() | ||
| if user2: | ||
| user2.remove() | ||
| if user3: | ||
| user3.remove() | ||
| if group: | ||
| group.remove() | ||
| if zone: | ||
| zone.remove() | ||
|
|
||
| if __name__ == "__main__": | ||
| # let the tests find the parent irods lib | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is
implied_zone?Do we expect users of the PRC to ever use this parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's useful for comparison purposes if you can tell
__eq__that a null length zone field implies the current zone name.