Files
@ b1d6478d4561
Branch filter:
Location: kallithea/rhodecode/lib/helpers.py - annotation
b1d6478d4561
21.4 KiB
text/x-python
added repo creation filesystem test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 | 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 49eb69d78988 49eb69d78988 63c91390853c 1e757ac98988 1e757ac98988 4f834b0abcd3 1e757ac98988 1e757ac98988 4f834b0abcd3 4f834b0abcd3 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 fd63782c4426 1e757ac98988 4cd0709b6d4b 4cd0709b6d4b 4cd0709b6d4b 4cd0709b6d4b d65843e07d3c d65843e07d3c 4cd0709b6d4b 4cd0709b6d4b 4cd0709b6d4b 4cd0709b6d4b 4cd0709b6d4b 4cd0709b6d4b 4cd0709b6d4b 49eb69d78988 49eb69d78988 49eb69d78988 49eb69d78988 49eb69d78988 49eb69d78988 49eb69d78988 49eb69d78988 49eb69d78988 49eb69d78988 49eb69d78988 49eb69d78988 49eb69d78988 49eb69d78988 49eb69d78988 49eb69d78988 49eb69d78988 1e757ac98988 d65843e07d3c d65843e07d3c d65843e07d3c d65843e07d3c d65843e07d3c d65843e07d3c 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 05528ad948c4 1e757ac98988 1294f2baf2bc 1294f2baf2bc 1294f2baf2bc 5cc96df705b9 1e757ac98988 05528ad948c4 1e757ac98988 1e757ac98988 05528ad948c4 1e757ac98988 82aaf4e71817 82aaf4e71817 82aaf4e71817 1e757ac98988 05528ad948c4 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 82aaf4e71817 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 82aaf4e71817 82aaf4e71817 82aaf4e71817 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 82aaf4e71817 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 82aaf4e71817 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 05528ad948c4 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 05528ad948c4 1e757ac98988 129eb072b8a8 129eb072b8a8 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 9279dfedcf93 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 9279dfedcf93 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 d65843e07d3c 1e757ac98988 63c91390853c 63c91390853c 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 9279dfedcf93 1e757ac98988 63c91390853c 1e757ac98988 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 63c91390853c 1e757ac98988 d65843e07d3c d65843e07d3c 5cc96df705b9 1e757ac98988 d65843e07d3c 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 d65843e07d3c d65843e07d3c 5cc96df705b9 1e757ac98988 05528ad948c4 1e757ac98988 99850ac883d1 99850ac883d1 99850ac883d1 99850ac883d1 99850ac883d1 05528ad948c4 1e757ac98988 1e757ac98988 1e757ac98988 99850ac883d1 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 05528ad948c4 1e757ac98988 1e757ac98988 05528ad948c4 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 05528ad948c4 1e757ac98988 1e757ac98988 05528ad948c4 05528ad948c4 1e757ac98988 1e757ac98988 1e757ac98988 373ee7031003 373ee7031003 1e757ac98988 1e757ac98988 1e757ac98988 ffd07396d315 ffd07396d315 1e757ac98988 82aaf4e71817 1e757ac98988 05528ad948c4 1e757ac98988 05528ad948c4 1e757ac98988 05528ad948c4 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 05528ad948c4 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1951c35483ab 1951c35483ab 1951c35483ab 1951c35483ab 1e757ac98988 1e757ac98988 1e757ac98988 fd63782c4426 1e757ac98988 fd63782c4426 1e757ac98988 fd63782c4426 fd63782c4426 fd63782c4426 fd63782c4426 df61378032f3 9dc1d92d82ed 9dc1d92d82ed 1e757ac98988 fd63782c4426 9dc1d92d82ed fd63782c4426 4a3291628f09 4a3291628f09 4a3291628f09 4a3291628f09 4a3291628f09 fd63782c4426 fd63782c4426 fd63782c4426 fd63782c4426 fd63782c4426 fd63782c4426 4a3291628f09 dff6d5cb8bba fd63782c4426 fd63782c4426 dff6d5cb8bba dff6d5cb8bba fd63782c4426 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 ffd07396d315 1e757ac98988 df61378032f3 131c1e335fa7 d65843e07d3c 131c1e335fa7 d65843e07d3c 131c1e335fa7 131c1e335fa7 131c1e335fa7 131c1e335fa7 e002951ba66d 131c1e335fa7 131c1e335fa7 e002951ba66d 131c1e335fa7 131c1e335fa7 131c1e335fa7 131c1e335fa7 df61378032f3 d65843e07d3c df61378032f3 df61378032f3 d65843e07d3c df61378032f3 d65843e07d3c df61378032f3 ee6f345736a6 df61378032f3 df61378032f3 df61378032f3 df61378032f3 df61378032f3 df61378032f3 7df3855bf6c7 def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c d65843e07d3c def3578dac8c def3578dac8c d65843e07d3c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c eafe5ae429ea eafe5ae429ea eafe5ae429ea eafe5ae429ea eafe5ae429ea eafe5ae429ea eafe5ae429ea eafe5ae429ea eafe5ae429ea eafe5ae429ea eafe5ae429ea def3578dac8c def3578dac8c def3578dac8c d14723711d17 def3578dac8c def3578dac8c def3578dac8c def3578dac8c 1af15d66838f def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c 22c147726ea6 22c147726ea6 def3578dac8c 49eb69d78988 7df3855bf6c7 def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c dbec976d9975 df61378032f3 5c87d5ad1b5e def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c def3578dac8c 1af15d66838f 1af15d66838f 1af15d66838f 1af15d66838f 1af15d66838f 1af15d66838f 1af15d66838f 1af15d66838f 1af15d66838f 09e58532d4f7 1af15d66838f 1af15d66838f 1af15d66838f 1af15d66838f 1af15d66838f d65843e07d3c 1af15d66838f 1af15d66838f 1af15d66838f 1af15d66838f 1af15d66838f 1af15d66838f 1af15d66838f 09e58532d4f7 df61378032f3 df61378032f3 fd63782c4426 1e757ac98988 fd63782c4426 1e757ac98988 1e757ac98988 1e757ac98988 fd63782c4426 1e757ac98988 fd63782c4426 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 f12cd4707301 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 05528ad948c4 05528ad948c4 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 05528ad948c4 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 1e757ac98988 05528ad948c4 1e757ac98988 7a1df0130533 7a1df0130533 7a1df0130533 7a1df0130533 7a1df0130533 7a1df0130533 7a1df0130533 7a1df0130533 7a1df0130533 7a1df0130533 | """Helper functions
Consists of functions to typically be used within templates, but also
available to Controllers. This module is available to both as 'h'.
"""
import random
import hashlib
import StringIO
from pygments.formatters import HtmlFormatter
from pygments import highlight as code_highlight
from pylons import url
from pylons.i18n.translation import _, ungettext
from vcs.utils.annotate import annotate_highlight
from rhodecode.lib.utils import repo_name_slug
from webhelpers.html import literal, HTML, escape
from webhelpers.html.tools import *
from webhelpers.html.builder import make_tag
from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
password, textarea, title, ul, xml_declaration, radio
from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
mail_to, strip_links, strip_tags, tag_re
from webhelpers.number import format_byte_size, format_bit_size
from webhelpers.pylonslib import Flash as _Flash
from webhelpers.pylonslib.secure_form import secure_form
from webhelpers.text import chop_at, collapse, convert_accented_entities, \
convert_misc_entities, lchop, plural, rchop, remove_formatting, \
replace_whitespace, urlify, truncate, wrap_paragraphs
from webhelpers.date import time_ago_in_words
from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
convert_boolean_attrs, NotGiven
def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
"""Reset button
"""
_set_input_attrs(attrs, type, name, value)
_set_id_attr(attrs, id, name)
convert_boolean_attrs(attrs, ["disabled"])
return HTML.input(**attrs)
reset = _reset
def get_token():
"""Return the current authentication token, creating one if one doesn't
already exist.
"""
token_key = "_authentication_token"
from pylons import session
if not token_key in session:
try:
token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
except AttributeError: # Python < 2.4
token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
session[token_key] = token
if hasattr(session, 'save'):
session.save()
return session[token_key]
class _GetError(object):
"""Get error from form_errors, and represent it as span wrapped error
message
:param field_name: field to fetch errors for
:param form_errors: form errors dict
"""
def __call__(self, field_name, form_errors):
tmpl = """<span class="error_msg">%s</span>"""
if form_errors and form_errors.has_key(field_name):
return literal(tmpl % form_errors.get(field_name))
get_error = _GetError()
class _ToolTip(object):
def __call__(self, tooltip_title, trim_at=50):
"""Special function just to wrap our text into nice formatted
autowrapped text
:param tooltip_title:
"""
return wrap_paragraphs(escape(tooltip_title), trim_at)\
.replace('\n', '<br/>')
def activate(self):
"""Adds tooltip mechanism to the given Html all tooltips have to have
set class `tooltip` and set attribute `tooltip_title`.
Then a tooltip will be generated based on that. All with yui js tooltip
"""
js = '''
YAHOO.util.Event.onDOMReady(function(){
function toolTipsId(){
var ids = [];
var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
for (var i = 0; i < tts.length; i++) {
//if element doesn't not have and id autogenerate one for tooltip
if (!tts[i].id){
tts[i].id='tt'+i*100;
}
ids.push(tts[i].id);
}
return ids
};
var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
context: toolTipsId(),
monitorresize:false,
xyoffset :[0,0],
autodismissdelay:300000,
hidedelay:5,
showdelay:20,
});
// Set the text for the tooltip just before we display it. Lazy method
myToolTips.contextTriggerEvent.subscribe(
function(type, args) {
var context = args[0];
//positioning of tooltip
var tt_w = this.element.clientWidth;//tooltip width
var tt_h = this.element.clientHeight;//tooltip height
var context_w = context.offsetWidth;
var context_h = context.offsetHeight;
var pos_x = YAHOO.util.Dom.getX(context);
var pos_y = YAHOO.util.Dom.getY(context);
var display_strategy = 'right';
var xy_pos = [0,0];
switch (display_strategy){
case 'top':
var cur_x = (pos_x+context_w/2)-(tt_w/2);
var cur_y = (pos_y-tt_h-4);
xy_pos = [cur_x,cur_y];
break;
case 'bottom':
var cur_x = (pos_x+context_w/2)-(tt_w/2);
var cur_y = pos_y+context_h+4;
xy_pos = [cur_x,cur_y];
break;
case 'left':
var cur_x = (pos_x-tt_w-4);
var cur_y = pos_y-((tt_h/2)-context_h/2);
xy_pos = [cur_x,cur_y];
break;
case 'right':
var cur_x = (pos_x+context_w+4);
var cur_y = pos_y-((tt_h/2)-context_h/2);
xy_pos = [cur_x,cur_y];
break;
default:
var cur_x = (pos_x+context_w/2)-(tt_w/2);
var cur_y = pos_y-tt_h-4;
xy_pos = [cur_x,cur_y];
break;
}
this.cfg.setProperty("xy",xy_pos);
});
//Mouse out
myToolTips.contextMouseOutEvent.subscribe(
function(type, args) {
var context = args[0];
});
});
'''
return literal(js)
tooltip = _ToolTip()
class _FilesBreadCrumbs(object):
def __call__(self, repo_name, rev, paths):
if isinstance(paths, str):
paths = paths.decode('utf-8')
url_l = [link_to(repo_name, url('files_home',
repo_name=repo_name,
revision=rev, f_path=''))]
paths_l = paths.split('/')
for cnt, p in enumerate(paths_l):
if p != '':
url_l.append(link_to(p, url('files_home',
repo_name=repo_name,
revision=rev,
f_path='/'.join(paths_l[:cnt + 1]))))
return literal('/'.join(url_l))
files_breadcrumbs = _FilesBreadCrumbs()
class CodeHtmlFormatter(HtmlFormatter):
"""My code Html Formatter for source codes
"""
def wrap(self, source, outfile):
return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
def _wrap_code(self, source):
for cnt, it in enumerate(source):
i, t = it
t = '<div id="L%s">%s</div>' % (cnt + 1, t)
yield i, t
def _wrap_tablelinenos(self, inner):
dummyoutfile = StringIO.StringIO()
lncount = 0
for t, line in inner:
if t:
lncount += 1
dummyoutfile.write(line)
fl = self.linenostart
mw = len(str(lncount + fl - 1))
sp = self.linenospecial
st = self.linenostep
la = self.lineanchors
aln = self.anchorlinenos
nocls = self.noclasses
if sp:
lines = []
for i in range(fl, fl + lncount):
if i % st == 0:
if i % sp == 0:
if aln:
lines.append('<a href="#%s%d" class="special">%*d</a>' %
(la, i, mw, i))
else:
lines.append('<span class="special">%*d</span>' % (mw, i))
else:
if aln:
lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
else:
lines.append('%*d' % (mw, i))
else:
lines.append('')
ls = '\n'.join(lines)
else:
lines = []
for i in range(fl, fl + lncount):
if i % st == 0:
if aln:
lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
else:
lines.append('%*d' % (mw, i))
else:
lines.append('')
ls = '\n'.join(lines)
# in case you wonder about the seemingly redundant <div> here: since the
# content in the other cell also is wrapped in a div, some browsers in
# some configurations seem to mess up the formatting...
if nocls:
yield 0, ('<table class="%stable">' % self.cssclass +
'<tr><td><div class="linenodiv" '
'style="background-color: #f0f0f0; padding-right: 10px">'
'<pre style="line-height: 125%">' +
ls + '</pre></div></td><td class="code">')
else:
yield 0, ('<table class="%stable">' % self.cssclass +
'<tr><td class="linenos"><div class="linenodiv"><pre>' +
ls + '</pre></div></td><td class="code">')
yield 0, dummyoutfile.getvalue()
yield 0, '</td></tr></table>'
def pygmentize(filenode, **kwargs):
"""pygmentize function using pygments
:param filenode:
"""
return literal(code_highlight(filenode.content,
filenode.lexer, CodeHtmlFormatter(**kwargs)))
def pygmentize_annotation(filenode, **kwargs):
"""pygmentize function for annotation
:param filenode:
"""
color_dict = {}
def gen_color(n=10000):
"""generator for getting n of evenly distributed colors using
hsv color and golden ratio. It always return same order of colors
:returns: RGB tuple
"""
import colorsys
golden_ratio = 0.618033988749895
h = 0.22717784590367374
for c in xrange(n):
h += golden_ratio
h %= 1
HSV_tuple = [h, 0.95, 0.95]
RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
yield map(lambda x:str(int(x * 256)), RGB_tuple)
cgenerator = gen_color()
def get_color_string(cs):
if color_dict.has_key(cs):
col = color_dict[cs]
else:
col = color_dict[cs] = cgenerator.next()
return "color: rgb(%s)! important;" % (', '.join(col))
def url_func(changeset):
tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
" %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
tooltip_html = tooltip_html % (changeset.author,
changeset.date,
tooltip(changeset.message))
lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
short_id(changeset.raw_id))
uri = link_to(
lnk_format,
url('changeset_home', repo_name=changeset.repository.name,
revision=changeset.raw_id),
style=get_color_string(changeset.raw_id),
class_='tooltip',
title=tooltip_html
)
uri += '\n'
return uri
return literal(annotate_highlight(filenode, url_func, **kwargs))
def get_changeset_safe(repo, rev):
from vcs.backends.base import BaseRepository
from vcs.exceptions import RepositoryError
if not isinstance(repo, BaseRepository):
raise Exception('You must pass an Repository '
'object as first argument got %s', type(repo))
try:
cs = repo.get_changeset(rev)
except RepositoryError:
from rhodecode.lib.utils import EmptyChangeset
cs = EmptyChangeset()
return cs
def is_following_repo(repo_name, user_id):
from rhodecode.model.scm import ScmModel
return ScmModel().is_following_repo(repo_name, user_id)
flash = _Flash()
#==============================================================================
# MERCURIAL FILTERS available via h.
#==============================================================================
from mercurial import util
from mercurial.templatefilters import person as _person
def _age(curdate):
"""turns a datetime into an age string."""
if not curdate:
return ''
from datetime import timedelta, datetime
agescales = [("year", 3600 * 24 * 365),
("month", 3600 * 24 * 30),
("day", 3600 * 24),
("hour", 3600),
("minute", 60),
("second", 1), ]
age = datetime.now() - curdate
age_seconds = (age.days * agescales[2][1]) + age.seconds
pos = 1
for scale in agescales:
if scale[1] <= age_seconds:
if pos == 6:pos = 5
return time_ago_in_words(curdate, agescales[pos][0]) + ' ' + _('ago')
pos += 1
return _('just now')
age = lambda x:_age(x)
capitalize = lambda x: x.capitalize()
email = util.email
email_or_none = lambda x: util.email(x) if util.email(x) != x else None
person = lambda x: _person(x)
short_id = lambda x: x[:12]
def bool2icon(value):
"""Returns True/False values represented as small html image of true/false
icons
:param value: bool value
"""
if value is True:
return HTML.tag('img', src="/images/icons/accept.png", alt=_('True'))
if value is False:
return HTML.tag('img', src="/images/icons/cancel.png", alt=_('False'))
return value
def action_parser(user_log):
"""This helper will map the specified string action into translated
fancy names with icons and links
:param user_log: user log instance
"""
action = user_log.action
action_params = ' '
x = action.split(':')
if len(x) > 1:
action, action_params = x
def get_cs_links():
revs_limit = 5 #display this amount always
revs_top_limit = 50 #show upto this amount of changesets hidden
revs = action_params.split(',')
repo_name = user_log.repository.repo_name
from rhodecode.model.scm import ScmModel
message = lambda rev: get_changeset_safe(ScmModel().get(repo_name),
rev).message
cs_links = " " + ', '.join ([link_to(rev,
url('changeset_home',
repo_name=repo_name,
revision=rev), title=tooltip(message(rev)),
class_='tooltip') for rev in revs[:revs_limit] ])
compare_view = (' <div class="compare_view tooltip" title="%s">'
'<a href="%s">%s</a> '
'</div>' % (_('Show all combined changesets %s->%s' \
% (revs[0], revs[-1])),
url('changeset_home', repo_name=repo_name,
revision='%s...%s' % (revs[0], revs[-1])
),
_('compare view'))
)
if len(revs) > revs_limit:
uniq_id = revs[0]
html_tmpl = ('<span> %s '
'<a class="show_more" id="_%s" href="#more">%s</a> '
'%s</span>')
cs_links += html_tmpl % (_('and'), uniq_id, _('%s more') \
% (len(revs) - revs_limit),
_('revisions'))
html_tmpl = '<span id="%s" style="display:none"> %s </span>'
cs_links += html_tmpl % (uniq_id, ', '.join([link_to(rev,
url('changeset_home',
repo_name=repo_name, revision=rev),
title=message(rev), class_='tooltip')
for rev in revs[revs_limit:revs_top_limit]]))
if len(revs) > 1:
cs_links += compare_view
return cs_links
def get_fork_name():
from rhodecode.model.scm import ScmModel
repo_name = action_params
repo = ScmModel().get(repo_name)
if repo is None:
return repo_name
return link_to(action_params, url('summary_home',
repo_name=repo.name,),
title=repo.dbrepo.description)
map = {'user_deleted_repo':(_('User [deleted] repository'), None),
'user_created_repo':(_('User [created] repository'), None),
'user_forked_repo':(_('User [forked] repository as:'), get_fork_name),
'user_updated_repo':(_('User [updated] repository'), None),
'admin_deleted_repo':(_('Admin [delete] repository'), None),
'admin_created_repo':(_('Admin [created] repository'), None),
'admin_forked_repo':(_('Admin [forked] repository'), None),
'admin_updated_repo':(_('Admin [updated] repository'), None),
'push':(_('[Pushed]'), get_cs_links),
'pull':(_('[Pulled]'), None),
'started_following_repo':(_('User [started following] repository'), None),
'stopped_following_repo':(_('User [stopped following] repository'), None),
}
action_str = map.get(action, action)
action = action_str[0].replace('[', '<span class="journal_highlight">')\
.replace(']', '</span>')
if action_str[1] is not None:
action = action + " " + action_str[1]()
return literal(action)
def action_parser_icon(user_log):
action = user_log.action
action_params = None
x = action.split(':')
if len(x) > 1:
action, action_params = x
tmpl = """<img src="/images/icons/%s" alt="%s"/>"""
map = {'user_deleted_repo':'database_delete.png',
'user_created_repo':'database_add.png',
'user_forked_repo':'arrow_divide.png',
'user_updated_repo':'database_edit.png',
'admin_deleted_repo':'database_delete.png',
'admin_created_repo':'database_add.png',
'admin_forked_repo':'arrow_divide.png',
'admin_updated_repo':'database_edit.png',
'push':'script_add.png',
'pull':'down_16.png',
'started_following_repo':'heart_add.png',
'stopped_following_repo':'heart_delete.png',
}
return literal(tmpl % (map.get(action, action), action))
#==============================================================================
# PERMS
#==============================================================================
from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
HasRepoPermissionAny, HasRepoPermissionAll
#==============================================================================
# GRAVATAR URL
#==============================================================================
import hashlib
import urllib
from pylons import request
def gravatar_url(email_address, size=30):
ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
default = 'identicon'
baseurl_nossl = "http://www.gravatar.com/avatar/"
baseurl_ssl = "https://secure.gravatar.com/avatar/"
baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
# construct the url
gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
return gravatar_url
def safe_unicode(str):
"""safe unicode function. In case of UnicodeDecode error we try to return
unicode with errors replace, if this failes we return unicode with
string_escape decoding """
try:
u_str = unicode(str)
except UnicodeDecodeError:
try:
u_str = unicode(str, 'utf-8', 'replace')
except UnicodeDecodeError:
#incase we have a decode error just represent as byte string
u_str = unicode(str(str).encode('string_escape'))
return u_str
def changed_tooltip(nodes):
if nodes:
pref = ': <br/> '
suf = ''
if len(nodes) > 30:
suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
return literal(pref + '<br/> '.join([x.path for x in nodes[:30]]) + suf)
else:
return ': ' + _('No Files')
|