##// END OF EJS Templates
- added commenting to pull requests...
marcink -
r2443:fd0a8224 codereview
parent child Browse files
Show More
@@ -457,6 +457,12 b' def make_map(config):'
457 457 action='show_all', conditions=dict(function=check_repo,
458 458 method=["GET"]))
459 459
460 rmap.connect('pullrequest_comment',
461 '/{repo_name:.*}/pull-request-comment/{pull_request_id}',
462 controller='pullrequests',
463 action='comment', conditions=dict(function=check_repo,
464 method=["POST"]))
465
460 466 rmap.connect('summary_home', '/{repo_name:.*}/summary',
461 467 controller='summary', conditions=dict(function=check_repo))
462 468
@@ -390,10 +390,10 b' class ChangesetController(BaseRepoContro'
390 390 if status and change_status:
391 391 ChangesetStatusModel().set_status(
392 392 c.rhodecode_db_repo.repo_id,
393 revision,
394 393 status,
395 394 c.rhodecode_user.user_id,
396 395 comm,
396 revision=revision,
397 397 )
398 398 action_logger(self.rhodecode_user,
399 399 'user_commented_revision:%s' % revision,
@@ -24,19 +24,20 b''
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25 import logging
26 26 import traceback
27 import binascii
28 27
29 28 from webob.exc import HTTPNotFound
30 29
31 30 from pylons import request, response, session, tmpl_context as c, url
32 31 from pylons.controllers.util import abort, redirect
33 32 from pylons.i18n.translation import _
33 from pylons.decorators import jsonify
34 34
35 35 from rhodecode.lib.base import BaseRepoController, render
36 36 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
37 37 from rhodecode.lib import helpers as h
38 38 from rhodecode.lib import diffs
39 from rhodecode.model.db import User, PullRequest, Repository, ChangesetStatus
39 from rhodecode.lib.utils import action_logger
40 from rhodecode.model.db import User, PullRequest, ChangesetStatus
40 41 from rhodecode.model.pull_request import PullRequestModel
41 42 from rhodecode.model.meta import Session
42 43 from rhodecode.model.repo import RepoModel
@@ -208,9 +209,56 b' class PullrequestsController(BaseRepoCon'
208 209 .get_comments(c.rhodecode_db_repo.repo_id,
209 210 pull_request=pull_request_id)
210 211
211 # changeset(pull-request) statuse
212 # changeset(pull-request) status
212 213 c.current_changeset_status = ChangesetStatusModel()\
213 .get_status(c.rhodecode_db_repo.repo_id,
214 pull_request=pull_request_id)
214 .get_status(c.pull_request.org_repo,
215 pull_request=c.pull_request)
215 216 c.changeset_statuses = ChangesetStatus.STATUSES
216 217 return render('/pullrequests/pullrequest_show.html')
218
219 @jsonify
220 def comment(self, repo_name, pull_request_id):
221
222 status = request.POST.get('changeset_status')
223 change_status = request.POST.get('change_changeset_status')
224
225 comm = ChangesetCommentsModel().create(
226 text=request.POST.get('text'),
227 repo_id=c.rhodecode_db_repo.repo_id,
228 user_id=c.rhodecode_user.user_id,
229 pull_request=pull_request_id,
230 f_path=request.POST.get('f_path'),
231 line_no=request.POST.get('line'),
232 status_change=(ChangesetStatus.get_status_lbl(status)
233 if status and change_status else None)
234 )
235
236 # get status if set !
237 if status and change_status:
238 ChangesetStatusModel().set_status(
239 c.rhodecode_db_repo.repo_id,
240 status,
241 c.rhodecode_user.user_id,
242 comm,
243 pull_request=pull_request_id
244 )
245 action_logger(self.rhodecode_user,
246 'user_commented_pull_request:%s' % pull_request_id,
247 c.rhodecode_db_repo, self.ip_addr, self.sa)
248
249 Session.commit()
250
251 if not request.environ.get('HTTP_X_PARTIAL_XHR'):
252 return redirect(h.url('pullrequest_show', repo_name=repo_name,
253 pull_request_id=pull_request_id))
254
255 data = {
256 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
257 }
258 if comm:
259 c.co = comm
260 data.update(comm.get_dict())
261 data.update({'rendered_text':
262 render('changeset/changeset_comment_block.html')})
263
264 return data No newline at end of file
@@ -66,12 +66,15 b' class ChangesetStatusModel(BaseModel):'
66 66 else:
67 67 raise Exception('Please specify revision or pull_request')
68 68
69 status = q.scalar()
69 # need to use first here since there can be multiple statuses
70 # returned from pull_request
71 status = q.first()
70 72 status = status.status if status else status
71 73 st = status or ChangesetStatus.DEFAULT
72 74 return str(st)
73 75
74 def set_status(self, repo, revision, status, user, comment):
76 def set_status(self, repo, status, user, comment, revision=None,
77 pull_request=None):
75 78 """
76 79 Creates new status for changeset or updates the old ones bumping their
77 80 version, leaving the current status at
@@ -89,20 +92,48 b' class ChangesetStatusModel(BaseModel):'
89 92 """
90 93 repo = self._get_repo(repo)
91 94
92 cur_statuses = ChangesetStatus.query()\
93 .filter(ChangesetStatus.repo == repo)\
94 .filter(ChangesetStatus.revision == revision)\
95 .all()
95 q = ChangesetStatus.query()
96
97 if revision:
98 q = q.filter(ChangesetStatus.repo == repo)
99 q = q.filter(ChangesetStatus.revision == revision)
100 elif pull_request:
101 pull_request = self.__get_pull_request(pull_request)
102 q = q.filter(ChangesetStatus.repo == pull_request.org_repo)
103 q = q.filter(ChangesetStatus.pull_request == pull_request)
104 cur_statuses = q.all()
105
96 106 if cur_statuses:
97 107 for st in cur_statuses:
98 108 st.version += 1
99 109 self.sa.add(st)
100 new_status = ChangesetStatus()
101 new_status.author = self._get_user(user)
102 new_status.repo = self._get_repo(repo)
103 new_status.status = status
104 new_status.revision = revision
105 new_status.comment = comment
106 self.sa.add(new_status)
107 return new_status
110
111 def _create_status(user, repo, status, comment, revision, pull_request):
112 new_status = ChangesetStatus()
113 new_status.author = self._get_user(user)
114 new_status.repo = self._get_repo(repo)
115 new_status.status = status
116 new_status.comment = comment
117 new_status.revision = revision
118 new_status.pull_request = pull_request
119 return new_status
108 120
121 if revision:
122 new_status = _create_status(user=user, repo=repo, status=status,
123 comment=comment, revision=revision,
124 pull_request=None)
125 self.sa.add(new_status)
126 return new_status
127 elif pull_request:
128 #pull request can have more than one revision associated to it
129 #we need to create new version for each one
130 new_statuses = []
131 repo = pull_request.org_repo
132 for rev in pull_request.revisions:
133 new_status = _create_status(user=user, repo=repo,
134 status=status, comment=comment,
135 revision=rev,
136 pull_request=pull_request)
137 new_statuses.append(new_status)
138 self.sa.add(new_status)
139 return new_statuses
@@ -55,38 +55,54 b' class ChangesetCommentsModel(BaseModel):'
55 55 user_objects.append(user_obj)
56 56 return user_objects
57 57
58 def create(self, text, repo_id, user_id, revision, f_path=None,
59 line_no=None, status_change=None):
58 def create(self, text, repo_id, user_id, revision=None, pull_request=None,
59 f_path=None, line_no=None, status_change=None):
60 60 """
61 Creates new comment for changeset. IF status_change is not none
62 this comment is associated with a status change of changeset
61 Creates new comment for changeset or pull request.
62 IF status_change is not none this comment is associated with a
63 status change of changeset or changesets associated with pull request
63 64
64 65 :param text:
65 66 :param repo_id:
66 67 :param user_id:
67 68 :param revision:
69 :param pull_request:
68 70 :param f_path:
69 71 :param line_no:
70 72 :param status_change:
71 73 """
74 if not text:
75 return
72 76
73 if text:
74 repo = Repository.get(repo_id)
77 repo = Repository.get(repo_id)
78 comment = ChangesetComment()
79 comment.repo = repo
80 comment.user_id = user_id
81 comment.text = text
82 comment.f_path = f_path
83 comment.line_no = line_no
84
85 if revision:
75 86 cs = repo.scm_instance.get_changeset(revision)
76 87 desc = "%s - %s" % (cs.short_id, h.shorter(cs.message, 256))
77 88 author_email = cs.author_email
78 comment = ChangesetComment()
79 comment.repo = repo
80 comment.user_id = user_id
81 89 comment.revision = revision
82 comment.text = text
83 comment.f_path = f_path
84 comment.line_no = line_no
90 elif pull_request:
91 pull_request = self.__get_pull_request(pull_request)
92 comment.pull_request = pull_request
93 desc = ''
94 else:
95 raise Exception('Please specify revision or pull_request_id')
85 96
86 self.sa.add(comment)
87 self.sa.flush()
88 # make notification
89 line = ''
97 self.sa.add(comment)
98 self.sa.flush()
99
100 # make notification
101 line = ''
102 body = text
103
104 #changeset
105 if revision:
90 106 if line_no:
91 107 line = _('on line %s') % line_no
92 108 subj = safe_unicode(
@@ -99,34 +115,41 b' class ChangesetCommentsModel(BaseModel):'
99 115 )
100 116 )
101 117 )
102
103 body = text
104
118 notification_type = Notification.TYPE_CHANGESET_COMMENT
105 119 # get the current participants of this changeset
106 120 recipients = ChangesetComment.get_users(revision=revision)
107
108 121 # add changeset author if it's in rhodecode system
109 122 recipients += [User.get_by_email(author_email)]
123 #pull request
124 elif pull_request:
125 #TODO: make this something usefull
126 subj = 'commented on pull request something...'
127 notification_type = Notification.TYPE_PULL_REQUEST_COMMENT
128 # get the current participants of this pull request
129 recipients = ChangesetComment.get_users(pull_request_id=
130 pull_request.pull_request_id)
131 # add pull request author
132 recipients += [pull_request.author]
110 133
111 # create notification objects, and emails
134 # create notification objects, and emails
135 NotificationModel().create(
136 created_by=user_id, subject=subj, body=body,
137 recipients=recipients, type_=notification_type,
138 email_kwargs={'status_change': status_change}
139 )
140
141 mention_recipients = set(self._extract_mentions(body))\
142 .difference(recipients)
143 if mention_recipients:
144 subj = _('[Mention]') + ' ' + subj
112 145 NotificationModel().create(
113 created_by=user_id, subject=subj, body=body,
114 recipients=recipients, type_=Notification.TYPE_CHANGESET_COMMENT,
115 email_kwargs={'status_change': status_change}
146 created_by=user_id, subject=subj, body=body,
147 recipients=mention_recipients,
148 type_=notification_type,
149 email_kwargs={'status_change': status_change}
116 150 )
117 151
118 mention_recipients = set(self._extract_mentions(body))\
119 .difference(recipients)
120 if mention_recipients:
121 subj = _('[Mention]') + ' ' + subj
122 NotificationModel().create(
123 created_by=user_id, subject=subj, body=body,
124 recipients=mention_recipients,
125 type_=Notification.TYPE_CHANGESET_COMMENT,
126 email_kwargs={'status_change': status_change}
127 )
128
129 return comment
152 return comment
130 153
131 154 def delete(self, comment):
132 155 """
@@ -766,7 +766,12 b' class Repository(Base, BaseModel):'
766 766 statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
767 767 grouped = {}
768 768 for stat in statuses.all():
769 grouped[stat.revision] = [str(stat.status), stat.status_lbl]
769 pr_id = pr_repo = None
770 if stat.pull_request:
771 pr_id = stat.pull_request.pull_request_id
772 pr_repo = stat.pull_request.other_repo.repo_name
773 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
774 pr_id, pr_repo]
770 775 return grouped
771 776
772 777 #==========================================================================
@@ -1336,17 +1341,21 b' class ChangesetComment(Base, BaseModel):'
1336 1341 pull_request = relationship('PullRequest', lazy='joined')
1337 1342
1338 1343 @classmethod
1339 def get_users(cls, revision):
1344 def get_users(cls, revision=None, pull_request_id=None):
1340 1345 """
1341 Returns user associated with this changesetComment. ie those
1346 Returns user associated with this ChangesetComment. ie those
1342 1347 who actually commented
1343 1348
1344 1349 :param cls:
1345 1350 :param revision:
1346 1351 """
1347 return Session.query(User)\
1348 .filter(cls.revision == revision)\
1349 .join(ChangesetComment.author).all()
1352 q = Session.query(User)\
1353 .join(ChangesetComment.author)
1354 if revision:
1355 q = q.filter(cls.revision == revision)
1356 elif pull_request_id:
1357 q = q.filter(cls.pull_request_id == pull_request_id)
1358 return q.all()
1350 1359
1351 1360
1352 1361 class ChangesetStatus(Base, BaseModel):
@@ -1457,6 +1466,7 b' class Notification(Base, BaseModel):'
1457 1466 TYPE_MENTION = u'mention'
1458 1467 TYPE_REGISTRATION = u'registration'
1459 1468 TYPE_PULL_REQUEST = u'pull_request'
1469 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1460 1470
1461 1471 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1462 1472 subject = Column('subject', Unicode(512), nullable=True)
@@ -198,13 +198,15 b' class NotificationModel(BaseModel):'
198 198 Creates a human readable description based on properties
199 199 of notification object
200 200 """
201
201 #alias
202 _n = notification
202 203 _map = {
203 notification.TYPE_CHANGESET_COMMENT: _('commented on commit'),
204 notification.TYPE_MESSAGE: _('sent message'),
205 notification.TYPE_MENTION: _('mentioned you'),
206 notification.TYPE_REGISTRATION: _('registered in RhodeCode'),
207 notification.TYPE_PULL_REQUEST: _('opened new pull request')
204 _n.TYPE_CHANGESET_COMMENT: _('commented on commit'),
205 _n.TYPE_MESSAGE: _('sent message'),
206 _n.TYPE_MENTION: _('mentioned you'),
207 _n.TYPE_REGISTRATION: _('registered in RhodeCode'),
208 _n.TYPE_PULL_REQUEST: _('opened new pull request'),
209 _n.TYPE_PULL_REQUEST_COMMENT: _('commented on pull request')
208 210 }
209 211
210 212 tmpl = "%(user)s %(action)s %(when)s"
@@ -85,7 +85,13 b''
85 85 <div class="changeset-status-container">
86 86 %if c.statuses.get(cs.raw_id):
87 87 <div title="${_('Changeset status')}" class="changeset-status-lbl">${c.statuses.get(cs.raw_id)[1]}</div>
88 <div class="changeset-status-ico"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" /></div>
88 <div class="changeset-status-ico">
89 %if c.statuses.get(cs.raw_id)[2]:
90 <a class="tooltip" title="${_('Click to open associated pull request')}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" /></a>
91 %else:
92 <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
93 %endif
94 </div>
89 95 %endif
90 96 </div>
91 97 </div>
@@ -70,8 +70,8 b''
70 70 ##${comment.comment_inline_form(c.changeset)}
71 71
72 72 ## render comments main comments form and it status
73 ##${comment.comments(h.url('pull_request_comment', repo_name=c.repo_name, pull_request_id=c.pull_request.pull_request_id),
74 ## c.current_changeset_status)}
73 ${comment.comments(h.url('pullrequest_comment', repo_name=c.repo_name, pull_request_id=c.pull_request.pull_request_id),
74 c.current_changeset_status)}
75 75
76 76 </div>
77 77
General Comments 0
You need to be logged in to leave comments. Login now