diff --git a/rhodecode/apps/repository/views/repo_commits.py b/rhodecode/apps/repository/views/repo_commits.py --- a/rhodecode/apps/repository/views/repo_commits.py +++ b/rhodecode/apps/repository/views/repo_commits.py @@ -380,49 +380,36 @@ class RepoCommitsView(RepoAppView): commit_id = self.request.matchdict['commit_id'] return self._commit(commit_id, method='download') - @LoginRequired() - @NotAnonymous() - @HasRepoPermissionAnyDecorator( - 'repository.read', 'repository.write', 'repository.admin') - @CSRFRequired() - @view_config( - route_name='repo_commit_comment_create', request_method='POST', - renderer='json_ext') - def repo_commit_comment_create(self): + def _commit_comments_create(self, commit_id, comments): _ = self.request.translate - commit_id = self.request.matchdict['commit_id'] + data = {} + if not comments: + return + + commit = self.db_repo.get_commit(commit_id) - c = self.load_default_context() - status = self.request.POST.get('changeset_status', None) - is_draft = str2bool(self.request.POST.get('draft')) - text = self.request.POST.get('text') - comment_type = self.request.POST.get('comment_type') - resolves_comment_id = self.request.POST.get('resolves_comment_id', None) - f_path = self.request.POST.get('f_path') - line_no = self.request.POST.get('line') - target_elem_id = 'file-{}'.format(h.safeid(h.safe_unicode(f_path))) + all_drafts = len([x for x in comments if str2bool(x['is_draft'])]) == len(comments) + for entry in comments: + c = self.load_default_context() + comment_type = entry['comment_type'] + text = entry['text'] + status = entry['status'] + is_draft = str2bool(entry['is_draft']) + resolves_comment_id = entry['resolves_comment_id'] + f_path = entry['f_path'] + line_no = entry['line'] + target_elem_id = 'file-{}'.format(h.safeid(h.safe_unicode(f_path))) - if status: - text = text or (_('Status change %(transition_icon)s %(status)s') - % {'transition_icon': '>', - 'status': ChangesetStatus.get_status_lbl(status)}) + if status: + text = text or (_('Status change %(transition_icon)s %(status)s') + % {'transition_icon': '>', + 'status': ChangesetStatus.get_status_lbl(status)}) - multi_commit_ids = [] - for _commit_id in self.request.POST.get('commit_ids', '').split(','): - if _commit_id not in ['', None, EmptyCommit.raw_id]: - if _commit_id not in multi_commit_ids: - multi_commit_ids.append(_commit_id) - - commit_ids = multi_commit_ids or [commit_id] - - data = {} - # Multiple comments for each passed commit id - for current_id in filter(None, commit_ids): comment = CommentsModel().create( text=text, repo=self.db_repo.repo_id, user=self._rhodecode_db_user.user_id, - commit_id=current_id, + commit_id=commit_id, f_path=f_path, line_no=line_no, status_change=(ChangesetStatus.get_status_lbl(status) @@ -438,9 +425,9 @@ class RepoCommitsView(RepoAppView): # get status if set ! if status: + # `dont_allow_on_closed_pull_request = True` means # if latest status was from pull request and it's closed # disallow changing status ! - # dont_allow_on_closed_pull_request = True ! try: ChangesetStatusModel().set_status( @@ -448,7 +435,7 @@ class RepoCommitsView(RepoAppView): status, self._rhodecode_db_user.user_id, comment, - revision=current_id, + revision=commit_id, dont_allow_on_closed_pull_request=True ) except StatusChangeOnClosedPullRequestError: @@ -458,11 +445,15 @@ class RepoCommitsView(RepoAppView): h.flash(msg, category='warning') raise HTTPFound(h.route_path( 'repo_commit', repo_name=self.db_repo_name, - commit_id=current_id)) + commit_id=commit_id)) + + Session().flush() + # this is somehow required to get access to some relationship + # loaded on comment + Session().refresh(comment) # skip notifications for drafts if not is_draft: - commit = self.db_repo.get_commit(current_id) CommentsModel().trigger_commit_comment_hook( self.db_repo, self._rhodecode_user, 'create', data={'comment': comment, 'commit': commit}) @@ -471,6 +462,8 @@ class RepoCommitsView(RepoAppView): data[comment_id] = { 'target_id': target_elem_id } + Session().flush() + c.co = comment c.at_version_num = 0 c.is_new = True @@ -481,21 +474,25 @@ class RepoCommitsView(RepoAppView): data[comment_id].update(comment.get_dict()) data[comment_id].update({'rendered_text': rendered_comment}) - # skip channelstream for draft comments - if not is_draft: - comment_broadcast_channel = channelstream.comment_channel( - self.db_repo_name, commit_obj=commit) - - comment_data = data - posted_comment_type = 'inline' if is_inline else 'general' - channelstream.comment_channelstream_push( - self.request, comment_broadcast_channel, self._rhodecode_user, - _('posted a new {} comment').format(posted_comment_type), - comment_data=comment_data) - # finalize, commit and redirect Session().commit() + # skip channelstream for draft comments + if not all_drafts: + comment_broadcast_channel = channelstream.comment_channel( + self.db_repo_name, commit_obj=commit) + + comment_data = data + posted_comment_type = 'inline' if is_inline else 'general' + if len(data) == 1: + msg = _('posted {} new {} comment').format(len(data), posted_comment_type) + else: + msg = _('posted {} new {} comments').format(len(data), posted_comment_type) + + channelstream.comment_channelstream_push( + self.request, comment_broadcast_channel, self._rhodecode_user, msg, + comment_data=comment_data) + return data @LoginRequired() @@ -504,6 +501,44 @@ class RepoCommitsView(RepoAppView): 'repository.read', 'repository.write', 'repository.admin') @CSRFRequired() @view_config( + route_name='repo_commit_comment_create', request_method='POST', + renderer='json_ext') + def repo_commit_comment_create(self): + _ = self.request.translate + commit_id = self.request.matchdict['commit_id'] + + multi_commit_ids = [] + for _commit_id in self.request.POST.get('commit_ids', '').split(','): + if _commit_id not in ['', None, EmptyCommit.raw_id]: + if _commit_id not in multi_commit_ids: + multi_commit_ids.append(_commit_id) + + commit_ids = multi_commit_ids or [commit_id] + + data = [] + # Multiple comments for each passed commit id + for current_id in filter(None, commit_ids): + comment_data = { + 'comment_type': self.request.POST.get('comment_type'), + 'text': self.request.POST.get('text'), + 'status': self.request.POST.get('changeset_status', None), + 'is_draft': self.request.POST.get('draft'), + 'resolves_comment_id': self.request.POST.get('resolves_comment_id', None), + 'close_pull_request': self.request.POST.get('close_pull_request'), + 'f_path': self.request.POST.get('f_path'), + 'line': self.request.POST.get('line'), + } + comment = self._commit_comments_create(commit_id=current_id, comments=[comment_data]) + data.append(comment) + + return data if len(data) > 1 else data[0] + + @LoginRequired() + @NotAnonymous() + @HasRepoPermissionAnyDecorator( + 'repository.read', 'repository.write', 'repository.admin') + @CSRFRequired() + @view_config( route_name='repo_commit_comment_preview', request_method='POST', renderer='string', xhr=True) def repo_commit_comment_preview(self): @@ -690,6 +725,7 @@ class RepoCommitsView(RepoAppView): def repo_commit_comment_edit(self): self.load_default_context() + commit_id = self.request.matchdict['commit_id'] comment_id = self.request.matchdict['comment_id'] comment = ChangesetComment.get_or_404(comment_id) @@ -742,11 +778,11 @@ class RepoCommitsView(RepoAppView): if not comment_history: raise HTTPNotFound() - commit_id = self.request.matchdict['commit_id'] - commit = self.db_repo.get_commit(commit_id) - CommentsModel().trigger_commit_comment_hook( - self.db_repo, self._rhodecode_user, 'edit', - data={'comment': comment, 'commit': commit}) + if not comment.draft: + commit = self.db_repo.get_commit(commit_id) + CommentsModel().trigger_commit_comment_hook( + self.db_repo, self._rhodecode_user, 'edit', + data={'comment': comment, 'commit': commit}) Session().commit() return { diff --git a/rhodecode/apps/repository/views/repo_pull_requests.py b/rhodecode/apps/repository/views/repo_pull_requests.py --- a/rhodecode/apps/repository/views/repo_pull_requests.py +++ b/rhodecode/apps/repository/views/repo_pull_requests.py @@ -1523,9 +1523,9 @@ class RepoPullRequestsView(RepoAppView, def _pull_request_comments_create(self, pull_request, comments): _ = self.request.translate data = {} - pull_request_id = pull_request.pull_request_id if not comments: return + pull_request_id = pull_request.pull_request_id all_drafts = len([x for x in comments if str2bool(x['is_draft'])]) == len(comments) @@ -1616,9 +1616,11 @@ class RepoPullRequestsView(RepoAppView, # loaded on comment Session().refresh(comment) - PullRequestModel().trigger_pull_request_hook( - pull_request, self._rhodecode_user, 'comment', - data={'comment': comment}) + # skip notifications for drafts + if not is_draft: + PullRequestModel().trigger_pull_request_hook( + pull_request, self._rhodecode_user, 'comment', + data={'comment': comment}) # we now calculate the status of pull request, and based on that # calculation we set the commits status @@ -1647,16 +1649,16 @@ class RepoPullRequestsView(RepoAppView, Session().commit() # skip channelstream for draft comments - if all_drafts: + if not all_drafts: comment_broadcast_channel = channelstream.comment_channel( self.db_repo_name, pull_request_obj=pull_request) comment_data = data - comment_type = 'inline' if is_inline else 'general' + posted_comment_type = 'inline' if is_inline else 'general' if len(data) == 1: - msg = _('posted {} new {} comment').format(len(data), comment_type) + msg = _('posted {} new {} comment').format(len(data), posted_comment_type) else: - msg = _('posted {} new {} comments').format(len(data), comment_type) + msg = _('posted {} new {} comments').format(len(data), posted_comment_type) channelstream.comment_channelstream_push( self.request, comment_broadcast_channel, self._rhodecode_user, msg, @@ -1782,11 +1784,6 @@ class RepoPullRequestsView(RepoAppView, log.debug('comment: forbidden because pull request is closed') raise HTTPForbidden() - if not comment: - log.debug('Comment with id:%s not found, skipping', comment_id) - # comment already deleted in another call probably - return True - if comment.pull_request.is_closed(): # don't allow deleting comments on closed pull request raise HTTPForbidden() @@ -1837,10 +1834,10 @@ class RepoPullRequestsView(RepoAppView, raise HTTPNotFound() Session().commit() - - PullRequestModel().trigger_pull_request_hook( - pull_request, self._rhodecode_user, 'comment_edit', - data={'comment': comment}) + if not comment.draft: + PullRequestModel().trigger_pull_request_hook( + pull_request, self._rhodecode_user, 'comment_edit', + data={'comment': comment}) return { 'comment_history_id': comment_history.comment_history_id, diff --git a/rhodecode/public/css/comments.less b/rhodecode/public/css/comments.less --- a/rhodecode/public/css/comments.less +++ b/rhodecode/public/css/comments.less @@ -509,9 +509,9 @@ form.comment-form { } .toolbar-text { - height: 42px; + height: 28px; display: table-cell; - vertical-align: bottom; + vertical-align: baseline; font-size: 11px; color: @grey4; text-align: right; diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js --- a/rhodecode/public/js/rhodecode/routes.js +++ b/rhodecode/public/js/rhodecode/routes.js @@ -387,6 +387,7 @@ function registerRCRoutes() { pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []); pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []); pyroutes.register('pullrequest_draft_comments_submit', '/%(repo_name)s/pull-request/%(pull_request_id)s/draft_comments_submit', ['repo_name', 'pull_request_id']); + pyroutes.register('commit_draft_comments_submit', '/%(repo_name)s/changeset/%(commit_id)s/draft_comments_submit', ['repo_name', 'commit_id']); pyroutes.register('repo_artifacts_list', '/%(repo_name)s/artifacts', ['repo_name']); pyroutes.register('repo_artifacts_data', '/%(repo_name)s/artifacts_data', ['repo_name']); pyroutes.register('repo_artifacts_new', '/%(repo_name)s/artifacts/new', ['repo_name']); diff --git a/rhodecode/public/js/src/rhodecode/comments.js b/rhodecode/public/js/src/rhodecode/comments.js --- a/rhodecode/public/js/src/rhodecode/comments.js +++ b/rhodecode/public/js/src/rhodecode/comments.js @@ -700,7 +700,16 @@ var CommentsController = function() { var $comment = $node.closest('.comment'); var comment_id = $($comment).data('commentId'); var isDraft = $($comment).data('commentDraft'); - var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id); + + var pullRequestId = templateContext.pull_request_data.pull_request_id; + var commitId = templateContext.commit_data.commit_id; + + if (pullRequestId) { + var url = pyroutes.url('pullrequest_comment_delete', {"comment_id": comment_id, "repo_name": templateContext.repo_name, "pull_request_id": pullRequestId}) + } else if (commitId) { + var url = pyroutes.url('repo_commit_comment_delete', {"comment_id": comment_id, "repo_name": templateContext.repo_name, "commit_id": commitId}) + } + var postData = { 'csrf_token': CSRF_TOKEN }; @@ -756,16 +765,20 @@ var CommentsController = function() { this._finalizeDrafts = function(commentIds) { - // remove the drafts so we can lock them before submit. + var pullRequestId = templateContext.pull_request_data.pull_request_id; + var commitId = templateContext.commit_data.commit_id; + + if (pullRequestId) { + var url = pyroutes.url('pullrequest_draft_comments_submit', {"repo_name": templateContext.repo_name, "pull_request_id": pullRequestId}) + } else if (commitId) { + var url = pyroutes.url('commit_draft_comments_submit', {"repo_name": templateContext.repo_name, "commit_id": commitId}) + } + + // remove the drafts so we can lock them before submit. $.each(commentIds, function(idx, val){ $('#comment-{0}'.format(val)).remove(); }) - var params = { - 'pull_request_id': templateContext.pull_request_data.pull_request_id, - 'repo_name': templateContext.repo_name, - }; - var url = pyroutes.url('pullrequest_draft_comments_submit', params) var postData = {'comments': commentIds, 'csrf_token': CSRF_TOKEN}; var submitSuccessCallback = function(json_data) { diff --git a/rhodecode/templates/changeset/changeset.mako b/rhodecode/templates/changeset/changeset.mako --- a/rhodecode/templates/changeset/changeset.mako +++ b/rhodecode/templates/changeset/changeset.mako @@ -24,8 +24,6 @@ <%def name="main()"> diff --git a/rhodecode/templates/changeset/changeset_file_comment.mako b/rhodecode/templates/changeset/changeset_file_comment.mako --- a/rhodecode/templates/changeset/changeset_file_comment.mako +++ b/rhodecode/templates/changeset/changeset_file_comment.mako @@ -542,7 +542,7 @@
<% renderer_url = '%s' % (h.route_url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper()) %> - ${_('Styling with {} is supported.').format(renderer_url)|n} + ${_('{} is supported.').format(renderer_url)|n}