diff --git a/docs/examples.rst b/docs/examples.rst index d4e6e1cfa..bba30bf75 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -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:: @@ -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 ----------- diff --git a/jira/client.py b/jira/client.py index 36dc2fea9..d4af4698c 100644 --- a/jira/client.py +++ b/jira/client.py @@ -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, @@ -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 @@ -2264,18 +2273,25 @@ def _get_user_id(self, user: str | None) -> str | None: # non-resource @translate_resource_args - 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 @@ -2720,23 +2736,28 @@ def watchers(self, issue: str | int) -> Watchers: return self._find_for_resource(Watchers, issue) @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 - 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: @@ -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 diff --git a/tests/resources/test_issue.py b/tests/resources/test_issue.py index a496edb2e..6b80cf7a1 100644 --- a/tests/resources/test_issue.py +++ b/tests/resources/test_issue.py @@ -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) diff --git a/tests/resources/test_watchers.py b/tests/resources/test_watchers.py index 7e7c991be..28549fa07 100644 --- a/tests/resources/test_watchers.py +++ b/tests/resources/test_watchers.py @@ -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)