Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions irods/manager/user_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,38 @@ def remove_quota(self, user_name, resource="total"):
self._get_session, "set-quota", "user", user_name, resource, "0"
)

@staticmethod
def _parse_user_and_zone(user_param, zone_param):
"""
Parse out user and zone components from the arguments given.

Args:
user_param: either a simple user name, or a combination of both
user and zone names joined with "#".
zone_param: a simple zone name,

Returns:
The resulting parsed user and zone.

Raises:
RuntimeError: in the case of formatting errors or conflicting zone names.
"""
if '#' in user_param:
u_parsed_user, u_parsed_zone = user_param.split('#', 1)
if not u_parsed_zone:
raise RuntimeError("The compound user#zone specification may not contain a zero-length zone")
if '#' in u_parsed_zone:
raise RuntimeError(f"{u_parsed_zone = } is wrongly formatted")
if zone_param and (u_parsed_zone != zone_param):
raise RuntimeError(
f"Two nonzero-length zone names ({u_parsed_zone}, {zone_param}) were given, but they do not agree."
)
return u_parsed_user, u_parsed_zone
return user_param, zone_param

def get(self, user_name, user_zone=""):
user_name, user_zone = self._parse_user_and_zone(user_name, user_zone)

if not user_zone:
user_zone = self.sess.zone

Expand Down Expand Up @@ -121,15 +152,20 @@ def create(self, user_name, user_type, user_zone="", auth_str=""):
def remove(self, user_name, user_zone="", _object=None):
if _object is None:
_object = self.get(user_name, user_zone)

if _object.type == "rodsgroup": # noqa: SIM108
uz_args = (f"{_object.name}",)
else:
uz_args = (f"{_object.name}#{_object.zone}",)

message_body = GeneralAdminRequest(
"rm",
(
"user"
if (_object.type != "rodsgroup" or self.sess.server_version < (4, 3, 2))
else "group"
),
user_name,
user_zone,
*uz_args,
)
request = iRODSMessage(
"RODS_API_REQ", msg=message_body, int_info=api_number["GENERAL_ADMIN_AN"]
Expand Down
42 changes: 36 additions & 6 deletions irods/test/admin_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@
import os
import sys
import unittest
from irods.models import User, Group

import irods.keywords as kw
from irods.column import Like
from irods.exception import (
UserDoesNotExist,
ResourceDoesNotExist,
SYS_NO_API_PRIV,
ResourceDoesNotExist,
UserDoesNotExist,
)
from irods.session import iRODSSession
from irods.models import Collection, Group, User
from irods.resource import iRODSResource
import irods.test.helpers as helpers
import irods.keywords as kw
from irods.session import iRODSSession
from irods.test import helpers


class TestAdmin(unittest.TestCase):
Expand Down Expand Up @@ -531,6 +533,34 @@ def test_set_user_info(self):
with self.assertRaises(UserDoesNotExist):
self.sess.users.get(self.new_user_name)

def test_deleting_remote_user_including_home_collection_and_trash_artifact__issue_763(self):
# Test and confirm that, when passing user and zone parameters separately in calls to
# remove remote users, that both /tempZone/home/user#zone and /tempZone/trash/home/user#zone
# are deleted.
remote_zone = remote_user = None
try:
remote_zone = (sess := self.sess).zones.create('other_zone', 'remote')
remote_user = sess.users.create(user_name='myuser', user_type='rodsuser', user_zone=remote_zone.name)

def get_collection_artifacts():
return list(
sess.query(Collection).filter(Like(Collection.name, f'%/{remote_user.name}#{remote_zone.name}'))
)

# Two collection artifacts should be present, with names:
# /<local_zone>/home/remote_user#remote_zone
# /<local_zone>/trash/home/remote_user#remote_zone
self.assertEqual(len(get_collection_artifacts()), 2)

remote_user.remove()

# The above-mentioned artifacts should have been deleted along with the remote user.
self.assertEqual(len(get_collection_artifacts()), 0)

finally:
if remote_zone:
remote_zone.remove()


if __name__ == "__main__":
# let the tests find the parent irods lib
Expand Down
1 change: 1 addition & 0 deletions irods/test/user_group_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ def generator(p=OLDPASS):
shutil.rmtree(ENV_DIR)
ses.users.remove("alice")


def test_modifying_password_at_various_lengths__issue_328(self):
ses = self.sess
try:
Expand Down