Changeset - fd0a822481ec
[Not reviewed]
codereview
0 9 0
Marcin Kuzminski - 13 years ago 2012-06-11 00:58:24
marcin@python-works.com
- added commenting to pull requests
- it's now possible to change pull request status via changeset status option
- status flags with associated pull requests are links to pull request they been
changed in
9 files changed with 197 insertions and 71 deletions:
0 comments (0 inline, 0 general)
rhodecode/config/routing.py
Show inline comments
 
@@ -457,6 +457,12 @@ def make_map(config):
 
                 action='show_all', conditions=dict(function=check_repo,
 
                                                method=["GET"]))
 

	
 
    rmap.connect('pullrequest_comment',
 
                 '/{repo_name:.*}/pull-request-comment/{pull_request_id}',
 
                 controller='pullrequests',
 
                 action='comment', conditions=dict(function=check_repo,
 
                                                method=["POST"]))
 

	
 
    rmap.connect('summary_home', '/{repo_name:.*}/summary',
 
                controller='summary', conditions=dict(function=check_repo))
 

	
rhodecode/controllers/changeset.py
Show inline comments
 
@@ -390,10 +390,10 @@ class ChangesetController(BaseRepoContro
 
        if status and change_status:
 
            ChangesetStatusModel().set_status(
 
                c.rhodecode_db_repo.repo_id,
 
                revision,
 
                status,
 
                c.rhodecode_user.user_id,
 
                comm,
 
                revision=revision,
 
            )
 
        action_logger(self.rhodecode_user,
 
                      'user_commented_revision:%s' % revision,
rhodecode/controllers/pullrequests.py
Show inline comments
 
@@ -24,19 +24,20 @@
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
import logging
 
import traceback
 
import binascii
 

	
 
from webob.exc import HTTPNotFound
 

	
 
from pylons import request, response, session, tmpl_context as c, url
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 
from pylons.decorators import jsonify
 

	
 
from rhodecode.lib.base import BaseRepoController, render
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib import diffs
 
from rhodecode.model.db import User, PullRequest, Repository, ChangesetStatus
 
from rhodecode.lib.utils import action_logger
 
from rhodecode.model.db import User, PullRequest, ChangesetStatus
 
from rhodecode.model.pull_request import PullRequestModel
 
from rhodecode.model.meta import Session
 
from rhodecode.model.repo import RepoModel
 
@@ -208,9 +209,56 @@ class PullrequestsController(BaseRepoCon
 
                          .get_comments(c.rhodecode_db_repo.repo_id,
 
                                        pull_request=pull_request_id)
 

	
 
        # changeset(pull-request) statuse
 
        # changeset(pull-request) status
 
        c.current_changeset_status = ChangesetStatusModel()\
 
                              .get_status(c.rhodecode_db_repo.repo_id,
 
                                          pull_request=pull_request_id)
 
                              .get_status(c.pull_request.org_repo,
 
                                          pull_request=c.pull_request)
 
        c.changeset_statuses = ChangesetStatus.STATUSES
 
        return render('/pullrequests/pullrequest_show.html')
 

	
 
    @jsonify
 
    def comment(self, repo_name, pull_request_id):
 

	
 
        status = request.POST.get('changeset_status')
 
        change_status = request.POST.get('change_changeset_status')
 

	
 
        comm = ChangesetCommentsModel().create(
 
            text=request.POST.get('text'),
 
            repo_id=c.rhodecode_db_repo.repo_id,
 
            user_id=c.rhodecode_user.user_id,
 
            pull_request=pull_request_id,
 
            f_path=request.POST.get('f_path'),
 
            line_no=request.POST.get('line'),
 
            status_change=(ChangesetStatus.get_status_lbl(status) 
 
                           if status and change_status else None)
 
        )
 

	
 
        # get status if set !
 
        if status and change_status:
 
            ChangesetStatusModel().set_status(
 
                c.rhodecode_db_repo.repo_id,
 
                status,
 
                c.rhodecode_user.user_id,
 
                comm,
 
                pull_request=pull_request_id
 
            )
 
        action_logger(self.rhodecode_user,
 
                      'user_commented_pull_request:%s' % pull_request_id,
 
                      c.rhodecode_db_repo, self.ip_addr, self.sa)
 

	
 
        Session.commit()
 

	
 
        if not request.environ.get('HTTP_X_PARTIAL_XHR'):
 
            return redirect(h.url('pullrequest_show', repo_name=repo_name,
 
                                  pull_request_id=pull_request_id))
 

	
 
        data = {
 
           'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
 
        }
 
        if comm:
 
            c.co = comm
 
            data.update(comm.get_dict())
 
            data.update({'rendered_text':
 
                         render('changeset/changeset_comment_block.html')})
 

	
 
        return data
 
\ No newline at end of file
rhodecode/model/changeset_status.py
Show inline comments
 
@@ -66,12 +66,15 @@ class ChangesetStatusModel(BaseModel):
 
        else:
 
            raise Exception('Please specify revision or pull_request')
 

	
 
        status = q.scalar()
 
        # need to use first here since there can be multiple statuses
 
        # returned from pull_request
 
        status = q.first()
 
        status = status.status if status else status
 
        st = status or ChangesetStatus.DEFAULT
 
        return str(st)
 

	
 
    def set_status(self, repo, revision, status, user, comment):
 
    def set_status(self, repo, status, user, comment, revision=None,
 
                   pull_request=None):
 
        """
 
        Creates new status for changeset or updates the old ones bumping their
 
        version, leaving the current status at
 
@@ -89,20 +92,48 @@ class ChangesetStatusModel(BaseModel):
 
        """
 
        repo = self._get_repo(repo)
 

	
 
        cur_statuses = ChangesetStatus.query()\
 
            .filter(ChangesetStatus.repo == repo)\
 
            .filter(ChangesetStatus.revision == revision)\
 
            .all()
 
        q = ChangesetStatus.query()
 

	
 
        if revision:
 
            q = q.filter(ChangesetStatus.repo == repo)
 
            q = q.filter(ChangesetStatus.revision == revision)
 
        elif pull_request:
 
            pull_request = self.__get_pull_request(pull_request)
 
            q = q.filter(ChangesetStatus.repo == pull_request.org_repo)
 
            q = q.filter(ChangesetStatus.pull_request == pull_request)
 
        cur_statuses = q.all()
 

	
 
        if cur_statuses:
 
            for st in cur_statuses:
 
                st.version += 1
 
                self.sa.add(st)
 
        new_status = ChangesetStatus()
 
        new_status.author = self._get_user(user)
 
        new_status.repo = self._get_repo(repo)
 
        new_status.status = status
 
        new_status.revision = revision
 
        new_status.comment = comment
 
        self.sa.add(new_status)
 
        return new_status
 

	
 
        def _create_status(user, repo, status, comment, revision, pull_request):
 
            new_status = ChangesetStatus()
 
            new_status.author = self._get_user(user)
 
            new_status.repo = self._get_repo(repo)
 
            new_status.status = status
 
            new_status.comment = comment
 
            new_status.revision = revision
 
            new_status.pull_request = pull_request
 
            return new_status
 

	
 
        if revision:
 
            new_status = _create_status(user=user, repo=repo, status=status,
 
                           comment=comment, revision=revision, 
 
                           pull_request=None)
 
            self.sa.add(new_status)
 
            return new_status
 
        elif pull_request:
 
            #pull request can have more than one revision associated to it
 
            #we need to create new version for each one
 
            new_statuses = []
 
            repo = pull_request.org_repo
 
            for rev in pull_request.revisions:
 
                new_status = _create_status(user=user, repo=repo,
 
                                            status=status, comment=comment,
 
                                            revision=rev,
 
                                            pull_request=pull_request)
 
                new_statuses.append(new_status)
 
                self.sa.add(new_status)
 
            return new_statuses
rhodecode/model/comment.py
Show inline comments
 
@@ -55,38 +55,54 @@ class ChangesetCommentsModel(BaseModel):
 
                user_objects.append(user_obj)
 
        return user_objects
 

	
 
    def create(self, text, repo_id, user_id, revision, f_path=None,
 
               line_no=None, status_change=None):
 
    def create(self, text, repo_id, user_id, revision=None, pull_request=None,
 
               f_path=None, line_no=None, status_change=None):
 
        """
 
        Creates new comment for changeset. IF status_change is not none
 
        this comment is associated with a status change of changeset
 
        Creates new comment for changeset or pull request.
 
        IF status_change is not none this comment is associated with a 
 
        status change of changeset or changesets associated with pull request
 

	
 
        :param text:
 
        :param repo_id:
 
        :param user_id:
 
        :param revision:
 
        :param pull_request:
 
        :param f_path:
 
        :param line_no:
 
        :param status_change:
 
        """
 
        if not text:
 
            return
 

	
 
        if text:
 
            repo = Repository.get(repo_id)
 
        repo = Repository.get(repo_id)
 
        comment = ChangesetComment()
 
        comment.repo = repo
 
        comment.user_id = user_id
 
        comment.text = text
 
        comment.f_path = f_path
 
        comment.line_no = line_no
 

	
 
        if revision:
 
            cs = repo.scm_instance.get_changeset(revision)
 
            desc = "%s - %s" % (cs.short_id, h.shorter(cs.message, 256))
 
            author_email = cs.author_email
 
            comment = ChangesetComment()
 
            comment.repo = repo
 
            comment.user_id = user_id
 
            comment.revision = revision
 
            comment.text = text
 
            comment.f_path = f_path
 
            comment.line_no = line_no
 
        elif pull_request:
 
            pull_request = self.__get_pull_request(pull_request)
 
            comment.pull_request = pull_request
 
            desc = ''
 
        else:
 
            raise Exception('Please specify revision or pull_request_id')
 

	
 
            self.sa.add(comment)
 
            self.sa.flush()
 
            # make notification
 
            line = ''
 
        self.sa.add(comment)
 
        self.sa.flush()
 

	
 
        # make notification
 
        line = ''
 
        body = text
 

	
 
        #changeset
 
        if revision:
 
            if line_no:
 
                line = _('on line %s') % line_no
 
            subj = safe_unicode(
 
@@ -99,34 +115,41 @@ class ChangesetCommentsModel(BaseModel):
 
                          )
 
                )
 
            )
 

	
 
            body = text
 

	
 
            notification_type = Notification.TYPE_CHANGESET_COMMENT
 
            # get the current participants of this changeset
 
            recipients = ChangesetComment.get_users(revision=revision)
 

	
 
            # add changeset author if it's in rhodecode system
 
            recipients += [User.get_by_email(author_email)]
 
        #pull request
 
        elif pull_request:
 
            #TODO: make this something usefull
 
            subj = 'commented on pull request something...'
 
            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]
 

	
 
            # create notification objects, and emails
 
        # create notification objects, and emails
 
        NotificationModel().create(
 
          created_by=user_id, subject=subj, body=body,
 
          recipients=recipients, type_=notification_type,
 
          email_kwargs={'status_change': status_change}
 
        )
 

	
 
        mention_recipients = set(self._extract_mentions(body))\
 
                                .difference(recipients)
 
        if mention_recipients:
 
            subj = _('[Mention]') + ' ' + subj
 
            NotificationModel().create(
 
              created_by=user_id, subject=subj, body=body,
 
              recipients=recipients, type_=Notification.TYPE_CHANGESET_COMMENT,
 
              email_kwargs={'status_change': status_change}
 
                created_by=user_id, subject=subj, body=body,
 
                recipients=mention_recipients,
 
                type_=notification_type,
 
                email_kwargs={'status_change': status_change}
 
            )
 

	
 
            mention_recipients = set(self._extract_mentions(body))\
 
                                    .difference(recipients)
 
            if mention_recipients:
 
                subj = _('[Mention]') + ' ' + subj
 
                NotificationModel().create(
 
                    created_by=user_id, subject=subj, body=body,
 
                    recipients=mention_recipients,
 
                    type_=Notification.TYPE_CHANGESET_COMMENT,
 
                    email_kwargs={'status_change': status_change}
 
                )
 

	
 
            return comment
 
        return comment
 

	
 
    def delete(self, comment):
 
        """
rhodecode/model/db.py
Show inline comments
 
@@ -766,7 +766,12 @@ class Repository(Base, BaseModel):
 
            statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
 
        grouped = {}
 
        for stat in statuses.all():
 
            grouped[stat.revision] = [str(stat.status), stat.status_lbl]
 
            pr_id = pr_repo = None
 
            if stat.pull_request:
 
                pr_id = stat.pull_request.pull_request_id
 
                pr_repo = stat.pull_request.other_repo.repo_name
 
            grouped[stat.revision] = [str(stat.status), stat.status_lbl,
 
                                      pr_id, pr_repo]
 
        return grouped
 

	
 
    #==========================================================================
 
@@ -1336,17 +1341,21 @@ class ChangesetComment(Base, BaseModel):
 
    pull_request = relationship('PullRequest', lazy='joined')
 

	
 
    @classmethod
 
    def get_users(cls, revision):
 
    def get_users(cls, revision=None, pull_request_id=None):
 
        """
 
        Returns user associated with this changesetComment. ie those
 
        Returns user associated with this ChangesetComment. ie those
 
        who actually commented
 

	
 
        :param cls:
 
        :param revision:
 
        """
 
        return Session.query(User)\
 
                .filter(cls.revision == revision)\
 
                .join(ChangesetComment.author).all()
 
        q = Session.query(User)\
 
                .join(ChangesetComment.author)
 
        if revision:
 
            q = q.filter(cls.revision == revision)
 
        elif pull_request_id:
 
            q = q.filter(cls.pull_request_id == pull_request_id)
 
        return q.all()
 

	
 

	
 
class ChangesetStatus(Base, BaseModel):
 
@@ -1457,6 +1466,7 @@ class Notification(Base, BaseModel):
 
    TYPE_MENTION = u'mention'
 
    TYPE_REGISTRATION = u'registration'
 
    TYPE_PULL_REQUEST = u'pull_request'
 
    TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
 

	
 
    notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
 
    subject = Column('subject', Unicode(512), nullable=True)
rhodecode/model/notification.py
Show inline comments
 
@@ -198,13 +198,15 @@ class NotificationModel(BaseModel):
 
        Creates a human readable description based on properties
 
        of notification object
 
        """
 

	
 
        #alias
 
        _n = notification
 
        _map = {
 
            notification.TYPE_CHANGESET_COMMENT: _('commented on commit'),
 
            notification.TYPE_MESSAGE: _('sent message'),
 
            notification.TYPE_MENTION: _('mentioned you'),
 
            notification.TYPE_REGISTRATION: _('registered in RhodeCode'),
 
            notification.TYPE_PULL_REQUEST: _('opened new pull request')
 
            _n.TYPE_CHANGESET_COMMENT: _('commented on commit'),
 
            _n.TYPE_MESSAGE: _('sent message'),
 
            _n.TYPE_MENTION: _('mentioned you'),
 
            _n.TYPE_REGISTRATION: _('registered in RhodeCode'),
 
            _n.TYPE_PULL_REQUEST: _('opened new pull request'),
 
            _n.TYPE_PULL_REQUEST_COMMENT: _('commented on pull request')
 
        }
 

	
 
        tmpl = "%(user)s %(action)s %(when)s"
