api: allow extra recipients for pr/commit comments api methods

- adds some sort of CC functionality for notification
- allows sending emails with notifications to people who are not commit messages, or pr reviewers e.g project manager etc.
This commit is contained in:
Marcin Kuzminski 2019-11-07 22:29:39 +01:00
parent bd7a7f7bc1
commit 697ce81998
7 changed files with 101 additions and 7 deletions

View file

@ -20,7 +20,7 @@
import pytest
from rhodecode.model.db import ChangesetStatus
from rhodecode.model.db import ChangesetStatus, User
from rhodecode.api.tests.utils import (
build_data, api_call, assert_error, assert_ok)
@ -79,3 +79,38 @@ class TestCommentCommit(object):
'success': True
}
assert_ok(id_, expected, given=response.body)
def test_api_comment_commit_with_extra_recipients(self, backend, user_util):
commit_id = backend.repo.scm_instance().get_commit('tip').raw_id
user1 = user_util.create_user()
user1_id = user1.user_id
user2 = user_util.create_user()
user2_id = user2.user_id
id_, params = build_data(
self.apikey, 'comment_commit', repoid=backend.repo_name,
commit_id=commit_id,
message='abracadabra',
extra_recipients=[user1.user_id, user2.username])
response = api_call(self.app, params)
repo = backend.repo.scm_instance()
expected = {
'msg': 'Commented on commit `%s` for repository `%s`' % (
repo.get_commit().raw_id, backend.repo_name),
'status_change': None,
'success': True
}
assert_ok(id_, expected, given=response.body)
# check user1/user2 inbox for notification
user1 = User.get(user1_id)
assert 1 == len(user1.notifications)
assert 'abracadabra' in user1.notifications[0].notification.body
user2 = User.get(user2_id)
assert 1 == len(user2.notifications)
assert 'abracadabra' in user2.notifications[0].notification.body

View file

