Skip to content
34 changes: 32 additions & 2 deletions irods/manager/user_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,32 @@
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 user_param and zone_param.

Return:
The parsed user and zone.

Raise:
RuntimeError in the case of formatting errors or conflicting zone names.
"""

Check failure on line 57 in irods/manager/user_manager.py

View workflow job for this annotation

GitHub Actions / ruff-lint / ruff-check

Ruff DOC501

DOC501: Raised exception `RuntimeError` missing from docstring [pydoclint:docstring-missing-exception]

Check failure on line 57 in irods/manager/user_manager.py

View workflow job for this annotation

GitHub Actions / ruff-lint / ruff-check

Ruff DOC201

DOC201: `return` is not documented in docstring [pydoclint:docstring-missing-returns]

Check failure on line 57 in irods/manager/user_manager.py

View workflow job for this annotation

GitHub Actions / ruff-lint / ruff-check

Ruff D213

D213: Multi-line docstring summary should start at the second line [pydocstyle:multi-line-summary-second-line]
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 +146,20 @@
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
Loading