@@ -331,49 +331,49 @@ def make_map(config):
controller='feed', action='atom',
conditions=dict(function=check_repo))
#==========================================================================
# REPOSITORY ROUTES
rmap.connect('summary_home', '/{repo_name:.*}',
controller='summary',
rmap.connect('repos_group_home', '/{group_name:.*}',
controller='admin/repos_groups', action="show_by_name",
conditions=dict(function=check_group))
rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
controller='changeset', revision='tip',
rmap.connect('changeset_comment', '/{repo_name:.*}/changeset/{revision}/comment',
controller='changeset', revision='tip', action='comment',
rmap.connect('changeset_comment_delete', '/{repo_name:.*}/changeset/comment/{comment_id}/delete',
controller='changeset', action='delete_comment',
conditions = dict(function=check_repo, method=["DELETE"]))
rmap.connect('raw_changeset_home',
'/{repo_name:.*}/raw-changeset/{revision}',
controller='changeset', action='raw_changeset',
revision='tip', conditions=dict(function=check_repo))
rmap.connect('summary_home', '/{repo_name:.*}/summary',
controller='summary', conditions=dict(function=check_repo))
rmap.connect('shortlog_home', '/{repo_name:.*}/shortlog',
controller='shortlog', conditions=dict(function=check_repo))
rmap.connect('branches_home', '/{repo_name:.*}/branches',
controller='branches', conditions=dict(function=check_repo))
rmap.connect('tags_home', '/{repo_name:.*}/tags',
controller='tags', conditions=dict(function=check_repo))
rmap.connect('changelog_home', '/{repo_name:.*}/changelog',
controller='changelog', conditions=dict(function=check_repo))
rmap.connect('changelog_details', '/{repo_name:.*}/changelog_details/{cs}',
controller='changelog', action='changelog_details',
@@ -23,48 +23,49 @@
#
# 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
from pylons import tmpl_context as c, url, request, response
from pylons.i18n.translation import _
from pylons.controllers.util import redirect
from pylons.decorators import jsonify
import rhodecode.lib.helpers as h
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \
NotAnonymous
from rhodecode.lib.base import BaseRepoController, render
from rhodecode.lib.utils import EmptyChangeset
from rhodecode.lib.compat import OrderedDict
from rhodecode.model.db import ChangesetComment
from rhodecode.model.comment import ChangesetCommentsModel
from vcs.exceptions import RepositoryError, ChangesetError, \
ChangesetDoesNotExistError
from vcs.nodes import FileNode
from vcs.utils import diffs as differ
from webob.exc import HTTPForbidden
log = logging.getLogger(__name__)
class ChangesetController(BaseRepoController):
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
'repository.admin')
def __before__(self):
super(ChangesetController, self).__before__()
c.affected_files_cut_off = 60
def index(self, revision):
def wrap_to_table(str):
return '''<table class="code-difftable">
<tr class="line">
<td class="lineno new"></td>
<td class="code"><pre>%s</pre></td>
</tr>
</table>''' % str
@@ -257,29 +258,34 @@ class ChangesetController(BaseRepoContro
% revision
c.parent_tmpl = ''.join(['# Parent %s\n' % x.raw_id for x in
c.changeset.parents])
c.diffs = ''
for x in c.changes:
c.diffs += x[2]
return render('changeset/raw_changeset.html')
def comment(self, repo_name, revision):
ccmodel = ChangesetCommentsModel()
ccmodel.create(text=request.POST.get('text'),
repo_id=c.rhodecode_db_repo.repo_id,
user_id=c.rhodecode_user.user_id,
commit_id=revision, f_path=request.POST.get('f_path'),
line_no = request.POST.get('line'))
return redirect(h.url('changeset_home', repo_name=repo_name,
revision=revision))
@jsonify
@HasRepoPermissionAnyDecorator('hg.admin', 'repository.admin')
def delete_comment(self, comment_id):
ccmodel.delete(comment_id=comment_id)
return True
co = ChangesetComment.get(comment_id)
if (h.HasPermissionAny('hg.admin', 'repository.admin')() or
co.author.user_id == c.rhodecode_user.user_id):
else:
raise HTTPForbidden()
@@ -3242,51 +3242,50 @@ div.rst-block pre {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.comments .comment .meta {
background: #f8f8f8;
padding: 6px;
border-bottom: 1px solid #ddd;
.comments .comment .meta img {
vertical-align: middle;
.comments .comment .meta .user {
font-weight: bold;
.comments .comment .meta .date {
float: right;
.comments .comment .text {
margin-top: 7px;
padding-bottom: 13px;
padding: 8px 6px 6px 14px;
background-color: #FAFAFA;
.comments .comments-number{
padding:0px 0px 10px 0px;
.comment-form .clearfix{
background: #EEE;
padding: 10px;
div.comment-form {
margin-top: 20px;
.comment-form strong {
display: block;
margin-bottom: 15px;
@@ -3309,27 +3308,27 @@ form.comment-form {
.file-comments {
display: none;
.comment-form .comment {
margin-left: 10px;
.comment-form .comment-help{
padding: 0px 0px 5px 0px;
color: #666;
.comment-form .comment-button{
padding-top:5px;
.add-another-button {
margin-top: 10px;
margin-bottom: 10px;
.comment .buttons {
position: absolute;
right:40px;
@@ -265,26 +265,36 @@ var q_filter = function(target,nodes,dis
var i;
var showing = 0;
for (i=0;i<l;i++ ){
var n = nodes[i];
var target_element = display_element(n)
if(req && n.innerHTML.toLowerCase().indexOf(req) == -1){
hide_node(target_element);
else{
show_node(target_element);
showing+=1;
// if repo_count is set update the number
var cnt = YUD.get('repo_count');
if(cnt){
YUD.get('repo_count').innerHTML = showing;
var ajaxPOST = function(url,postData,success) {
var sUrl = url;
var callback = {
success: success,
failure: function (o) {
alert("error");
},
};
var postData = postData;
var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
@@ -137,27 +137,38 @@
%endfor
<%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
<div class="comments">
<div class="comments-number">${len(c.comments)} comment(s)</div>
%for co in c.comments:
${comment.comment_block(co)}
%if c.rhodecode_user.username != 'default':
<div class="comment-form">
${h.form(h.url('changeset_comment', repo_name=c.repo_name, revision=c.changeset.raw_id))}
<strong>Leave a comment</strong>
<div class="clearfix">
<div class="comment-help">${_('Comments parsed using RST syntax')}</div>
${h.textarea('text')}
</div>
<div class="comment-button">
${h.submit('save', _('Comment'), class_='ui-button')}
${h.end_form()}
%endif
<script type="text/javascript">
var deleteComment = function(comment_id){
var url = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}".replace('__COMMENT_ID__',comment_id);
var postData = '_method=delete';
var success = function(o){
var n = YUD.get('comment-'+comment_id);
n.parentNode.removeChild(n);
ajaxPOST(url,postData,success);
</script>
</%def>
##usage:
## <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
## ${comment.comment_block(co)}
##
<%def name="comment_block(co)">
<div class="comment" id="comment-${co.comment_id}">
<div class="meta">
<span class="user">
<img src="${h.gravatar_url(co.author.email, 20)}" />
${co.author.username}
</span>
<a href="${h.url.current(anchor='comment-%s' % co.comment_id)}"> ${_('commented on')} </a>
${h.short_id(co.commit_id)}
%if co.f_path:
${_(' in file ')}
${co.f_path}:L${co.line_no}
<span class="date">
${h.age(co.modified_at)}
<div class="text">
%if h.HasPermissionAny('hg.admin', 'repository.admin')() or co.author.user_id == c.rhodecode_user.user_id:
<div class="buttons">
<a href="javascript:void(0);" onClick="deleteComment(${co.comment_id})" class="">${_('Delete')}</a>
<span onClick="deleteComment(${co.comment_id})" class="delete-comment ui-button-small">${_('Delete')}</span>
${h.rst(co.text)|n}
\ No newline at end of file
Status change: