##// END OF EJS Templates
fixes inline comments double entries
marcink -
r1681:1bf03daa beta
parent child Browse files
Show More
@@ -1,93 +1,95
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.comment
4 4 ~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 comments model for RhodeCode
7 7
8 8 :created_on: Nov 11, 2011
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26
27 27 import logging
28 28 import traceback
29 29
30 30 from rhodecode.model import BaseModel
31 31 from rhodecode.model.db import ChangesetComment
32 32 from sqlalchemy.util.compat import defaultdict
33 33
34 34 log = logging.getLogger(__name__)
35 35
36 36
37 37 class ChangesetCommentsModel(BaseModel):
38 38
39 39
40 40 def create(self, text, repo_id, user_id, revision, f_path=None,
41 41 line_no=None):
42 42 """
43 43 Creates new comment for changeset
44 44
45 45 :param text:
46 46 :param repo_id:
47 47 :param user_id:
48 48 :param revision:
49 49 :param f_path:
50 50 :param line_no:
51 51 """
52 52 if text:
53 53 comment = ChangesetComment()
54 54 comment.repo_id = repo_id
55 55 comment.user_id = user_id
56 56 comment.revision = revision
57 57 comment.text = text
58 58 comment.f_path = f_path
59 59 comment.line_no = line_no
60 60
61 61 self.sa.add(comment)
62 62 self.sa.commit()
63 63 return comment
64 64
65 65 def delete(self, comment_id):
66 66 """
67 67 Deletes given comment
68 68
69 69 :param comment_id:
70 70 """
71 71 comment = ChangesetComment.get(comment_id)
72 72 self.sa.delete(comment)
73 73 self.sa.commit()
74 74 return comment
75 75
76 76
77 77 def get_comments(self, repo_id, revision):
78 78 return ChangesetComment.query()\
79 79 .filter(ChangesetComment.repo_id == repo_id)\
80 80 .filter(ChangesetComment.revision == revision)\
81 81 .filter(ChangesetComment.line_no == None)\
82 82 .filter(ChangesetComment.f_path == None).all()
83 83
84 84 def get_inline_comments(self, repo_id, revision):
85 85 comments = self.sa.query(ChangesetComment)\
86 86 .filter(ChangesetComment.repo_id == repo_id)\
87 .filter(ChangesetComment.revision == revision).all()
87 .filter(ChangesetComment.revision == revision)\
88 .filter(ChangesetComment.line_no != None)\
89 .filter(ChangesetComment.f_path != None).all()
88 90
89 91 paths = defaultdict(lambda:defaultdict(list))
90 92
91 93 for co in comments:
92 94 paths[co.f_path][co.line_no].append(co)
93 95 return paths.items()
@@ -1,214 +1,216
1 1 ## -*- coding: utf-8 -*-
2 2
3 3 <%inherit file="/base/base.html"/>
4 4
5 5 <%def name="title()">
6 6 ${c.repo_name} ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)} - ${c.rhodecode_name}
7 7 </%def>
8 8
9 9 <%def name="breadcrumbs_links()">
10 10 ${h.link_to(u'Home',h.url('/'))}
11 11 &raquo;
12 12 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
13 13 &raquo;
14 14 ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
15 15 </%def>
16 16
17 17 <%def name="page_nav()">
18 18 ${self.menu('changelog')}
19 19 </%def>
20 20
21 21 <%def name="main()">
22 22 <div class="box">
23 23 <!-- box / title -->
24 24 <div class="title">
25 25 ${self.breadcrumbs()}
26 26 </div>
27 27 <div class="table">
28 28 <div class="diffblock">
29 29 <div class="code-header">
30 30 <div>
31 31 ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
32 32 &raquo; <span>${h.link_to(_('raw diff'),
33 33 h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show'))}</span>
34 34 &raquo; <span>${h.link_to(_('download diff'),
35 35 h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download'))}</span>
36 36 </div>
37 37 </div>
38 38 </div>
39 39 <div id="changeset_content">
40 40 <div class="container">
41 41 <div class="left">
42 42 <div class="date">${_('commit')} ${c.changeset.revision}: ${h.short_id(c.changeset.raw_id)}@${c.changeset.date}</div>
43 43 <div class="author">
44 44 <div class="gravatar">
45 45 <img alt="gravatar" src="${h.gravatar_url(h.email(c.changeset.author),20)}"/>
46 46 </div>
47 47 <span>${h.person(c.changeset.author)}</span><br/>
48 48 <span><a href="mailto:${h.email_or_none(c.changeset.author)}">${h.email_or_none(c.changeset.author)}</a></span><br/>
49 49 </div>
50 50 <div class="message">${h.link_to(h.wrap_paragraphs(c.changeset.message),h.url('changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</div>
51 51 </div>
52 52 <div class="right">
53 53 <div class="changes">
54 54 % if len(c.changeset.affected_files) <= c.affected_files_cut_off:
55 55 <span class="removed" title="${_('removed')}">${len(c.changeset.removed)}</span>
56 56 <span class="changed" title="${_('changed')}">${len(c.changeset.changed)}</span>
57 57 <span class="added" title="${_('added')}">${len(c.changeset.added)}</span>
58 58 % else:
59 59 <span class="removed" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
60 60 <span class="changed" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
61 61 <span class="added" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
62 62 % endif
63 63 </div>
64 64 %if len(c.changeset.parents)>1:
65 65 <div class="merge">
66 66 ${_('merge')}<img alt="merge" src="${h.url('/images/icons/arrow_join.png')}"/>
67 67 </div>
68 68 %endif
69 69
70 70 %if c.changeset.parents:
71 71 %for p_cs in reversed(c.changeset.parents):
72 72 <div class="parent">${_('Parent')} ${p_cs.revision}: ${h.link_to(h.short_id(p_cs.raw_id),
73 73 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}
74 74 </div>
75 75 %endfor
76 76 %else:
77 77 <div class="parent">${_('No parents')}</div>
78 78 %endif
79 79 <span class="logtags">
80 80 <span class="branchtag" title="${'%s %s' % (_('branch'),c.changeset.branch)}">
81 81 ${h.link_to(c.changeset.branch,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
82 82 %for tag in c.changeset.tags:
83 83 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
84 84 ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
85 85 %endfor
86 86 </span>
87 87 </div>
88 88 </div>
89 89 <span style="font-size:1.1em;font-weight: bold">
90 90 ${_('%s files affected with %s additions and %s deletions.') % (len(c.changeset.affected_files),c.lines_added,c.lines_deleted)}
91 91 </span>
92 92 <div class="cs_files">
93 93 %for change,filenode,diff,cs1,cs2,stat in c.changes:
94 94 <div class="cs_${change}">
95 95 <div class="node">${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor='C-%s-%s' % (h.short_id(filenode.changeset.raw_id),h.safeid(h.safe_unicode(filenode.path)))))}</div>
96 96 <div class="changes">${h.fancy_file_stats(stat)}</div>
97 97 </div>
98 98 %endfor
99 99 % if c.cut_off:
100 100 ${_('Changeset was too big and was cut off...')}
101 101 % endif
102 102 </div>
103 103 </div>
104 104
105 105 </div>
106 106
107 107 %for change,filenode,diff,cs1,cs2,stat in c.changes:
108 108 %if change !='removed':
109 109 <div style="clear:both;height:10px"></div>
110 110 <div class="diffblock margined">
111 111 <div id="${'C-%s-%s' % (h.short_id(filenode.changeset.raw_id),h.safeid(h.safe_unicode(filenode.path)))}" class="code-header">
112 112 <div class="changeset_header">
113 113 <span class="changeset_file">
114 114 ${h.link_to_if(change!='removed',h.safe_unicode(filenode.path),h.url('files_home',repo_name=c.repo_name,
115 115 revision=filenode.changeset.raw_id,f_path=h.safe_unicode(filenode.path)))}
116 116 </span>
117 117 &raquo; <span>${h.link_to(_('diff'),
118 118 h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='diff'))}</span>
119 119 &raquo; <span>${h.link_to(_('raw diff'),
120 120 h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='raw'))}</span>
121 121 &raquo; <span>${h.link_to(_('download diff'),
122 122 h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='download'))}</span>
123 123 </div>
124 124 </div>
125 125 <div class="code-body">
126 126 <div class="full_f_path" path="${filenode.path}"></div>
127 127 %if diff:
128 128 ${diff|n}
129 129 %else:
130 130 ${_('No changes in this file')}
131 131 %endif
132 132 </div>
133 133 </div>
134 134 %endif
135 135 %endfor
136 136
137 137 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
138 138 ## template for inline comment form
139 139 ${comment.comment_inline_form()}
140 140
141 141 <div class="comments">
142 142 <div class="comments-number">${len(c.comments)} comment(s) (${c.inline_cnt} ${_('inline')})</div>
143 143
144 144 %for path, lines in c.inline_comments:
145 145 <div class="inline-comment-placeholder" path="${path} ">
146 146 % for line,comments in lines.iteritems():
147 147 <div class="inline-comment-placeholder-line" line="${line}">
148 148 %for co in comments:
149 149 ${comment.comment_block(co)}
150 150 %endfor
151 151 </div>
152 152 %endfor
153 153 </div>
154 154 %endfor
155 155
156 156 %for co in c.comments:
157 157 ${comment.comment_block(co)}
158 158 %endfor
159 159 %if c.rhodecode_user.username != 'default':
160 160 <div class="comment-form">
161 161 ${h.form(h.url('changeset_comment', repo_name=c.repo_name, revision=c.changeset.raw_id))}
162 162 <strong>${_('Leave a comment')}</strong>
163 163 <div class="clearfix">
164 <div class="comment-help">${_('Comments parsed using RST syntax')}</div>
164 <div class="comment-help">
165 ${_('Comments parsed using')} <a href="${h.url('rst_help')}">RST</a> ${_('syntax')}
166 </div>
165 167 ${h.textarea('text')}
166 168 </div>
167 169 <div class="comment-button">
168 170 ${h.submit('save', _('Comment'), class_='ui-button')}
169 171 </div>
170 172 ${h.end_form()}
171 173 </div>
172 174 %endif
173 175 </div>
174 176 <script type="text/javascript">
175 177 var deleteComment = function(comment_id){
176 178
177 179 var url = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}".replace('__COMMENT_ID__',comment_id);
178 180 var postData = '_method=delete';
179 181 var success = function(o){
180 182 var n = YUD.get('comment-'+comment_id);
181 183 n.parentNode.removeChild(n);
182 184 }
183 185 ajaxPOST(url,postData,success);
184 186 }
185 187
186 188 YUE.onDOMReady(function(){
187 189 YUE.on(YUQ('.line'),'mouseenter',function(e){
188 190 var tr = e.currentTarget;
189 191 if(YUD.hasClass(tr,'form-open') || YUD.hasClass(tr,'context')){
190 192 return
191 193 }
192 194 YUD.addClass(tr,'highlight');
193 195 });
194 196 YUE.on(YUQ('.line'),'mouseleave',function(e){
195 197 YUD.removeClass(e.currentTarget,'highlight');
196 198 });
197 199
198 200 YUE.on(YUQ('.line'),'click',function(e){
199 201 var tr = e.currentTarget;
200 202 if(YUD.hasClass(tr,'form-open') || YUD.hasClass(tr,'context')){
201 203 return
202 204 }
203 205 YUD.addClass(tr,'form-open');
204 206 var node = tr.parentNode.parentNode.parentNode.getElementsByClassName('full_f_path')[0];
205 207 var f_path = YUD.getAttribute(node,'path');
206 208 var lineno = getLineNo(tr);
207 209 var form = createInlineForm(tr, f_path, lineno);
208 210 YUD.insertAfter(form,tr);
209 211 })
210 212 })
211 213
212 214 </script>
213 215 </div>
214 216 </%def>
General Comments 0
You need to be logged in to leave comments. Login now