comment.py
244 lines
| 8.7 KiB
| text/x-python
|
PythonLexer
r1670 | # -*- coding: utf-8 -*- | |||
""" | ||||
rhodecode.model.comment | ||||
~~~~~~~~~~~~~~~~~~~~~~~ | ||||
comments model for RhodeCode | ||||
r1789 | ||||
r1670 | :created_on: Nov 11, 2011 | |||
:author: marcink | ||||
r1824 | :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com> | |||
r1670 | :license: GPLv3, see COPYING for more details. | |||
""" | ||||
# This program is free software: you can redistribute it and/or modify | ||||
# it under the terms of the GNU General Public License as published by | ||||
# the Free Software Foundation, either version 3 of the License, or | ||||
# (at your option) any later version. | ||||
# | ||||
# This program is distributed in the hope that it will be useful, | ||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | ||||
# | ||||
# You should have received a copy of the GNU General Public License | ||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
import logging | ||||
import traceback | ||||
r1712 | from pylons.i18n.translation import _ | |||
from sqlalchemy.util.compat import defaultdict | ||||
r2178 | from rhodecode.lib.utils2 import extract_mentioned_users, safe_unicode | |||
r1712 | from rhodecode.lib import helpers as h | |||
r1670 | from rhodecode.model import BaseModel | |||
r2440 | from rhodecode.model.db import ChangesetComment, User, Repository, \ | |||
Notification, PullRequest | ||||
r1703 | from rhodecode.model.notification import NotificationModel | |||
r1670 | ||||
log = logging.getLogger(__name__) | ||||
class ChangesetCommentsModel(BaseModel): | ||||
r2522 | cls = ChangesetComment | |||
r1713 | def __get_changeset_comment(self, changeset_comment): | |||
r1716 | return self._get_instance(ChangesetComment, changeset_comment) | |||
r1670 | ||||
r2440 | def __get_pull_request(self, pull_request): | |||
return self._get_instance(PullRequest, pull_request) | ||||
r1712 | def _extract_mentions(self, s): | |||
r1713 | user_objects = [] | |||
for username in extract_mentioned_users(s): | ||||
r1712 | user_obj = User.get_by_username(username, case_insensitive=True) | |||
if user_obj: | ||||
r1713 | user_objects.append(user_obj) | |||
return user_objects | ||||
r1712 | ||||
r2541 | def create(self, text, repo, user, revision=None, pull_request=None, | |||
r2443 | f_path=None, line_no=None, status_change=None): | |||
r1670 | """ | |||
r2443 | Creates new comment for changeset or pull request. | |||
r2478 | IF status_change is not none this comment is associated with a | |||
r2443 | status change of changeset or changesets associated with pull request | |||
r1789 | ||||
r1670 | :param text: | |||
r2541 | :param repo: | |||
:param user: | ||||
r1675 | :param revision: | |||
r2443 | :param pull_request: | |||
r1670 | :param f_path: | |||
:param line_no: | ||||
r2296 | :param status_change: | |||
r1670 | """ | |||
r2443 | if not text: | |||
return | ||||
r2150 | ||||
r2541 | repo = self._get_repo(repo) | |||
user = self._get_user(user) | ||||
r2443 | comment = ChangesetComment() | |||
comment.repo = repo | ||||
r2541 | comment.author = user | |||
r2443 | comment.text = text | |||
comment.f_path = f_path | ||||
comment.line_no = line_no | ||||
if revision: | ||||
r1716 | cs = repo.scm_instance.get_changeset(revision) | |||
r2178 | desc = "%s - %s" % (cs.short_id, h.shorter(cs.message, 256)) | |||
r1677 | comment.revision = revision | |||
r2443 | elif pull_request: | |||
pull_request = self.__get_pull_request(pull_request) | ||||
comment.pull_request = pull_request | ||||
r2541 | desc = pull_request.pull_request_id | |||
r2443 | else: | |||
raise Exception('Please specify revision or pull_request_id') | ||||
r1670 | ||||
r2443 | self.sa.add(comment) | |||
self.sa.flush() | ||||
# make notification | ||||
line = '' | ||||
body = text | ||||
#changeset | ||||
if revision: | ||||
r1712 | if line_no: | |||
line = _('on line %s') % line_no | ||||
r2178 | subj = safe_unicode( | |||
r2541 | h.link_to('Re commit: %(desc)s %(line)s' % \ | |||
{'desc': desc, 'line': line}, | ||||
r2178 | h.url('changeset_home', repo_name=repo.repo_name, | |||
revision=revision, | ||||
anchor='comment-%s' % comment.comment_id, | ||||
qualified=True, | ||||
) | ||||
) | ||||
) | ||||
r2443 | notification_type = Notification.TYPE_CHANGESET_COMMENT | |||
r2077 | # get the current participants of this changeset | |||
r1703 | recipients = ChangesetComment.get_users(revision=revision) | |||
r2082 | # add changeset author if it's in rhodecode system | |||
r3343 | cs_author = User.get_from_cs_author(cs.author) | |||
if not cs_author: | ||||
#use repo owner if we cannot extract the author correctly | ||||
cs_author = repo.user | ||||
recipients += [cs_author] | ||||
r2805 | email_kwargs = { | |||
'status_change': status_change, | ||||
} | ||||
r2443 | #pull request | |||
elif pull_request: | ||||
r2802 | _url = h.url('pullrequest_show', | |||
repo_name=pull_request.other_repo.repo_name, | ||||
pull_request_id=pull_request.pull_request_id, | ||||
anchor='comment-%s' % comment.comment_id, | ||||
qualified=True, | ||||
) | ||||
r2541 | subj = safe_unicode( | |||
h.link_to('Re pull request: %(desc)s %(line)s' % \ | ||||
r2802 | {'desc': desc, 'line': line}, _url) | |||
r2541 | ) | |||
r2443 | notification_type = Notification.TYPE_PULL_REQUEST_COMMENT | |||
# get the current participants of this pull request | ||||
recipients = ChangesetComment.get_users(pull_request_id= | ||||
pull_request.pull_request_id) | ||||
# add pull request author | ||||
recipients += [pull_request.author] | ||||
r1716 | ||||
r2802 | # add the reviewers to notification | |||
recipients += [x.user for x in pull_request.reviewers] | ||||
#set some variables for email notification | ||||
r2805 | email_kwargs = { | |||
r2802 | 'pr_id': pull_request.pull_request_id, | |||
'status_change': status_change, | ||||
'pr_comment_url': _url, | ||||
'pr_comment_user': h.person(user.email), | ||||
'pr_target_repo': h.url('summary_home', | ||||
repo_name=pull_request.other_repo.repo_name, | ||||
qualified=True) | ||||
} | ||||
r2443 | # create notification objects, and emails | |||
NotificationModel().create( | ||||
r2802 | created_by=user, subject=subj, body=body, | |||
recipients=recipients, type_=notification_type, | ||||
r2805 | email_kwargs=email_kwargs | |||
r2443 | ) | |||
mention_recipients = set(self._extract_mentions(body))\ | ||||
.difference(recipients) | ||||
if mention_recipients: | ||||
r2814 | email_kwargs.update({'pr_mention': True}) | |||
r2443 | subj = _('[Mention]') + ' ' + subj | |||
r2077 | NotificationModel().create( | |||
r2541 | created_by=user, subject=subj, body=body, | |||
r2443 | recipients=mention_recipients, | |||
type_=notification_type, | ||||
r2814 | email_kwargs=email_kwargs | |||
r2077 | ) | |||
r1703 | ||||
r2443 | return comment | |||
r1670 | ||||
r1713 | def delete(self, comment): | |||
r1670 | """ | |||
Deletes given comment | ||||
r1789 | ||||
r1670 | :param comment_id: | |||
""" | ||||
r1713 | comment = self.__get_changeset_comment(comment) | |||
r1670 | self.sa.delete(comment) | |||
r1713 | ||||
r1670 | return comment | |||
r1675 | ||||
r2440 | def get_comments(self, repo_id, revision=None, pull_request=None): | |||
r2439 | """ | |||
Get's main comments based on revision or pull_request_id | ||||
:param repo_id: | ||||
:type repo_id: | ||||
:param revision: | ||||
:type revision: | ||||
r2440 | :param pull_request: | |||
:type pull_request: | ||||
r2439 | """ | |||
r2440 | ||||
r2439 | q = ChangesetComment.query()\ | |||
r1675 | .filter(ChangesetComment.repo_id == repo_id)\ | |||
.filter(ChangesetComment.line_no == None)\ | ||||
r2439 | .filter(ChangesetComment.f_path == None) | |||
if revision: | ||||
q = q.filter(ChangesetComment.revision == revision) | ||||
r2440 | elif pull_request: | |||
pull_request = self.__get_pull_request(pull_request) | ||||
q = q.filter(ChangesetComment.pull_request == pull_request) | ||||
r2439 | else: | |||
r2440 | raise Exception('Please specify revision or pull_request') | |||
r2639 | q = q.order_by(ChangesetComment.created_on) | |||
r2439 | return q.all() | |||
r1675 | ||||
r2440 | def get_inline_comments(self, repo_id, revision=None, pull_request=None): | |||
r2439 | q = self.sa.query(ChangesetComment)\ | |||
r1675 | .filter(ChangesetComment.repo_id == repo_id)\ | |||
r1681 | .filter(ChangesetComment.line_no != None)\ | |||
r2187 | .filter(ChangesetComment.f_path != None)\ | |||
.order_by(ChangesetComment.comment_id.asc())\ | ||||
r2439 | ||||
if revision: | ||||
q = q.filter(ChangesetComment.revision == revision) | ||||
r2440 | elif pull_request: | |||
pull_request = self.__get_pull_request(pull_request) | ||||
q = q.filter(ChangesetComment.pull_request == pull_request) | ||||
r2439 | else: | |||
raise Exception('Please specify revision or pull_request_id') | ||||
comments = q.all() | ||||
r1677 | ||||
r1789 | paths = defaultdict(lambda: defaultdict(list)) | |||
r1675 | ||||
for co in comments: | ||||
r1677 | paths[co.f_path][co.line_no].append(co) | |||
return paths.items() | ||||