Skip to content

Remove internal user lookup #1874

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

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
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
12 changes: 10 additions & 2 deletions docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,16 @@ If you only want a few specific fields, save time by asking for them explicitly:

issue = jira.issue('JRA-1330', fields='summary,comment')

Reassign an issue::
Reassign an issue:
Reassigning an issue can be done either by providing the username/accountId (hosted/cloud) or the User Resource object itself::

# requires issue assign permission, which is different from issue editing permission!
# via username, for hosted instances
jira.assign_issue(issue, 'newassignee')
# or accountId, for cloud instances
jira.assign_issue(issue, 'gweg3:5fr23r23r-3041-4342-23f2-2g3g232c2e1234:8008sdg3-441a-12f2-9sg1-erbwer3q3r3')
# or via the User retrieved from search_users()
jira.assign_issue(issue, user_resource)

If you want to unassign it again, just do::

Expand Down Expand Up @@ -421,15 +427,17 @@ Watchers are objects, represented by :class:`jira.resources.Watchers`::
# watcher is instance of jira.resources.User:
print(watcher.emailAddress)

You can add users to watchers by their name::
You can add users to watchers by their name (hosted) / accountId (cloud) or the User resource itself::

jira.add_watcher(issue, 'username')
jira.add_watcher(issue, user_resource.name)
jira.add_watcher(issue, user_resource)

And of course you can remove users from watcher::

jira.remove_watcher(issue, 'username')
jira.remove_watcher(issue, user_resource.name)
jira.remove_watcher(issue, user_resource)

Attachments
-----------
Expand Down
48 changes: 38 additions & 10 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,14 @@ def __init__(
else:
self._version = (0, 0, 0)

self.with_lookup = with_lookup
if with_lookup:
warnings.warn(
"Auto-lookup (with_lookup) has been set to True, the library will look-up the provided user "
"for its 'add_watcher', 'remove_watcher' and 'assign_issue' methods; this functionality "
"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 @@ -2264,18 +2273,25 @@ def _get_user_id(self, user: str | None) -> str | None:

# non-resource
@translate_resource_args
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@translate_resource_args

It will be critical for this approach to work to remove this decorator which would have automagically converted the object to a string

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the decorator touches on the User objects, it seems to only manipulate the Issue in this case

def assign_issue(self, issue: int | str, assignee: str | None) -> bool:
def assign_issue(self, issue: int | str, assignee: str | User | None) -> bool:
"""Assign an issue to a user.

Args:
issue (Union[int, str]): the issue ID or key to assign
assignee (str): the user to assign the issue to. None will set it to unassigned. -1 will set it to Automatic.
assignee (Union[str, User]): username (for hosted) or account ID (for cloud) of the user to add to the
watchers list. Alternatively, you can provide the User object itself.
None will set it to unassigned. -1 will set it to Automatic.

Returns:
bool
"""
url = self._get_latest_url(f"issue/{issue}/assignee")
user_id = self._get_user_id(assignee)
if isinstance(assignee, User):
user_id: str | None = 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 @@ -2720,23 +2736,28 @@ def watchers(self, issue: str | int) -> Watchers:
return self._find_for_resource(Watchers, issue)

@translate_resource_args
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@translate_resource_args

def add_watcher(self, issue: str | int, watcher: str) -> Response:
def add_watcher(self, issue: str | int, watcher: str | User) -> Response:
"""Add a user to an issue's watchers list.

Args:
issue (Union[str, int]): ID or key of the issue affected
watcher (str): name of the user to add to the watchers list
watcher (str | User): username (for hosted) or account ID (for cloud) of the user to add to the watchers
list

Returns:
Response
"""
url = self._get_url("issue/" + str(issue) + "/watchers")
# Use user_id when adding watcher
watcher_id = self._get_user_id(watcher)
if isinstance(watcher, User):
watcher_id: str | None = 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@translate_resource_args

def remove_watcher(self, issue: str | int, watcher: str) -> Response:
def remove_watcher(self, issue: str | int, watcher: str | User) -> Response:
"""Remove a user from an issue's watch list.

Args:
Expand All @@ -2748,8 +2769,15 @@ def remove_watcher(self, issue: str | int, watcher: str) -> 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
user_id = self._get_user_id(watcher)
payload = {"accountId": user_id} if self._is_cloud else {"username": user_id}
if isinstance(watcher, User):
watcher_id: str | None = 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
10 changes: 9 additions & 1 deletion tests/resources/test_issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,12 +429,20 @@ def test_createmeta_expand(self):
)
self.assertTrue("fields" in meta["projects"][0]["issuetypes"][0])

def test_assign_issue(self):
def test_assign_issue_username(self):
# Assign issue via username
self.assertTrue(self.jira.assign_issue(self.issue_1, self.user_normal.name))
self.assertEqual(
self.jira.issue(self.issue_1).fields.assignee.name, self.user_normal.name
)

def test_assign_issue_user_obj(self):
# Assign issue via User object
self.assertTrue(self.jira.assign_issue(self.issue_1, self.user_normal))
self.assertEqual(
self.jira.issue(self.issue_1).fields.assignee.name, self.user_normal.name
)

def test_assign_issue_with_issue_obj(self):
issue = self.jira.issue(self.issue_1)
x = self.jira.assign_issue(issue, self.user_normal.name)
Expand Down
9 changes: 9 additions & 0 deletions tests/resources/test_watchers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,12 @@ def test_add_remove_watcher(self):
self.jira.remove_watcher(self.issue_1, self.test_manager.user_normal.name)
new_watchers = self.jira.watchers(self.issue_1).watchCount
self.assertEqual(init_watchers, new_watchers)

# verify passing the user object also words
self.jira.add_watcher(self.issue_1, self.test_manager.user_normal)
self.assertEqual(self.jira.watchers(self.issue_1).watchCount, init_watchers + 1)

# same, but for removing
self.jira.remove_watcher(self.issue_1, self.test_manager.user_normal)
new_watchers = self.jira.watchers(self.issue_1).watchCount
self.assertEqual(init_watchers, new_watchers)
Loading