Show More
@@ -17,3 +17,4 b' List of contributors to RhodeCode projec' | |||
|
17 | 17 | Matt Zuba <matt.zuba@goodwillaz.org> |
|
18 | 18 | Aras Pranckevicius <aras@unity3d.com> |
|
19 | 19 | Tony Bussieres <t.bussieres@gmail.com> |
|
20 | Erwin Kroon <e.kroon@smartmetersolutions.nl> No newline at end of file |
@@ -648,6 +648,7 b' Here is a sample excerpt from an Apache ' | |||
|
648 | 648 | threads=4 \ |
|
649 | 649 | python-path=/home/web/rhodecode/pyenv/lib/python2.6/site-packages |
|
650 | 650 | WSGIScriptAlias / /home/web/rhodecode/dispatch.wsgi |
|
651 | WSGIPassAuthorization On | |
|
651 | 652 | |
|
652 | 653 | Example wsgi dispatch script:: |
|
653 | 654 |
@@ -1,5 +1,5 b'' | |||
|
1 | 1 | Pylons==1.0.0 |
|
2 |
Beaker==1.6. |
|
|
2 | Beaker==1.6.3 | |
|
3 | 3 | WebHelpers>=1.2 |
|
4 | 4 | formencode==1.2.4 |
|
5 | 5 | SQLAlchemy==0.7.4 |
@@ -38,7 +38,7 b" PLATFORM_OTHERS = ('Linux', 'Darwin', 'F" | |||
|
38 | 38 | |
|
39 | 39 | requirements = [ |
|
40 | 40 | "Pylons==1.0.0", |
|
41 |
"Beaker==1.6. |
|
|
41 | "Beaker==1.6.3", | |
|
42 | 42 | "WebHelpers>=1.2", |
|
43 | 43 | "formencode==1.2.4", |
|
44 | 44 | "SQLAlchemy==0.7.4", |
@@ -248,7 +248,7 b' class SettingsController(BaseController)' | |||
|
248 | 248 | |
|
249 | 249 | if update: |
|
250 | 250 | h.flash(_('Updated hooks'), category='success') |
|
251 |
|
|
|
251 | self.sa.commit() | |
|
252 | 252 | except: |
|
253 | 253 | log.error(traceback.format_exc()) |
|
254 | 254 | h.flash(_('error occurred during hook creation'), |
@@ -285,7 +285,7 b' class SettingsController(BaseController)' | |||
|
285 | 285 | if setting_id == 'hooks': |
|
286 | 286 | hook_id = request.POST.get('hook_id') |
|
287 | 287 | RhodeCodeUi.delete(hook_id) |
|
288 | ||
|
288 | self.sa.commit() | |
|
289 | 289 | |
|
290 | 290 | @HasPermissionAllDecorator('hg.admin') |
|
291 | 291 | def show(self, setting_id, format='html'): |
@@ -221,17 +221,20 b' class ChangesetController(BaseRepoContro' | |||
|
221 | 221 | lim = self.cut_off_limit |
|
222 | 222 | if cumulative_diff > self.cut_off_limit: |
|
223 | 223 | lim = -1 |
|
224 |
size, cs1, cs2, diff, st = wrapped_diff( |
|
|
225 |
|
|
|
226 | cut_off_limit=lim, | |
|
227 | ignore_whitespace=ign_whitespace_lcl, | |
|
228 | line_context=line_context_lcl, | |
|
229 | enable_comments=enable_comments) | |
|
224 | size, cs1, cs2, diff, st = wrapped_diff( | |
|
225 | filenode_old=None, | |
|
226 | filenode_new=node, | |
|
227 | cut_off_limit=lim, | |
|
228 | ignore_whitespace=ign_whitespace_lcl, | |
|
229 | line_context=line_context_lcl, | |
|
230 | enable_comments=enable_comments | |
|
231 | ) | |
|
230 | 232 | cumulative_diff += size |
|
231 | 233 | c.lines_added += st[0] |
|
232 | 234 | c.lines_deleted += st[1] |
|
233 |
c.changes[changeset.raw_id].append( |
|
|
234 | cs1, cs2, st)) | |
|
235 | c.changes[changeset.raw_id].append( | |
|
236 | ('added', node, diff, cs1, cs2, st) | |
|
237 | ) | |
|
235 | 238 | |
|
236 | 239 | #================================================================== |
|
237 | 240 | # CHANGED FILES |
@@ -249,24 +252,27 b' class ChangesetController(BaseRepoContro' | |||
|
249 | 252 | lim = self.cut_off_limit |
|
250 | 253 | if cumulative_diff > self.cut_off_limit: |
|
251 | 254 | lim = -1 |
|
252 |
size, cs1, cs2, diff, st = wrapped_diff( |
|
|
253 |
|
|
|
254 | cut_off_limit=lim, | |
|
255 | ignore_whitespace=ign_whitespace_lcl, | |
|
256 | line_context=line_context_lcl, | |
|
257 | enable_comments=enable_comments) | |
|
255 | size, cs1, cs2, diff, st = wrapped_diff( | |
|
256 | filenode_old=filenode_old, | |
|
257 | filenode_new=node, | |
|
258 | cut_off_limit=lim, | |
|
259 | ignore_whitespace=ign_whitespace_lcl, | |
|
260 | line_context=line_context_lcl, | |
|
261 | enable_comments=enable_comments | |
|
262 | ) | |
|
258 | 263 | cumulative_diff += size |
|
259 | 264 | c.lines_added += st[0] |
|
260 | 265 | c.lines_deleted += st[1] |
|
261 |
c.changes[changeset.raw_id].append( |
|
|
262 | cs1, cs2, st)) | |
|
263 | ||
|
266 | c.changes[changeset.raw_id].append( | |
|
267 | ('changed', node, diff, cs1, cs2, st) | |
|
268 | ) | |
|
264 | 269 | #================================================================== |
|
265 | 270 | # REMOVED FILES |
|
266 | 271 | #================================================================== |
|
267 | 272 | for node in changeset.removed: |
|
268 |
c.changes[changeset.raw_id].append( |
|
|
269 |
|
|
|
273 | c.changes[changeset.raw_id].append( | |
|
274 | ('removed', node, None, None, None, (0, 0)) | |
|
275 | ) | |
|
270 | 276 | |
|
271 | 277 | # count inline comments |
|
272 | 278 | for path, lines in c.inline_comments: |
@@ -311,7 +317,7 b' class ChangesetController(BaseRepoContro' | |||
|
311 | 317 | format='gitdiff').raw_diff() |
|
312 | 318 | |
|
313 | 319 | cs1 = None |
|
314 |
cs2 = node. |
|
|
320 | cs2 = node.changeset.raw_id | |
|
315 | 321 | c.changes.append(('added', node, diff, cs1, cs2)) |
|
316 | 322 | |
|
317 | 323 | for node in c.changeset.changed: |
@@ -325,8 +331,8 b' class ChangesetController(BaseRepoContro' | |||
|
325 | 331 | diff = diffs.DiffProcessor(f_gitdiff, |
|
326 | 332 | format='gitdiff').raw_diff() |
|
327 | 333 | |
|
328 |
cs1 = filenode_old. |
|
|
329 |
cs2 = node. |
|
|
334 | cs1 = filenode_old.changeset.raw_id | |
|
335 | cs2 = node.changeset.raw_id | |
|
330 | 336 | c.changes.append(('changed', node, diff, cs1, cs2)) |
|
331 | 337 | |
|
332 | 338 | response.content_type = 'text/plain' |
@@ -335,8 +341,8 b' class ChangesetController(BaseRepoContro' | |||
|
335 | 341 | response.content_disposition = 'attachment; filename=%s.patch' \ |
|
336 | 342 | % revision |
|
337 | 343 | |
|
338 |
c.parent_tmpl = ''.join(['# Parent %s\n' % x.raw_id |
|
|
339 |
|
|
|
344 | c.parent_tmpl = ''.join(['# Parent %s\n' % x.raw_id | |
|
345 | for x in c.changeset.parents]) | |
|
340 | 346 | |
|
341 | 347 | c.diffs = '' |
|
342 | 348 | for x in c.changes: |
@@ -428,8 +428,9 b' class FilesController(BaseRepoController' | |||
|
428 | 428 | |
|
429 | 429 | diff_name = '%s_vs_%s.diff' % (diff1, diff2) |
|
430 | 430 | response.content_type = 'text/plain' |
|
431 |
response.content_disposition = |
|
|
432 | % diff_name | |
|
431 | response.content_disposition = ( | |
|
432 | 'attachment; filename=%s' % diff_name | |
|
433 | ) | |
|
433 | 434 | return diff.raw_diff() |
|
434 | 435 | |
|
435 | 436 | elif c.action == 'raw': |
@@ -83,8 +83,8 b' def wrapped_diff(filenode_old, filenode_' | |||
|
83 | 83 | if not diff: |
|
84 | 84 | diff = wrap_to_table(_('No changes detected')) |
|
85 | 85 | |
|
86 |
cs1 = filenode_old. |
|
|
87 |
cs2 = filenode_new. |
|
|
86 | cs1 = filenode_old.changeset.raw_id | |
|
87 | cs2 = filenode_new.changeset.raw_id | |
|
88 | 88 | |
|
89 | 89 | return size, cs1, cs2, diff, stats |
|
90 | 90 |
@@ -121,6 +121,7 b' class SimpleGit(BaseVCSController):' | |||
|
121 | 121 | #====================================================================== |
|
122 | 122 | # CHECK ANONYMOUS PERMISSION |
|
123 | 123 | #====================================================================== |
|
124 | ||
|
124 | 125 | if action in ['pull', 'push']: |
|
125 | 126 | anonymous_user = self.__get_user('default') |
|
126 | 127 | username = anonymous_user.username |
@@ -169,15 +170,13 b' class SimpleGit(BaseVCSController):' | |||
|
169 | 170 | start_response) |
|
170 | 171 | |
|
171 | 172 | #check permissions for this repository |
|
172 | perm = self._check_permission(action, user, | |
|
173 | repo_name) | |
|
173 | perm = self._check_permission(action, user, repo_name) | |
|
174 | 174 | if perm is not True: |
|
175 | 175 | return HTTPForbidden()(environ, start_response) |
|
176 | 176 | |
|
177 | 177 | #=================================================================== |
|
178 | 178 | # GIT REQUEST HANDLING |
|
179 | 179 | #=================================================================== |
|
180 | ||
|
181 | 180 | repo_path = safe_str(os.path.join(self.basepath, repo_name)) |
|
182 | 181 | log.debug('Repository path is %s' % repo_path) |
|
183 | 182 | |
@@ -203,7 +202,6 b' class SimpleGit(BaseVCSController):' | |||
|
203 | 202 | :param repo_name: name of the repository |
|
204 | 203 | :param repo_path: full path to the repository |
|
205 | 204 | """ |
|
206 | ||
|
207 | 205 | _d = {'/' + repo_name: Repo(repo_path)} |
|
208 | 206 | backend = dulserver.DictBackend(_d) |
|
209 | 207 | gitserve = HTTPGitApplication(backend) |
@@ -229,19 +227,24 b' class SimpleGit(BaseVCSController):' | |||
|
229 | 227 | return User.get_by_username(username) |
|
230 | 228 | |
|
231 | 229 | def __get_action(self, environ): |
|
232 | """Maps git request commands into a pull or push command. | |
|
230 | """ | |
|
231 | Maps git request commands into a pull or push command. | |
|
233 | 232 | |
|
234 | 233 | :param environ: |
|
235 | 234 | """ |
|
236 | 235 | service = environ['QUERY_STRING'].split('=') |
|
236 | ||
|
237 | 237 | if len(service) > 1: |
|
238 | 238 | service_cmd = service[1] |
|
239 | 239 | mapping = { |
|
240 | 240 | 'git-receive-pack': 'push', |
|
241 | 241 | 'git-upload-pack': 'pull', |
|
242 | 242 | } |
|
243 | ||
|
244 | return mapping.get(service_cmd, | |
|
245 | service_cmd if service_cmd else 'other') | |
|
243 | op = mapping[service_cmd] | |
|
244 | self._git_stored_op = op | |
|
245 | return op | |
|
246 | 246 | else: |
|
247 | return 'other' | |
|
247 | # try to fallback to stored variable as we don't know if the last | |
|
248 | # operation is pull/push | |
|
249 | op = getattr(self, '_git_stored_op', 'pull') | |
|
250 | return op |
@@ -247,7 +247,7 b' class GitChangeset(BaseChangeset):' | |||
|
247 | 247 | iterating commits. |
|
248 | 248 | """ |
|
249 | 249 | cmd = 'log --pretty="format: %%H" --name-status -p %s -- "%s"' % ( |
|
250 |
|
|
|
250 | self.id, path | |
|
251 | 251 | ) |
|
252 | 252 | so, se = self.repository.run_git_command(cmd) |
|
253 | 253 | ids = re.findall(r'\w{40}', so) |
@@ -187,9 +187,8 b' class MercurialChangeset(BaseChangeset):' | |||
|
187 | 187 | """ |
|
188 | 188 | Returns last commit of the file at the given ``path``. |
|
189 | 189 | """ |
|
190 |
|
|
|
191 | changeset = self.repository.get_changeset(fctx.linkrev()) | |
|
192 | return changeset | |
|
190 | node = self.get_node(path) | |
|
191 | return node.history[0] | |
|
193 | 192 | |
|
194 | 193 | def get_file_history(self, path): |
|
195 | 194 | """ |
@@ -306,14 +306,14 b' class FileNode(Node):' | |||
|
306 | 306 | attribute to indicate that type should *NOT* be calculated). |
|
307 | 307 | """ |
|
308 | 308 | if hasattr(self, '_mimetype'): |
|
309 | if (isinstance(self._mimetype,(tuple,list,)) and | |
|
309 | if (isinstance(self._mimetype, (tuple, list,)) and | |
|
310 | 310 | len(self._mimetype) == 2): |
|
311 | 311 | return self._mimetype |
|
312 | 312 | else: |
|
313 | 313 | raise NodeError('given _mimetype attribute must be an 2 ' |
|
314 | 314 | 'element list or tuple') |
|
315 | 315 | |
|
316 | mtype,encoding = mimetypes.guess_type(self.name) | |
|
316 | mtype, encoding = mimetypes.guess_type(self.name) | |
|
317 | 317 | |
|
318 | 318 | if mtype is None: |
|
319 | 319 | if self.is_binary: |
@@ -322,7 +322,7 b' class FileNode(Node):' | |||
|
322 | 322 | else: |
|
323 | 323 | mtype = 'text/plain' |
|
324 | 324 | encoding = None |
|
325 | return mtype,encoding | |
|
325 | return mtype, encoding | |
|
326 | 326 | |
|
327 | 327 | @LazyProperty |
|
328 | 328 | def mimetype(self): |
@@ -392,8 +392,8 b' class FileNode(Node):' | |||
|
392 | 392 | """ |
|
393 | 393 | Returns True if file has binary content. |
|
394 | 394 | """ |
|
395 | bin = '\0' in self.content | |
|
396 | return bin | |
|
395 | _bin = '\0' in self.content | |
|
396 | return _bin | |
|
397 | 397 | |
|
398 | 398 | @LazyProperty |
|
399 | 399 | def extension(self): |
@@ -406,6 +406,10 b' class FileNode(Node):' | |||
|
406 | 406 | """ |
|
407 | 407 | return bool(self.mode & stat.S_IXUSR) |
|
408 | 408 | |
|
409 | def __repr__(self): | |
|
410 | return '<%s %r @ %s>' % (self.__class__.__name__, self.path, | |
|
411 | self.changeset.short_id) | |
|
412 | ||
|
409 | 413 | |
|
410 | 414 | class RemovedFileNode(FileNode): |
|
411 | 415 | """ |
@@ -537,6 +541,10 b' class DirNode(Node):' | |||
|
537 | 541 | |
|
538 | 542 | return size |
|
539 | 543 | |
|
544 | def __repr__(self): | |
|
545 | return '<%s %r @ %s>' % (self.__class__.__name__, self.path, | |
|
546 | self.changeset.short_id) | |
|
547 | ||
|
540 | 548 | |
|
541 | 549 | class RootNode(DirNode): |
|
542 | 550 | """ |
@@ -15,17 +15,17 b' from rhodecode.lib.vcs.exceptions import' | |||
|
15 | 15 | from rhodecode.lib.vcs.nodes import FileNode, NodeError |
|
16 | 16 | |
|
17 | 17 | |
|
18 | def get_udiff(filenode_old, filenode_new,show_whitespace=True): | |
|
18 | def get_udiff(filenode_old, filenode_new, show_whitespace=True): | |
|
19 | 19 | """ |
|
20 | 20 | Returns unified diff between given ``filenode_old`` and ``filenode_new``. |
|
21 | 21 | """ |
|
22 | 22 | try: |
|
23 |
filenode_old_date = filenode_old. |
|
|
23 | filenode_old_date = filenode_old.changeset.date | |
|
24 | 24 | except NodeError: |
|
25 | 25 | filenode_old_date = None |
|
26 | 26 | |
|
27 | 27 | try: |
|
28 |
filenode_new_date = filenode_new. |
|
|
28 | filenode_new_date = filenode_new.changeset.date | |
|
29 | 29 | except NodeError: |
|
30 | 30 | filenode_new_date = None |
|
31 | 31 |
@@ -67,7 +67,7 b' class ChangesetCommentsModel(BaseModel):' | |||
|
67 | 67 | repo = Repository.get(repo_id) |
|
68 | 68 | cs = repo.scm_instance.get_changeset(revision) |
|
69 | 69 | desc = cs.message |
|
70 | author = cs.author_email | |
|
70 | author_email = cs.author_email | |
|
71 | 71 | comment = ChangesetComment() |
|
72 | 72 | comment.repo = repo |
|
73 | 73 | comment.user_id = user_id |
@@ -92,22 +92,27 b' class ChangesetCommentsModel(BaseModel):' | |||
|
92 | 92 | ) |
|
93 | 93 | ) |
|
94 | 94 | body = text |
|
95 | ||
|
96 | # get the current participants of this changeset | |
|
95 | 97 | recipients = ChangesetComment.get_users(revision=revision) |
|
96 | # add changeset author | |
|
97 | recipients += [User.get_by_email(author)] | |
|
98 | 98 | |
|
99 | NotificationModel().create(created_by=user_id, subject=subj, | |
|
100 | body=body, recipients=recipients, | |
|
101 | type_=Notification.TYPE_CHANGESET_COMMENT) | |
|
99 | # add changeset author if it's in rhodecode system | |
|
100 | recipients += [User.get_by_email(author_email)] | |
|
101 | ||
|
102 | NotificationModel().create( | |
|
103 | created_by=user_id, subject=subj, body=body, | |
|
104 | recipients=recipients, type_=Notification.TYPE_CHANGESET_COMMENT | |
|
105 | ) | |
|
102 | 106 | |
|
103 | 107 | mention_recipients = set(self._extract_mentions(body))\ |
|
104 | 108 | .difference(recipients) |
|
105 | 109 | if mention_recipients: |
|
106 | 110 | subj = _('[Mention]') + ' ' + subj |
|
107 |
NotificationModel().create( |
|
|
108 | body=body, | |
|
109 |
|
|
|
110 |
|
|
|
111 | NotificationModel().create( | |
|
112 | created_by=user_id, subject=subj, body=body, | |
|
113 | recipients=mention_recipients, | |
|
114 | type_=Notification.TYPE_CHANGESET_COMMENT | |
|
115 | ) | |
|
111 | 116 | |
|
112 | 117 | return comment |
|
113 | 118 |
@@ -807,7 +807,9 b' class RepoGroup(Base, BaseModel):' | |||
|
807 | 807 | |
|
808 | 808 | @property |
|
809 | 809 | def repositories(self): |
|
810 |
return Repository.query() |
|
|
810 | return Repository.query()\ | |
|
811 | .filter(Repository.group == self)\ | |
|
812 | .order_by(Repository.repo_name) | |
|
811 | 813 | |
|
812 | 814 | @property |
|
813 | 815 | def repositories_recursive_count(self): |
@@ -85,13 +85,19 b' class NotificationModel(BaseModel):' | |||
|
85 | 85 | if obj: |
|
86 | 86 | recipients_objs.append(obj) |
|
87 | 87 | recipients_objs = set(recipients_objs) |
|
88 | log.debug('sending notifications %s to %s' % ( | |
|
89 | type_, recipients_objs) | |
|
90 | ) | |
|
88 | 91 | else: |
|
89 | 92 | # empty recipients means to all admins |
|
90 | 93 | recipients_objs = User.query().filter(User.admin == True).all() |
|
91 | ||
|
92 | notif = Notification.create(created_by=created_by_obj, subject=subject, | |
|
93 | body=body, recipients=recipients_objs, | |
|
94 | type_=type_) | |
|
94 | log.debug('sending notifications %s to admins: %s' % ( | |
|
95 | type_, recipients_objs) | |
|
96 | ) | |
|
97 | notif = Notification.create( | |
|
98 | created_by=created_by_obj, subject=subject, | |
|
99 | body=body, recipients=recipients_objs, type_=type_ | |
|
100 | ) | |
|
95 | 101 | |
|
96 | 102 | if with_email is False: |
|
97 | 103 | return notif |
@@ -163,10 +169,12 b' class NotificationModel(BaseModel):' | |||
|
163 | 169 | of notification object |
|
164 | 170 | """ |
|
165 | 171 | |
|
166 | _map = {notification.TYPE_CHANGESET_COMMENT:_('commented on commit'), | |
|
167 |
|
|
|
168 |
|
|
|
169 |
|
|
|
172 | _map = { | |
|
173 | notification.TYPE_CHANGESET_COMMENT: _('commented on commit'), | |
|
174 | notification.TYPE_MESSAGE: _('sent message'), | |
|
175 | notification.TYPE_MENTION: _('mentioned you'), | |
|
176 | notification.TYPE_REGISTRATION: _('registered in RhodeCode') | |
|
177 | } | |
|
170 | 178 | |
|
171 | 179 | DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S" |
|
172 | 180 | |
@@ -176,9 +184,10 b' class NotificationModel(BaseModel):' | |||
|
176 | 184 | else: |
|
177 | 185 | DTF = lambda d: datetime.datetime.strftime(d, DATETIME_FORMAT) |
|
178 | 186 | when = DTF(notification.created_on) |
|
179 | data = dict(user=notification.created_by_user.username, | |
|
180 | action=_map[notification.type_], | |
|
181 | when=when) | |
|
187 | data = dict( | |
|
188 | user=notification.created_by_user.username, | |
|
189 | action=_map[notification.type_], when=when, | |
|
190 | ) | |
|
182 | 191 | return tmpl % data |
|
183 | 192 | |
|
184 | 193 | |
@@ -194,10 +203,10 b' class EmailNotificationModel(BaseModel):' | |||
|
194 | 203 | self._tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup |
|
195 | 204 | |
|
196 | 205 | self.email_types = { |
|
197 |
|
|
|
198 |
|
|
|
199 |
|
|
|
200 |
|
|
|
206 | self.TYPE_CHANGESET_COMMENT: 'email_templates/changeset_comment.html', | |
|
207 | self.TYPE_PASSWORD_RESET: 'email_templates/password_reset.html', | |
|
208 | self.TYPE_REGISTRATION: 'email_templates/registration.html', | |
|
209 | self.TYPE_DEFAULT: 'email_templates/default.html' | |
|
201 | 210 | } |
|
202 | 211 | |
|
203 | 212 | def get_email_tmpl(self, type_, **kwargs): |
@@ -210,7 +219,7 b' class EmailNotificationModel(BaseModel):' | |||
|
210 | 219 | base = self.email_types.get(type_, self.email_types[self.TYPE_DEFAULT]) |
|
211 | 220 | email_template = self._tmpl_lookup.get_template(base) |
|
212 | 221 | # translator inject |
|
213 | _kwargs = {'_':_} | |
|
222 | _kwargs = {'_': _} | |
|
214 | 223 | _kwargs.update(kwargs) |
|
215 | 224 | log.debug('rendering tmpl %s with kwargs %s' % (base, _kwargs)) |
|
216 | 225 | return email_template.render(**_kwargs) |
@@ -531,6 +531,13 b' class UserModel(BaseModel):' | |||
|
531 | 531 | """ |
|
532 | 532 | user = self.__get_user(user) |
|
533 | 533 | perm = self.__get_perm(perm) |
|
534 | # if this permission is already granted skip it | |
|
535 | _perm = UserToPerm.query()\ | |
|
536 | .filter(UserToPerm.user == user)\ | |
|
537 | .filter(UserToPerm.permission == perm)\ | |
|
538 | .scalar() | |
|
539 | if _perm: | |
|
540 | return | |
|
534 | 541 | new = UserToPerm() |
|
535 | 542 | new.user = user |
|
536 | 543 | new.permission = perm |
@@ -546,7 +553,9 b' class UserModel(BaseModel):' | |||
|
546 | 553 | user = self.__get_user(user) |
|
547 | 554 | perm = self.__get_perm(perm) |
|
548 | 555 | |
|
549 |
obj = UserToPerm.query() |
|
|
550 |
.filter(UserToPerm. |
|
|
556 | obj = UserToPerm.query()\ | |
|
557 | .filter(UserToPerm.user == user)\ | |
|
558 | .filter(UserToPerm.permission == perm)\ | |
|
559 | .scalar() | |
|
551 | 560 | if obj: |
|
552 | 561 | self.sa.delete(obj) |
@@ -172,6 +172,14 b' class UsersGroupModel(BaseModel):' | |||
|
172 | 172 | |
|
173 | 173 | users_group = self.__get_users_group(users_group) |
|
174 | 174 | |
|
175 | # if this permission is already granted skip it | |
|
176 | _perm = UsersGroupToPerm.query()\ | |
|
177 | .filter(UsersGroupToPerm.users_group == users_group)\ | |
|
178 | .filter(UsersGroupToPerm.permission == perm)\ | |
|
179 | .scalar() | |
|
180 | if _perm: | |
|
181 | return | |
|
182 | ||
|
175 | 183 | new = UsersGroupToPerm() |
|
176 | 184 | new.users_group = users_group |
|
177 | 185 | new.permission = perm |
@@ -613,16 +613,20 b' var deleteNotification = function(url, n' | |||
|
613 | 613 | * QUICK REPO MENU |
|
614 | 614 | */ |
|
615 | 615 | var quick_repo_menu = function(){ |
|
616 |
YUE.on(YUQ('.quick_repo_menu'),' |
|
|
617 | var menu = e.currentTarget.firstElementChild.firstElementChild; | |
|
618 | if(YUD.hasClass(menu,'hidden')){ | |
|
619 |
YUD. |
|
|
620 |
YUD.re |
|
|
621 |
} |
|
|
622 | YUD.removeClass(e.currentTarget,'active'); | |
|
623 | YUD.addClass(menu,'hidden'); | |
|
624 | } | |
|
625 | }) | |
|
616 | YUE.on(YUQ('.quick_repo_menu'),'mouseenter',function(e){ | |
|
617 | var menu = e.currentTarget.firstElementChild.firstElementChild; | |
|
618 | if(YUD.hasClass(menu,'hidden')){ | |
|
619 | YUD.replaceClass(e.currentTarget,'hidden', 'active'); | |
|
620 | YUD.replaceClass(menu, 'hidden', 'active'); | |
|
621 | } | |
|
622 | }) | |
|
623 | YUE.on(YUQ('.quick_repo_menu'),'mouseleave',function(e){ | |
|
624 | var menu = e.currentTarget.firstElementChild.firstElementChild; | |
|
625 | if(YUD.hasClass(menu,'active')){ | |
|
626 | YUD.replaceClass(e.currentTarget, 'active', 'hidden'); | |
|
627 | YUD.replaceClass(menu, 'active', 'hidden'); | |
|
628 | } | |
|
629 | }) | |
|
626 | 630 | }; |
|
627 | 631 | |
|
628 | 632 |
@@ -1,8 +1,9 b'' | |||
|
1 | %if h.is_hg(c.scm_type): | |
|
1 | 2 | # ${c.scm_type.upper()} changeset patch |
|
2 | 3 | # User ${c.changeset.author|n} |
|
3 | 4 | # Date ${c.changeset.date} |
|
4 | 5 | # Node ID ${c.changeset.raw_id} |
|
5 | 6 | ${c.parent_tmpl} |
|
6 | 7 | ${c.changeset.message} |
|
7 | ||
|
8 | %endif | |
|
8 | 9 | ${c.diffs|n} |
@@ -34,8 +34,8 b'' | |||
|
34 | 34 | <dd> |
|
35 | 35 | <div> |
|
36 | 36 | ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')} |
|
37 |
${h.hidden('diff2',c.file. |
|
|
38 |
${h.select('diff1',c.file. |
|
|
37 | ${h.hidden('diff2',c.file.changeset.raw_id)} | |
|
38 | ${h.select('diff1',c.file.changeset.raw_id,c.file_history)} | |
|
39 | 39 | ${h.submit('diff','diff to revision',class_="ui-btn")} |
|
40 | 40 | ${h.submit('show_rev','show at revision',class_="ui-btn")} |
|
41 | 41 | ${h.end_form()} |
@@ -46,7 +46,7 b'' | |||
|
46 | 46 | <div class="code-header"> |
|
47 | 47 | <div class="stats"> |
|
48 | 48 | <div class="left"><img src="${h.url('/images/icons/file.png')}"/></div> |
|
49 |
<div class="left item">${h.link_to("r%s:%s" % (c.file. |
|
|
49 | <div class="left item">${h.link_to("r%s:%s" % (c.file.changeset.revision,h.short_id(c.file.changeset.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id))}</div> | |
|
50 | 50 | <div class="left item">${h.format_byte_size(c.file.size,binary=True)}</div> |
|
51 | 51 | <div class="left item last">${c.file.mimetype}</div> |
|
52 | 52 | <div class="buttons"> |
@@ -47,7 +47,7 b'' | |||
|
47 | 47 | <th>${_('Name')}</th> |
|
48 | 48 | <th>${_('Size')}</th> |
|
49 | 49 | <th>${_('Mimetype')}</th> |
|
50 | <th>${_('Revision')}</th> | |
|
50 | <th>${_('Last Revision')}</th> | |
|
51 | 51 | <th>${_('Last modified')}</th> |
|
52 | 52 | <th>${_('Last commiter')}</th> |
|
53 | 53 | </tr> |
@@ -70,7 +70,7 b'' | |||
|
70 | 70 | %for cnt,node in enumerate(c.file): |
|
71 | 71 | <tr class="parity${cnt%2}"> |
|
72 | 72 | <td> |
|
73 |
|
|
|
73 | ${h.link_to(node.name,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=h.safe_unicode(node.path)),class_=file_class(node)+" ypjax-link")} | |
|
74 | 74 | </td> |
|
75 | 75 | <td> |
|
76 | 76 | %if node.is_file(): |
@@ -42,7 +42,7 b'' | |||
|
42 | 42 | <div class="code-header"> |
|
43 | 43 | <div class="stats"> |
|
44 | 44 | <div class="left"><img src="${h.url('/images/icons/file.png')}"/></div> |
|
45 |
<div class="left item">${h.link_to("r%s:%s" % (c.file. |
|
|
45 | <div class="left item">${h.link_to("r%s:%s" % (c.file.changeset.revision,h.short_id(c.file.changeset.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id))}</div> | |
|
46 | 46 | <div class="left item">${h.format_byte_size(c.file.size,binary=True)}</div> |
|
47 | 47 | <div class="left item last">${c.file.mimetype}</div> |
|
48 | 48 | <div class="buttons"> |
@@ -3,8 +3,8 b'' | |||
|
3 | 3 | <dd> |
|
4 | 4 | <div> |
|
5 | 5 | ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')} |
|
6 |
${h.hidden('diff2',c.file. |
|
|
7 |
${h.select('diff1',c.file. |
|
|
6 | ${h.hidden('diff2',c.file.changeset.raw_id)} | |
|
7 | ${h.select('diff1',c.file.changeset.raw_id,c.file_history)} | |
|
8 | 8 | ${h.submit('diff','diff to revision',class_="ui-btn")} |
|
9 | 9 | ${h.submit('show_rev','show at revision',class_="ui-btn")} |
|
10 | 10 | ${h.end_form()} |
@@ -16,27 +16,27 b'' | |||
|
16 | 16 | <div class="code-header"> |
|
17 | 17 | <div class="stats"> |
|
18 | 18 | <div class="left img"><img src="${h.url('/images/icons/file.png')}"/></div> |
|
19 |
<div class="left item"><pre>${h.link_to("r%s:%s" % (c.file. |
|
|
19 | <div class="left item"><pre>${h.link_to("r%s:%s" % (c.file.changeset.revision,h.short_id(c.file.changeset.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id))}</pre></div> | |
|
20 | 20 | <div class="left item"><pre>${h.format_byte_size(c.file.size,binary=True)}</pre></div> |
|
21 | 21 | <div class="left item last"><pre>${c.file.mimetype}</pre></div> |
|
22 | 22 | <div class="buttons"> |
|
23 |
${h.link_to(_('show annotation'),h.url('files_annotate_home',repo_name=c.repo_name,revision=c.file. |
|
|
24 |
${h.link_to(_('show as raw'),h.url('files_raw_home',repo_name=c.repo_name,revision=c.file. |
|
|
25 |
${h.link_to(_('download as raw'),h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.file. |
|
|
23 | ${h.link_to(_('show annotation'),h.url('files_annotate_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")} | |
|
24 | ${h.link_to(_('show as raw'),h.url('files_raw_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")} | |
|
25 | ${h.link_to(_('download as raw'),h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")} | |
|
26 | 26 | % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name): |
|
27 | 27 | % if not c.file.is_binary: |
|
28 |
${h.link_to(_('edit'),h.url('files_edit_home',repo_name=c.repo_name,revision=c.file. |
|
|
28 | ${h.link_to(_('edit'),h.url('files_edit_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")} | |
|
29 | 29 | % endif |
|
30 | 30 | % endif |
|
31 | 31 | </div> |
|
32 | 32 | </div> |
|
33 | 33 | <div class="author"> |
|
34 | 34 | <div class="gravatar"> |
|
35 |
<img alt="gravatar" src="${h.gravatar_url(h.email(c.file. |
|
|
35 | <img alt="gravatar" src="${h.gravatar_url(h.email(c.file.changeset.author),16)}"/> | |
|
36 | 36 | </div> |
|
37 |
<div title="${c.file. |
|
|
37 | <div title="${c.file.changeset.author}" class="user">${h.person(c.file.changeset.author)}</div> | |
|
38 | 38 | </div> |
|
39 |
<div class="commit">${h.urlify_commit(c.file. |
|
|
39 | <div class="commit">${h.urlify_commit(c.file.changeset.message,c.repo_name)}</div> | |
|
40 | 40 | </div> |
|
41 | 41 | <div class="code-body"> |
|
42 | 42 | %if c.file.is_binary: |
@@ -46,7 +46,7 b'' | |||
|
46 | 46 | ${h.pygmentize(c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")} |
|
47 | 47 | %else: |
|
48 | 48 | ${_('File is too big to display')} ${h.link_to(_('show as raw'), |
|
49 |
h.url('files_raw_home',repo_name=c.repo_name,revision=c.file. |
|
|
49 | h.url('files_raw_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path))} | |
|
50 | 50 | %endif |
|
51 | 51 | <script type="text/javascript"> |
|
52 | 52 | function highlight_lines(lines){ |
@@ -75,7 +75,7 b' class TestFilesController(TestController' | |||
|
75 | 75 | |
|
76 | 76 | #test or history |
|
77 | 77 | response.mustcontain("""<optgroup label="Changesets"> |
|
78 |
<option |
|
|
78 | <option value="8911406ad776fdd3d0b9932a2e89677e57405a48">r167:8911406ad776 (default)</option> | |
|
79 | 79 | <option value="aa957ed78c35a1541f508d2ec90e501b0a9e3167">r165:aa957ed78c35 (default)</option> |
|
80 | 80 | <option value="48e11b73e94c0db33e736eaeea692f990cb0b5f1">r140:48e11b73e94c (default)</option> |
|
81 | 81 | <option value="adf3cbf483298563b968a6c673cd5bde5f7d5eea">r126:adf3cbf48329 (default)</option> |
@@ -110,23 +110,20 b' class TestFilesController(TestController' | |||
|
110 | 110 | <option value="3803844fdbd3b711175fc3da9bdacfcd6d29a6fb">r7:3803844fdbd3 (default)</option> |
|
111 | 111 | </optgroup> |
|
112 | 112 | <optgroup label="Branches"> |
|
113 | <option value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">default</option> | |
|
113 | <option selected="selected" value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">default</option> | |
|
114 | 114 | <option value="97e8b885c04894463c51898e14387d80c30ed1ee">git</option> |
|
115 | 115 | <option value="2e6a2bf9356ca56df08807f4ad86d480da72a8f4">web</option> |
|
116 | 116 | </optgroup> |
|
117 | 117 | <optgroup label="Tags"> |
|
118 | <option value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">tip</option> | |
|
118 | <option selected="selected" value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">tip</option> | |
|
119 | 119 | <option value="fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200">0.1.4</option> |
|
120 | 120 | <option value="17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">0.1.3</option> |
|
121 | 121 | <option value="a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720">0.1.2</option> |
|
122 | 122 | <option value="eb3a60fc964309c1a318b8dfe26aa2d1586c85ae">0.1.1</option> |
|
123 |
</optgroup> |
|
|
123 | </optgroup> | |
|
124 | """) | |
|
124 | 125 | |
|
125 | response.mustcontain("""<div class="commit">Partially implemented #16. filecontent/commit message/author/node name are safe_unicode now. | |
|
126 | In addition some other __str__ are unicode as well | |
|
127 | Added test for unicode | |
|
128 | Improved test to clone into uniq repository. | |
|
129 | removed extra unicode conversion in diff.</div>""") | |
|
126 | response.mustcontain("""<div class="commit">merge</div>""") | |
|
130 | 127 | |
|
131 | 128 | response.mustcontain("""<span style="text-transform: uppercase;"><a href="#">branch: default</a></span>""") |
|
132 | 129 | |
@@ -139,7 +136,7 b' removed extra unicode conversion in diff' | |||
|
139 | 136 | |
|
140 | 137 | |
|
141 | 138 | response.mustcontain("""<optgroup label="Changesets"> |
|
142 |
<option |
|
|
139 | <option value="8911406ad776fdd3d0b9932a2e89677e57405a48">r167:8911406ad776 (default)</option> | |
|
143 | 140 | <option value="aa957ed78c35a1541f508d2ec90e501b0a9e3167">r165:aa957ed78c35 (default)</option> |
|
144 | 141 | <option value="48e11b73e94c0db33e736eaeea692f990cb0b5f1">r140:48e11b73e94c (default)</option> |
|
145 | 142 | <option value="adf3cbf483298563b968a6c673cd5bde5f7d5eea">r126:adf3cbf48329 (default)</option> |
@@ -174,18 +171,17 b' removed extra unicode conversion in diff' | |||
|
174 | 171 | <option value="3803844fdbd3b711175fc3da9bdacfcd6d29a6fb">r7:3803844fdbd3 (default)</option> |
|
175 | 172 | </optgroup> |
|
176 | 173 | <optgroup label="Branches"> |
|
177 | <option value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">default</option> | |
|
174 | <option selected="selected" value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">default</option> | |
|
178 | 175 | <option value="97e8b885c04894463c51898e14387d80c30ed1ee">git</option> |
|
179 | 176 | <option value="2e6a2bf9356ca56df08807f4ad86d480da72a8f4">web</option> |
|
180 | 177 | </optgroup> |
|
181 | 178 | <optgroup label="Tags"> |
|
182 | <option value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">tip</option> | |
|
179 | <option selected="selected" value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">tip</option> | |
|
183 | 180 | <option value="fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200">0.1.4</option> |
|
184 | 181 | <option value="17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">0.1.3</option> |
|
185 | 182 | <option value="a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720">0.1.2</option> |
|
186 | 183 | <option value="eb3a60fc964309c1a318b8dfe26aa2d1586c85ae">0.1.1</option> |
|
187 | </optgroup> | |
|
188 | """) | |
|
184 | </optgroup>""") | |
|
189 | 185 | |
|
190 | 186 | response.mustcontain("""<span style="text-transform: uppercase;"><a href="#">branch: default</a></span>""") |
|
191 | 187 |
General Comments 0
You need to be logged in to leave comments.
Login now