rhodecode/templates/changelog/changelog.html
Show inline comments
 
@@ -85,7 +85,13 @@ ${_('%s Changelog') % c.repo_name} - ${c
 
                                        <div class="changeset-status-container">
 
                                            %if c.statuses.get(cs.raw_id):
 
                                              <div title="${_('Changeset status')}" class="changeset-status-lbl">${c.statuses.get(cs.raw_id)[1]}</div>
 
                                              <div class="changeset-status-ico"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" /></div>
 
                                              <div class="changeset-status-ico">
 
                                              %if c.statuses.get(cs.raw_id)[2]:
 
                                                <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>
 
                                              %else:
 
                                                <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
 
                                              %endif
 
                                              </div>
 
                                            %endif
 
                                        </div>
 
									</div>
rhodecode/templates/pullrequests/pullrequest_show.html
Show inline comments
 
@@ -70,8 +70,8 @@
 
    ##${comment.comment_inline_form(c.changeset)}
 

	
 
    ## render comments main comments form and it status
 
    ##${comment.comments(h.url('pull_request_comment', repo_name=c.repo_name, pull_request_id=c.pull_request.pull_request_id),
 
    ##                   c.current_changeset_status)}
 
    ${comment.comments(h.url('pullrequest_comment', repo_name=c.repo_name, pull_request_id=c.pull_request.pull_request_id),
 
                       c.current_changeset_status)}
 
    
 
</div>
 

	
0 comments (0 inline, 0 general)