@ -21,7 +21,7 @@
import pytest
from rhodecode.model.comment import CommentsModel
from rhodecode.model.db import UserLog
from rhodecode.model.db import UserLog, User
from rhodecode.model.pull_request import PullRequestModel
from rhodecode.tests import TEST_USER_ADMIN_LOGIN
from rhodecode.api.tests.utils import (
@ -69,6 +69,43 @@ class TestCommentPullRequest(object):
.all()
assert journal[-1].action == 'repo.pull_request.comment.create'
@pytest.mark.backends("git", "hg")
def test_api_comment_pull_request_with_extra_recipients(self, pr_util, user_util):
pull_request = pr_util.create_pull_request()
user1 = user_util.create_user()
user1_id = user1.user_id
user2 = user_util.create_user()
user2_id = user2.user_id
id_, params = build_data(
self.apikey, 'comment_pull_request',
repoid=pull_request.target_repo.repo_name,
pullrequestid=pull_request.pull_request_id,
message='test message',
extra_recipients=[user1.user_id, user2.username]
)
response = api_call(self.app, params)
pull_request = PullRequestModel().get(pull_request.pull_request_id)
comments = CommentsModel().get_comments(
pull_request.target_repo.repo_id, pull_request=pull_request)
expected = {
'pull_request_id': pull_request.pull_request_id,
'comment_id': comments[-1].comment_id,
'status': {'given': None, 'was_changed': None}
}
assert_ok(id_, expected, response.body)
# check user1/user2 inbox for notification
user1 = User.get(user1_id)
assert 1 == len(user1.notifications)
assert 'test message' in user1.notifications[0].notification.body
user2 = User.get(user2_id)
assert 1 == len(user2.notifications)
assert 'test message' in user2.notifications[0].notification.body
@pytest.mark.backends("git", "hg")
def test_api_comment_pull_request_change_status(
self, pr_util, no_notifications):

View file

@ -50,6 +50,7 @@ class TestGetMethod(object):
{'apiuser': '<RequiredType>',
'comment_type': "<Optional:u'note'>",
'commit_id': '<RequiredType>',
'extra_recipients': '<Optional:[]>',
'message': '<RequiredType>',
'repoid': '<RequiredType>',
'request': '<RequiredType>',

View file

@ -451,7 +451,7 @@ def comment_pull_request(
request, apiuser, pullrequestid, repoid=Optional(None),
message=Optional(None), commit_id=Optional(None), status=Optional(None),
comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
resolves_comment_id=Optional(None),
resolves_comment_id=Optional(None), extra_recipients=Optional([]),
userid=Optional(OAttr('apiuser'))):
"""
Comment on the pull request specified with the `pullrequestid`,
@ -476,6 +476,11 @@ def comment_pull_request(
:type status: str
:param comment_type: Comment type, one of: 'note', 'todo'
:type comment_type: Optional(str), default: 'note'
:param resolves_comment_id: id of comment which this one will resolve
:type resolves_comment_id: Optional(int)
:param extra_recipients: list of user ids or usernames to add
notifications for this comment. Acts like a CC for notification
:type extra_recipients: Optional(list)
:param userid: Comment on the pull request as this user
:type userid: Optional(str or int)
@ -521,6 +526,7 @@ def comment_pull_request(
commit_id = Optional.extract(commit_id)
comment_type = Optional.extract(comment_type)
resolves_comment_id = Optional.extract(resolves_comment_id)
extra_recipients = Optional.extract(extra_recipients)
if not message and not status:
raise JSONRPCError(
@ -580,7 +586,8 @@ def comment_pull_request(
renderer=renderer,
comment_type=comment_type,
resolves_comment_id=resolves_comment_id,
auth_user=auth_user
auth_user=auth_user,
extra_recipients=extra_recipients
)
if allowed_to_change_status and status:

View file

@ -1550,7 +1550,7 @@ def lock(request, apiuser, repoid, locked=Optional(None),
def comment_commit(
request, apiuser, repoid, commit_id, message, status=Optional(None),
comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
resolves_comment_id=Optional(None),
resolves_comment_id=Optional(None), extra_recipients=Optional([]),
userid=Optional(OAttr('apiuser'))):
"""
Set a commit comment, and optionally change the status of the commit.
@ -1568,6 +1568,11 @@ def comment_commit(
:type status: str
:param comment_type: Comment type, one of: 'note', 'todo'
:type comment_type: Optional(str), default: 'note'
:param resolves_comment_id: id of comment which this one will resolve
:type resolves_comment_id: Optional(int)
:param extra_recipients: list of user ids or usernames to add
notifications for this comment. Acts like a CC for notification
:type extra_recipients: Optional(list)
:param userid: Set the user name of the comment creator.
:type userid: Optional(str or int)
@ -1604,6 +1609,7 @@ def comment_commit(
status = Optional.extract(status)
comment_type = Optional.extract(comment_type)
resolves_comment_id = Optional.extract(resolves_comment_id)
extra_recipients = Optional.extract(extra_recipients)
allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES]
if status and status not in allowed_statuses:
@ -1632,7 +1638,8 @@ def comment_commit(
renderer=renderer,
comment_type=comment_type,
resolves_comment_id=resolves_comment_id,
auth_user=apiuser
auth_user=apiuser,
extra_recipients=extra_recipients
)
if status:
# also do a status change

View file

@ -232,7 +232,7 @@ class CommentsModel(BaseModel):
f_path=None, line_no=None, status_change=None,
status_change_type=None, comment_type=None,
resolves_comment_id=None, closing_pr=False, send_email=True,
renderer=None, auth_user=None):
renderer=None, auth_user=None, extra_recipients=None):
"""
Creates new comment for commit or pull request.
IF status_change is not none this comment is associated with a
@ -247,10 +247,13 @@ class CommentsModel(BaseModel):
:param line_no:
:param status_change: Label for status change
:param comment_type: Type of comment
:param resolves_comment_id: id of comment which this one will resolve
:param status_change_type: type of status change
:param closing_pr:
:param send_email:
:param renderer: pick renderer for this comment
:param auth_user: current authenticated user calling this method
:param extra_recipients: list of extra users to be added to recipients
"""
if not text:
@ -406,6 +409,9 @@ class CommentsModel(BaseModel):
'pr_comment_url': pr_comment_url,
'pr_closing': closing_pr,
})
recipients += [self._get_user(u) for u in (extra_recipients or [])]
if send_email:
# pre-generate the subject for notification itself
(subject,

View file

@ -111,6 +111,7 @@ class NotificationModel(BaseModel):
# add mentioned users into recipients
final_recipients = set(recipients_objs).union(mention_recipients)
notification = Notification.create(
created_by=created_by_obj, subject=notification_subject,
body=notification_body, recipients=final_recipients,