Skip to content

Commit

Permalink
Make auto lookup optional
Browse files Browse the repository at this point in the history
- Introduce a new flag at init called 'with_lookup', by default set to True
- If set to True, it will emit a warning to the end user at initialization
- If set to True, automatic user lookup will be performed for the 'add_watcher', 'remove_watcher' and 'assign_issue' methods
  • Loading branch information
dimitarOnGithub committed Sep 12, 2024
1 parent 974296e commit 790732d
Showing 1 changed file with 66 additions and 9 deletions.
75 changes: 66 additions & 9 deletions jira/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ def __init__(
kerberos_options: dict[str, Any] | None = None,
validate=False,
get_server_info: bool = True,
with_lookup: bool = True,
async_: bool = False,
async_workers: int = 5,
logging: bool = True,
Expand Down Expand Up @@ -665,6 +666,12 @@ def __init__(
else:
self._version = (0, 0, 0)

self.with_lookup = with_lookup
if with_lookup:
warnings.warn(f"Auto-lookup (with_lookup) has been set to True, the library will look-up the provided user "
f"for its 'add_watcher', 'remove_watcher' and 'assign_issue' methods; this functionality "
f"will be deprecated in future releases")

if self._options["check_update"] and not JIRA.checked_version:
self._check_update_()
JIRA.checked_version = True
Expand Down Expand Up @@ -2210,7 +2217,7 @@ def createmeta(
params["expand"] = expand
return self._get_json("issue/createmeta", params)

def get_user_identifier(self, user: User) -> str:
def _get_user_identifier(self, user: User) -> str:
"""Get the unique identifier depending on the deployment type.
- Cloud: 'accountId'
Expand All @@ -2224,9 +2231,47 @@ def get_user_identifier(self, user: User) -> str:
"""
return user.accountId if self._is_cloud else user.name

def _get_user_id(self, user: str | None) -> str | None:
"""Internal method for translating a user search (str) to an id.
Return None and -1 unchanged.
This function uses :py:meth:`JIRA.search_users` to find the user and then using :py:meth:`JIRA._get_user_identifier` extracts
the relevant identifier property depending on whether the instance is a Cloud or self-hosted Instance.
Args:
user (Optional[str]): The search term used for finding a user. None, '-1' and -1 are equivalent to 'Unassigned'.
Raises:
JIRAError: If any error occurs.
Returns:
Optional[str]: The Jira user's identifier. Or "-1" and None unchanged.
"""
if user in (None, -1, "-1"):
return user
try:
user_obj: User
if self._is_cloud:
users = self.search_users(query=user, maxResults=20)
else:
users = self.search_users(user=user, maxResults=20)

if len(users) < 1:
raise JIRAError(f"No matching user found for: '{user}'")

matches = []
if len(users) > 1:
matches = [u for u in users if self._get_user_identifier(u) == user]
user_obj = matches[0] if matches else users[0]

except Exception as e:
raise JIRAError(str(e))
return self._get_user_identifier(user_obj)

# non-resource
@translate_resource_args
def assign_issue(self, issue: int | str, assignee: str | None | User) -> bool:
def assign_issue(self, issue: int | str, assignee: str | User | None) -> bool:
"""Assign an issue to a user.
Args:
Expand All @@ -2240,8 +2285,12 @@ def assign_issue(self, issue: int | str, assignee: str | None | User) -> bool:
"""
url = self._get_latest_url(f"issue/{issue}/assignee")
if isinstance(assignee, User):
assignee = self.get_user_identifier(assignee)
payload = {"accountId": assignee} if self._is_cloud else {"name": assignee}
user_id = self._get_user_identifier(assignee)
else:
user_id = assignee
if self.with_lookup:
user_id = self._get_user_id(user_id)
payload = {"accountId": user_id} if self._is_cloud else {"name": user_id}
self._session.put(url, data=json.dumps(payload))
return True

Expand Down Expand Up @@ -2698,25 +2747,33 @@ def add_watcher(self, issue: str | int, watcher: str | User) -> Response:
"""
url = self._get_url("issue/" + str(issue) + "/watchers")
if isinstance(watcher, User):
watcher = self.get_user_identifier(watcher)
return self._session.post(url, data=json.dumps(watcher))
watcher_id = self._get_user_identifier(watcher)
else:
watcher_id = watcher
if self.with_lookup:
watcher_id = self._get_user_id(watcher_id)
return self._session.post(url, data=json.dumps(watcher_id))

@translate_resource_args
def remove_watcher(self, issue: str | int, watcher: str | User) -> Response:
"""Remove a user from an issue's watch list.
Args:
issue (Union[str, int]): ID or key of the issue affected
watcher (str): username (for hosted) or account ID (for cloud) of the user to add to the watchers list
watcher (str): name of the user to remove from the watchers list
Returns:
Response
"""
url = self._get_url("issue/" + str(issue) + "/watchers")
# https://docs.atlassian.com/software/jira/docs/api/REST/8.13.6/#api/2/issue-removeWatcher
if isinstance(watcher, User):
watcher = self.get_user_identifier(watcher)
payload = {"accountId": watcher} if self._is_cloud else {"username": watcher}
watcher_id = self._get_user_identifier(watcher)
else:
watcher_id = watcher
if self.with_lookup:
watcher_id = self._get_user_id(watcher_id)
payload = {"accountId": watcher_id} if self._is_cloud else {"username": watcher_id}
result = self._session.delete(url, params=payload)
return result

Expand Down

0 comments on commit 790732d

Please sign in to comment.