##// END OF EJS Templates
static: bring back ver=XXX for proper flushing caches when version is upgraded....
marcink -
r537:6c4e8fd9 default
parent child Browse files
Show More
@@ -1,1962 +1,1963 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 Helper functions
23 23
24 24 Consists of functions to typically be used within templates, but also
25 25 available to Controllers. This module is available to both as 'h'.
26 26 """
27 27
28 28 import random
29 29 import hashlib
30 30 import StringIO
31 31 import urllib
32 32 import math
33 33 import logging
34 34 import re
35 35 import urlparse
36 36 import time
37 37 import string
38 38 import hashlib
39 39 import pygments
40 40
41 41 from datetime import datetime
42 42 from functools import partial
43 43 from pygments.formatters.html import HtmlFormatter
44 44 from pygments import highlight as code_highlight
45 45 from pygments.lexers import (
46 46 get_lexer_by_name, get_lexer_for_filename, get_lexer_for_mimetype)
47 47 from pylons import url as pylons_url
48 48 from pylons.i18n.translation import _, ungettext
49 49 from pyramid.threadlocal import get_current_request
50 50
51 51 from webhelpers.html import literal, HTML, escape
52 52 from webhelpers.html.tools import *
53 53 from webhelpers.html.builder import make_tag
54 54 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
55 55 end_form, file, form as wh_form, hidden, image, javascript_link, link_to, \
56 56 link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \
57 57 submit, text, password, textarea, title, ul, xml_declaration, radio
58 58 from webhelpers.html.tools import auto_link, button_to, highlight, \
59 59 js_obfuscate, mail_to, strip_links, strip_tags, tag_re
60 60 from webhelpers.pylonslib import Flash as _Flash
61 61 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
62 62 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
63 63 replace_whitespace, urlify, truncate, wrap_paragraphs
64 64 from webhelpers.date import time_ago_in_words
65 65 from webhelpers.paginate import Page as _Page
66 66 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
67 67 convert_boolean_attrs, NotGiven, _make_safe_id_component
68 68 from webhelpers2.number import format_byte_size
69 69
70 70 from rhodecode.lib.annotate import annotate_highlight
71 71 from rhodecode.lib.action_parser import action_parser
72 72 from rhodecode.lib.ext_json import json
73 73 from rhodecode.lib.utils import repo_name_slug, get_custom_lexer
74 74 from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \
75 75 get_commit_safe, datetime_to_time, time_to_datetime, time_to_utcdatetime, \
76 76 AttributeDict, safe_int, md5, md5_safe
77 77 from rhodecode.lib.markup_renderer import MarkupRenderer
78 78 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
79 79 from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyCommit
80 80 from rhodecode.config.conf import DATE_FORMAT, DATETIME_FORMAT
81 81 from rhodecode.model.changeset_status import ChangesetStatusModel
82 82 from rhodecode.model.db import Permission, User, Repository
83 83 from rhodecode.model.repo_group import RepoGroupModel
84 84 from rhodecode.model.settings import IssueTrackerSettingsModel
85 85
86 86 log = logging.getLogger(__name__)
87 87
88 88
89 89 DEFAULT_USER = User.DEFAULT_USER
90 90 DEFAULT_USER_EMAIL = User.DEFAULT_USER_EMAIL
91 91
92 92
93 93 def url(*args, **kw):
94 94 return pylons_url(*args, **kw)
95 95
96 96
97 97 def pylons_url_current(*args, **kw):
98 98 """
99 99 This function overrides pylons.url.current() which returns the current
100 100 path so that it will also work from a pyramid only context. This
101 101 should be removed once port to pyramid is complete.
102 102 """
103 103 if not args and not kw:
104 104 request = get_current_request()
105 105 return request.path
106 106 return pylons_url.current(*args, **kw)
107 107
108 108 url.current = pylons_url_current
109 109
110 110
111 111 def asset(path, ver=None):
112 112 """
113 113 Helper to generate a static asset file path for rhodecode assets
114 114
115 115 eg. h.asset('images/image.png', ver='3923')
116 116
117 117 :param path: path of asset
118 118 :param ver: optional version query param to append as ?ver=
119 119 """
120 120 request = get_current_request()
121 return request.static_url('rhodecode:public/{}'.format(path), ver=ver)
121 return request.static_url(
122 'rhodecode:public/{}'.format(path), _query={'ver': ver})
122 123
123 124
124 125 def html_escape(text, html_escape_table=None):
125 126 """Produce entities within text."""
126 127 if not html_escape_table:
127 128 html_escape_table = {
128 129 "&": "&amp;",
129 130 '"': "&quot;",
130 131 "'": "&apos;",
131 132 ">": "&gt;",
132 133 "<": "&lt;",
133 134 }
134 135 return "".join(html_escape_table.get(c, c) for c in text)
135 136
136 137
137 138 def chop_at_smart(s, sub, inclusive=False, suffix_if_chopped=None):
138 139 """
139 140 Truncate string ``s`` at the first occurrence of ``sub``.
140 141
141 142 If ``inclusive`` is true, truncate just after ``sub`` rather than at it.
142 143 """
143 144 suffix_if_chopped = suffix_if_chopped or ''
144 145 pos = s.find(sub)
145 146 if pos == -1:
146 147 return s
147 148
148 149 if inclusive:
149 150 pos += len(sub)
150 151
151 152 chopped = s[:pos]
152 153 left = s[pos:].strip()
153 154
154 155 if left and suffix_if_chopped:
155 156 chopped += suffix_if_chopped
156 157
157 158 return chopped
158 159
159 160
160 161 def shorter(text, size=20):
161 162 postfix = '...'
162 163 if len(text) > size:
163 164 return text[:size - len(postfix)] + postfix
164 165 return text
165 166
166 167
167 168 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
168 169 """
169 170 Reset button
170 171 """
171 172 _set_input_attrs(attrs, type, name, value)
172 173 _set_id_attr(attrs, id, name)
173 174 convert_boolean_attrs(attrs, ["disabled"])
174 175 return HTML.input(**attrs)
175 176
176 177 reset = _reset
177 178 safeid = _make_safe_id_component
178 179
179 180
180 181 def branding(name, length=40):
181 182 return truncate(name, length, indicator="")
182 183
183 184
184 185 def FID(raw_id, path):
185 186 """
186 187 Creates a unique ID for filenode based on it's hash of path and commit
187 188 it's safe to use in urls
188 189
189 190 :param raw_id:
190 191 :param path:
191 192 """
192 193
193 194 return 'c-%s-%s' % (short_id(raw_id), md5_safe(path)[:12])
194 195
195 196
196 197 class _GetError(object):
197 198 """Get error from form_errors, and represent it as span wrapped error
198 199 message
199 200
200 201 :param field_name: field to fetch errors for
201 202 :param form_errors: form errors dict
202 203 """
203 204
204 205 def __call__(self, field_name, form_errors):
205 206 tmpl = """<span class="error_msg">%s</span>"""
206 207 if form_errors and field_name in form_errors:
207 208 return literal(tmpl % form_errors.get(field_name))
208 209
209 210 get_error = _GetError()
210 211
211 212
212 213 class _ToolTip(object):
213 214
214 215 def __call__(self, tooltip_title, trim_at=50):
215 216 """
216 217 Special function just to wrap our text into nice formatted
217 218 autowrapped text
218 219
219 220 :param tooltip_title:
220 221 """
221 222 tooltip_title = escape(tooltip_title)
222 223 tooltip_title = tooltip_title.replace('<', '&lt;').replace('>', '&gt;')
223 224 return tooltip_title
224 225 tooltip = _ToolTip()
225 226
226 227
227 228 def files_breadcrumbs(repo_name, commit_id, file_path):
228 229 if isinstance(file_path, str):
229 230 file_path = safe_unicode(file_path)
230 231
231 232 # TODO: johbo: Is this always a url like path, or is this operating
232 233 # system dependent?
233 234 path_segments = file_path.split('/')
234 235
235 236 repo_name_html = escape(repo_name)
236 237 if len(path_segments) == 1 and path_segments[0] == '':
237 238 url_segments = [repo_name_html]
238 239 else:
239 240 url_segments = [
240 241 link_to(
241 242 repo_name_html,
242 243 url('files_home',
243 244 repo_name=repo_name,
244 245 revision=commit_id,
245 246 f_path=''),
246 247 class_='pjax-link')]
247 248
248 249 last_cnt = len(path_segments) - 1
249 250 for cnt, segment in enumerate(path_segments):
250 251 if not segment:
251 252 continue
252 253 segment_html = escape(segment)
253 254
254 255 if cnt != last_cnt:
255 256 url_segments.append(
256 257 link_to(
257 258 segment_html,
258 259 url('files_home',
259 260 repo_name=repo_name,
260 261 revision=commit_id,
261 262 f_path='/'.join(path_segments[:cnt + 1])),
262 263 class_='pjax-link'))
263 264 else:
264 265 url_segments.append(segment_html)
265 266
266 267 return literal('/'.join(url_segments))
267 268
268 269
269 270 class CodeHtmlFormatter(HtmlFormatter):
270 271 """
271 272 My code Html Formatter for source codes
272 273 """
273 274
274 275 def wrap(self, source, outfile):
275 276 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
276 277
277 278 def _wrap_code(self, source):
278 279 for cnt, it in enumerate(source):
279 280 i, t = it
280 281 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
281 282 yield i, t
282 283
283 284 def _wrap_tablelinenos(self, inner):
284 285 dummyoutfile = StringIO.StringIO()
285 286 lncount = 0
286 287 for t, line in inner:
287 288 if t:
288 289 lncount += 1
289 290 dummyoutfile.write(line)
290 291
291 292 fl = self.linenostart
292 293 mw = len(str(lncount + fl - 1))
293 294 sp = self.linenospecial
294 295 st = self.linenostep
295 296 la = self.lineanchors
296 297 aln = self.anchorlinenos
297 298 nocls = self.noclasses
298 299 if sp:
299 300 lines = []
300 301
301 302 for i in range(fl, fl + lncount):
302 303 if i % st == 0:
303 304 if i % sp == 0:
304 305 if aln:
305 306 lines.append('<a href="#%s%d" class="special">%*d</a>' %
306 307 (la, i, mw, i))
307 308 else:
308 309 lines.append('<span class="special">%*d</span>' % (mw, i))
309 310 else:
310 311 if aln:
311 312 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
312 313 else:
313 314 lines.append('%*d' % (mw, i))
314 315 else:
315 316 lines.append('')
316 317 ls = '\n'.join(lines)
317 318 else:
318 319 lines = []
319 320 for i in range(fl, fl + lncount):
320 321 if i % st == 0:
321 322 if aln:
322 323 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
323 324 else:
324 325 lines.append('%*d' % (mw, i))
325 326 else:
326 327 lines.append('')
327 328 ls = '\n'.join(lines)
328 329
329 330 # in case you wonder about the seemingly redundant <div> here: since the
330 331 # content in the other cell also is wrapped in a div, some browsers in
331 332 # some configurations seem to mess up the formatting...
332 333 if nocls:
333 334 yield 0, ('<table class="%stable">' % self.cssclass +
334 335 '<tr><td><div class="linenodiv" '
335 336 'style="background-color: #f0f0f0; padding-right: 10px">'
336 337 '<pre style="line-height: 125%">' +
337 338 ls + '</pre></div></td><td id="hlcode" class="code">')
338 339 else:
339 340 yield 0, ('<table class="%stable">' % self.cssclass +
340 341 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
341 342 ls + '</pre></div></td><td id="hlcode" class="code">')
342 343 yield 0, dummyoutfile.getvalue()
343 344 yield 0, '</td></tr></table>'
344 345
345 346
346 347 class SearchContentCodeHtmlFormatter(CodeHtmlFormatter):
347 348 def __init__(self, **kw):
348 349 # only show these line numbers if set
349 350 self.only_lines = kw.pop('only_line_numbers', [])
350 351 self.query_terms = kw.pop('query_terms', [])
351 352 self.max_lines = kw.pop('max_lines', 5)
352 353 self.line_context = kw.pop('line_context', 3)
353 354 self.url = kw.pop('url', None)
354 355
355 356 super(CodeHtmlFormatter, self).__init__(**kw)
356 357
357 358 def _wrap_code(self, source):
358 359 for cnt, it in enumerate(source):
359 360 i, t = it
360 361 t = '<pre>%s</pre>' % t
361 362 yield i, t
362 363
363 364 def _wrap_tablelinenos(self, inner):
364 365 yield 0, '<table class="code-highlight %stable">' % self.cssclass
365 366
366 367 last_shown_line_number = 0
367 368 current_line_number = 1
368 369
369 370 for t, line in inner:
370 371 if not t:
371 372 yield t, line
372 373 continue
373 374
374 375 if current_line_number in self.only_lines:
375 376 if last_shown_line_number + 1 != current_line_number:
376 377 yield 0, '<tr>'
377 378 yield 0, '<td class="line">...</td>'
378 379 yield 0, '<td id="hlcode" class="code"></td>'
379 380 yield 0, '</tr>'
380 381
381 382 yield 0, '<tr>'
382 383 if self.url:
383 384 yield 0, '<td class="line"><a href="%s#L%i">%i</a></td>' % (
384 385 self.url, current_line_number, current_line_number)
385 386 else:
386 387 yield 0, '<td class="line"><a href="">%i</a></td>' % (
387 388 current_line_number)
388 389 yield 0, '<td id="hlcode" class="code">' + line + '</td>'
389 390 yield 0, '</tr>'
390 391
391 392 last_shown_line_number = current_line_number
392 393
393 394 current_line_number += 1
394 395
395 396
396 397 yield 0, '</table>'
397 398
398 399
399 400 def extract_phrases(text_query):
400 401 """
401 402 Extracts phrases from search term string making sure phrases
402 403 contained in double quotes are kept together - and discarding empty values
403 404 or fully whitespace values eg.
404 405
405 406 'some text "a phrase" more' => ['some', 'text', 'a phrase', 'more']
406 407
407 408 """
408 409
409 410 in_phrase = False
410 411 buf = ''
411 412 phrases = []
412 413 for char in text_query:
413 414 if in_phrase:
414 415 if char == '"': # end phrase
415 416 phrases.append(buf)
416 417 buf = ''
417 418 in_phrase = False
418 419 continue
419 420 else:
420 421 buf += char
421 422 continue
422 423 else:
423 424 if char == '"': # start phrase
424 425 in_phrase = True
425 426 phrases.append(buf)
426 427 buf = ''
427 428 continue
428 429 elif char == ' ':
429 430 phrases.append(buf)
430 431 buf = ''
431 432 continue
432 433 else:
433 434 buf += char
434 435
435 436 phrases.append(buf)
436 437 phrases = [phrase.strip() for phrase in phrases if phrase.strip()]
437 438 return phrases
438 439
439 440
440 441 def get_matching_offsets(text, phrases):
441 442 """
442 443 Returns a list of string offsets in `text` that the list of `terms` match
443 444
444 445 >>> get_matching_offsets('some text here', ['some', 'here'])
445 446 [(0, 4), (10, 14)]
446 447
447 448 """
448 449 offsets = []
449 450 for phrase in phrases:
450 451 for match in re.finditer(phrase, text):
451 452 offsets.append((match.start(), match.end()))
452 453
453 454 return offsets
454 455
455 456
456 457 def normalize_text_for_matching(x):
457 458 """
458 459 Replaces all non alnum characters to spaces and lower cases the string,
459 460 useful for comparing two text strings without punctuation
460 461 """
461 462 return re.sub(r'[^\w]', ' ', x.lower())
462 463
463 464
464 465 def get_matching_line_offsets(lines, terms):
465 466 """ Return a set of `lines` indices (starting from 1) matching a
466 467 text search query, along with `context` lines above/below matching lines
467 468
468 469 :param lines: list of strings representing lines
469 470 :param terms: search term string to match in lines eg. 'some text'
470 471 :param context: number of lines above/below a matching line to add to result
471 472 :param max_lines: cut off for lines of interest
472 473 eg.
473 474
474 475 text = '''
475 476 words words words
476 477 words words words
477 478 some text some
478 479 words words words
479 480 words words words
480 481 text here what
481 482 '''
482 483 get_matching_line_offsets(text, 'text', context=1)
483 484 {3: [(5, 9)], 6: [(0, 4)]]
484 485
485 486 """
486 487 matching_lines = {}
487 488 phrases = [normalize_text_for_matching(phrase)
488 489 for phrase in extract_phrases(terms)]
489 490
490 491 for line_index, line in enumerate(lines, start=1):
491 492 match_offsets = get_matching_offsets(
492 493 normalize_text_for_matching(line), phrases)
493 494 if match_offsets:
494 495 matching_lines[line_index] = match_offsets
495 496
496 497 return matching_lines
497 498
498 499
499 500 def get_lexer_safe(mimetype=None, filepath=None):
500 501 """
501 502 Tries to return a relevant pygments lexer using mimetype/filepath name,
502 503 defaulting to plain text if none could be found
503 504 """
504 505 lexer = None
505 506 try:
506 507 if mimetype:
507 508 lexer = get_lexer_for_mimetype(mimetype)
508 509 if not lexer:
509 510 lexer = get_lexer_for_filename(filepath)
510 511 except pygments.util.ClassNotFound:
511 512 pass
512 513
513 514 if not lexer:
514 515 lexer = get_lexer_by_name('text')
515 516
516 517 return lexer
517 518
518 519
519 520 def pygmentize(filenode, **kwargs):
520 521 """
521 522 pygmentize function using pygments
522 523
523 524 :param filenode:
524 525 """
525 526 lexer = get_custom_lexer(filenode.extension) or filenode.lexer
526 527 return literal(code_highlight(filenode.content, lexer,
527 528 CodeHtmlFormatter(**kwargs)))
528 529
529 530
530 531 def pygmentize_annotation(repo_name, filenode, **kwargs):
531 532 """
532 533 pygmentize function for annotation
533 534
534 535 :param filenode:
535 536 """
536 537
537 538 color_dict = {}
538 539
539 540 def gen_color(n=10000):
540 541 """generator for getting n of evenly distributed colors using
541 542 hsv color and golden ratio. It always return same order of colors
542 543
543 544 :returns: RGB tuple
544 545 """
545 546
546 547 def hsv_to_rgb(h, s, v):
547 548 if s == 0.0:
548 549 return v, v, v
549 550 i = int(h * 6.0) # XXX assume int() truncates!
550 551 f = (h * 6.0) - i
551 552 p = v * (1.0 - s)
552 553 q = v * (1.0 - s * f)
553 554 t = v * (1.0 - s * (1.0 - f))
554 555 i = i % 6
555 556 if i == 0:
556 557 return v, t, p
557 558 if i == 1:
558 559 return q, v, p
559 560 if i == 2:
560 561 return p, v, t
561 562 if i == 3:
562 563 return p, q, v
563 564 if i == 4:
564 565 return t, p, v
565 566 if i == 5:
566 567 return v, p, q
567 568
568 569 golden_ratio = 0.618033988749895
569 570 h = 0.22717784590367374
570 571
571 572 for _ in xrange(n):
572 573 h += golden_ratio
573 574 h %= 1
574 575 HSV_tuple = [h, 0.95, 0.95]
575 576 RGB_tuple = hsv_to_rgb(*HSV_tuple)
576 577 yield map(lambda x: str(int(x * 256)), RGB_tuple)
577 578
578 579 cgenerator = gen_color()
579 580
580 581 def get_color_string(commit_id):
581 582 if commit_id in color_dict:
582 583 col = color_dict[commit_id]
583 584 else:
584 585 col = color_dict[commit_id] = cgenerator.next()
585 586 return "color: rgb(%s)! important;" % (', '.join(col))
586 587
587 588 def url_func(repo_name):
588 589
589 590 def _url_func(commit):
590 591 author = commit.author
591 592 date = commit.date
592 593 message = tooltip(commit.message)
593 594
594 595 tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>"
595 596 " %s<br/><b>Date:</b> %s</b><br/><b>Message:"
596 597 "</b> %s<br/></div>")
597 598
598 599 tooltip_html = tooltip_html % (author, date, message)
599 600 lnk_format = '%5s:%s' % ('r%s' % commit.idx, commit.short_id)
600 601 uri = link_to(
601 602 lnk_format,
602 603 url('changeset_home', repo_name=repo_name,
603 604 revision=commit.raw_id),
604 605 style=get_color_string(commit.raw_id),
605 606 class_='tooltip',
606 607 title=tooltip_html
607 608 )
608 609
609 610 uri += '\n'
610 611 return uri
611 612 return _url_func
612 613
613 614 return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
614 615
615 616
616 617 def is_following_repo(repo_name, user_id):
617 618 from rhodecode.model.scm import ScmModel
618 619 return ScmModel().is_following_repo(repo_name, user_id)
619 620
620 621
621 622 class _Message(object):
622 623 """A message returned by ``Flash.pop_messages()``.
623 624
624 625 Converting the message to a string returns the message text. Instances
625 626 also have the following attributes:
626 627
627 628 * ``message``: the message text.
628 629 * ``category``: the category specified when the message was created.
629 630 """
630 631
631 632 def __init__(self, category, message):
632 633 self.category = category
633 634 self.message = message
634 635
635 636 def __str__(self):
636 637 return self.message
637 638
638 639 __unicode__ = __str__
639 640
640 641 def __html__(self):
641 642 return escape(safe_unicode(self.message))
642 643
643 644
644 645 class Flash(_Flash):
645 646
646 647 def pop_messages(self):
647 648 """Return all accumulated messages and delete them from the session.
648 649
649 650 The return value is a list of ``Message`` objects.
650 651 """
651 652 from pylons import session
652 653
653 654 messages = []
654 655
655 656 # Pop the 'old' pylons flash messages. They are tuples of the form
656 657 # (category, message)
657 658 for cat, msg in session.pop(self.session_key, []):
658 659 messages.append(_Message(cat, msg))
659 660
660 661 # Pop the 'new' pyramid flash messages for each category as list
661 662 # of strings.
662 663 for cat in self.categories:
663 664 for msg in session.pop_flash(queue=cat):
664 665 messages.append(_Message(cat, msg))
665 666 # Map messages from the default queue to the 'notice' category.
666 667 for msg in session.pop_flash():
667 668 messages.append(_Message('notice', msg))
668 669
669 670 session.save()
670 671 return messages
671 672
672 673 flash = Flash()
673 674
674 675 #==============================================================================
675 676 # SCM FILTERS available via h.
676 677 #==============================================================================
677 678 from rhodecode.lib.vcs.utils import author_name, author_email
678 679 from rhodecode.lib.utils2 import credentials_filter, age as _age
679 680 from rhodecode.model.db import User, ChangesetStatus
680 681
681 682 age = _age
682 683 capitalize = lambda x: x.capitalize()
683 684 email = author_email
684 685 short_id = lambda x: x[:12]
685 686 hide_credentials = lambda x: ''.join(credentials_filter(x))
686 687
687 688
688 689 def age_component(datetime_iso, value=None, time_is_local=False):
689 690 title = value or format_date(datetime_iso)
690 691
691 692 # detect if we have a timezone info, otherwise, add it
692 693 if isinstance(datetime_iso, datetime) and not datetime_iso.tzinfo:
693 694 tzinfo = '+00:00'
694 695
695 696 if time_is_local:
696 697 tzinfo = time.strftime("+%H:%M",
697 698 time.gmtime(
698 699 (datetime.now() - datetime.utcnow()).seconds + 1
699 700 )
700 701 )
701 702
702 703 return literal(
703 704 '<time class="timeago tooltip" '
704 705 'title="{1}" datetime="{0}{2}">{1}</time>'.format(
705 706 datetime_iso, title, tzinfo))
706 707
707 708
708 709 def _shorten_commit_id(commit_id):
709 710 from rhodecode import CONFIG
710 711 def_len = safe_int(CONFIG.get('rhodecode_show_sha_length', 12))
711 712 return commit_id[:def_len]
712 713
713 714
714 715 def show_id(commit):
715 716 """
716 717 Configurable function that shows ID
717 718 by default it's r123:fffeeefffeee
718 719
719 720 :param commit: commit instance
720 721 """
721 722 from rhodecode import CONFIG
722 723 show_idx = str2bool(CONFIG.get('rhodecode_show_revision_number', True))
723 724
724 725 raw_id = _shorten_commit_id(commit.raw_id)
725 726 if show_idx:
726 727 return 'r%s:%s' % (commit.idx, raw_id)
727 728 else:
728 729 return '%s' % (raw_id, )
729 730
730 731
731 732 def format_date(date):
732 733 """
733 734 use a standardized formatting for dates used in RhodeCode
734 735
735 736 :param date: date/datetime object
736 737 :return: formatted date
737 738 """
738 739
739 740 if date:
740 741 _fmt = "%a, %d %b %Y %H:%M:%S"
741 742 return safe_unicode(date.strftime(_fmt))
742 743
743 744 return u""
744 745
745 746
746 747 class _RepoChecker(object):
747 748
748 749 def __init__(self, backend_alias):
749 750 self._backend_alias = backend_alias
750 751
751 752 def __call__(self, repository):
752 753 if hasattr(repository, 'alias'):
753 754 _type = repository.alias
754 755 elif hasattr(repository, 'repo_type'):
755 756 _type = repository.repo_type
756 757 else:
757 758 _type = repository
758 759 return _type == self._backend_alias
759 760
760 761 is_git = _RepoChecker('git')
761 762 is_hg = _RepoChecker('hg')
762 763 is_svn = _RepoChecker('svn')
763 764
764 765
765 766 def get_repo_type_by_name(repo_name):
766 767 repo = Repository.get_by_repo_name(repo_name)
767 768 return repo.repo_type
768 769
769 770
770 771 def is_svn_without_proxy(repository):
771 772 from rhodecode import CONFIG
772 773 if is_svn(repository):
773 774 if not CONFIG.get('rhodecode_proxy_subversion_http_requests', False):
774 775 return True
775 776 return False
776 777
777 778
778 779 def discover_user(author):
779 780 """
780 781 Tries to discover RhodeCode User based on the autho string. Author string
781 782 is typically `FirstName LastName <email@address.com>`
782 783 """
783 784
784 785 # if author is already an instance use it for extraction
785 786 if isinstance(author, User):
786 787 return author
787 788
788 789 # Valid email in the attribute passed, see if they're in the system
789 790 _email = author_email(author)
790 791 if _email != '':
791 792 user = User.get_by_email(_email, case_insensitive=True, cache=True)
792 793 if user is not None:
793 794 return user
794 795
795 796 # Maybe it's a username, we try to extract it and fetch by username ?
796 797 _author = author_name(author)
797 798 user = User.get_by_username(_author, case_insensitive=True, cache=True)
798 799 if user is not None:
799 800 return user
800 801
801 802 return None
802 803
803 804
804 805 def email_or_none(author):
805 806 # extract email from the commit string
806 807 _email = author_email(author)
807 808
808 809 # If we have an email, use it, otherwise
809 810 # see if it contains a username we can get an email from
810 811 if _email != '':
811 812 return _email
812 813 else:
813 814 user = User.get_by_username(
814 815 author_name(author), case_insensitive=True, cache=True)
815 816
816 817 if user is not None:
817 818 return user.email
818 819
819 820 # No valid email, not a valid user in the system, none!
820 821 return None
821 822
822 823
823 824 def link_to_user(author, length=0, **kwargs):
824 825 user = discover_user(author)
825 826 # user can be None, but if we have it already it means we can re-use it
826 827 # in the person() function, so we save 1 intensive-query
827 828 if user:
828 829 author = user
829 830
830 831 display_person = person(author, 'username_or_name_or_email')
831 832 if length:
832 833 display_person = shorter(display_person, length)
833 834
834 835 if user:
835 836 return link_to(
836 837 escape(display_person),
837 838 url('user_profile', username=user.username),
838 839 **kwargs)
839 840 else:
840 841 return escape(display_person)
841 842
842 843
843 844 def person(author, show_attr="username_and_name"):
844 845 user = discover_user(author)
845 846 if user:
846 847 return getattr(user, show_attr)
847 848 else:
848 849 _author = author_name(author)
849 850 _email = email(author)
850 851 return _author or _email
851 852
852 853
853 854 def author_string(email):
854 855 if email:
855 856 user = User.get_by_email(email, case_insensitive=True, cache=True)
856 857 if user:
857 858 if user.firstname or user.lastname:
858 859 return '%s %s &lt;%s&gt;' % (user.firstname, user.lastname, email)
859 860 else:
860 861 return email
861 862 else:
862 863 return email
863 864 else:
864 865 return None
865 866
866 867
867 868 def person_by_id(id_, show_attr="username_and_name"):
868 869 # attr to return from fetched user
869 870 person_getter = lambda usr: getattr(usr, show_attr)
870 871
871 872 #maybe it's an ID ?
872 873 if str(id_).isdigit() or isinstance(id_, int):
873 874 id_ = int(id_)
874 875 user = User.get(id_)
875 876 if user is not None:
876 877 return person_getter(user)
877 878 return id_
878 879
879 880
880 881 def gravatar_with_user(author, show_disabled=False):
881 882 from rhodecode.lib.utils import PartialRenderer
882 883 _render = PartialRenderer('base/base.html')
883 884 return _render('gravatar_with_user', author, show_disabled=show_disabled)
884 885
885 886
886 887 def desc_stylize(value):
887 888 """
888 889 converts tags from value into html equivalent
889 890
890 891 :param value:
891 892 """
892 893 if not value:
893 894 return ''
894 895
895 896 value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
896 897 '<div class="metatag" tag="see">see =&gt; \\1 </div>', value)
897 898 value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
898 899 '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value)
899 900 value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z0-9\-\/]*)\]',
900 901 '<div class="metatag" tag="\\1">\\1 =&gt; <a href="/\\2">\\2</a></div>', value)
901 902 value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]',
902 903 '<div class="metatag" tag="lang">\\2</div>', value)
903 904 value = re.sub(r'\[([a-z]+)\]',
904 905 '<div class="metatag" tag="\\1">\\1</div>', value)
905 906
906 907 return value
907 908
908 909
909 910 def escaped_stylize(value):
910 911 """
911 912 converts tags from value into html equivalent, but escaping its value first
912 913 """
913 914 if not value:
914 915 return ''
915 916
916 917 # Using default webhelper escape method, but has to force it as a
917 918 # plain unicode instead of a markup tag to be used in regex expressions
918 919 value = unicode(escape(safe_unicode(value)))
919 920
920 921 value = re.sub(r'\[see\ \=\&gt;\ *([a-zA-Z0-9\/\=\?\&amp;\ \:\/\.\-]*)\]',
921 922 '<div class="metatag" tag="see">see =&gt; \\1 </div>', value)
922 923 value = re.sub(r'\[license\ \=\&gt;\ *([a-zA-Z0-9\/\=\?\&amp;\ \:\/\.\-]*)\]',
923 924 '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value)
924 925 value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\&gt;\ *([a-zA-Z0-9\-\/]*)\]',
925 926 '<div class="metatag" tag="\\1">\\1 =&gt; <a href="/\\2">\\2</a></div>', value)
926 927 value = re.sub(r'\[(lang|language)\ \=\&gt;\ *([a-zA-Z\-\/\#\+]*)\]',
927 928 '<div class="metatag" tag="lang">\\2</div>', value)
928 929 value = re.sub(r'\[([a-z]+)\]',
929 930 '<div class="metatag" tag="\\1">\\1</div>', value)
930 931
931 932 return value
932 933
933 934
934 935 def bool2icon(value):
935 936 """
936 937 Returns boolean value of a given value, represented as html element with
937 938 classes that will represent icons
938 939
939 940 :param value: given value to convert to html node
940 941 """
941 942
942 943 if value: # does bool conversion
943 944 return HTML.tag('i', class_="icon-true")
944 945 else: # not true as bool
945 946 return HTML.tag('i', class_="icon-false")
946 947
947 948
948 949 #==============================================================================
949 950 # PERMS
950 951 #==============================================================================
951 952 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
952 953 HasRepoPermissionAny, HasRepoPermissionAll, HasRepoGroupPermissionAll, \
953 954 HasRepoGroupPermissionAny, HasRepoPermissionAnyApi, get_csrf_token, \
954 955 csrf_token_key
955 956
956 957
957 958 #==============================================================================
958 959 # GRAVATAR URL
959 960 #==============================================================================
960 961 class InitialsGravatar(object):
961 962 def __init__(self, email_address, first_name, last_name, size=30,
962 963 background=None, text_color='#fff'):
963 964 self.size = size
964 965 self.first_name = first_name
965 966 self.last_name = last_name
966 967 self.email_address = email_address
967 968 self.background = background or self.str2color(email_address)
968 969 self.text_color = text_color
969 970
970 971 def get_color_bank(self):
971 972 """
972 973 returns a predefined list of colors that gravatars can use.
973 974 Those are randomized distinct colors that guarantee readability and
974 975 uniqueness.
975 976
976 977 generated with: http://phrogz.net/css/distinct-colors.html
977 978 """
978 979 return [
979 980 '#bf3030', '#a67f53', '#00ff00', '#5989b3', '#392040', '#d90000',
980 981 '#402910', '#204020', '#79baf2', '#a700b3', '#bf6060', '#7f5320',
981 982 '#008000', '#003059', '#ee00ff', '#ff0000', '#8c4b00', '#007300',
982 983 '#005fb3', '#de73e6', '#ff4040', '#ffaa00', '#3df255', '#203140',
983 984 '#47004d', '#591616', '#664400', '#59b365', '#0d2133', '#83008c',
984 985 '#592d2d', '#bf9f60', '#73e682', '#1d3f73', '#73006b', '#402020',
985 986 '#b2862d', '#397341', '#597db3', '#e600d6', '#a60000', '#736039',
986 987 '#00b318', '#79aaf2', '#330d30', '#ff8080', '#403010', '#16591f',
987 988 '#002459', '#8c4688', '#e50000', '#ffbf40', '#00732e', '#102340',
988 989 '#bf60ac', '#8c4646', '#cc8800', '#00a642', '#1d3473', '#b32d98',
989 990 '#660e00', '#ffd580', '#80ffb2', '#7391e6', '#733967', '#d97b6c',
990 991 '#8c5e00', '#59b389', '#3967e6', '#590047', '#73281d', '#665200',
991 992 '#00e67a', '#2d50b3', '#8c2377', '#734139', '#b2982d', '#16593a',
992 993 '#001859', '#ff00aa', '#a65e53', '#ffcc00', '#0d3321', '#2d3959',
993 994 '#731d56', '#401610', '#4c3d00', '#468c6c', '#002ca6', '#d936a3',
994 995 '#d94c36', '#403920', '#36d9a3', '#0d1733', '#592d4a', '#993626',
995 996 '#cca300', '#00734d', '#46598c', '#8c005e', '#7f1100', '#8c7000',
996 997 '#00a66f', '#7382e6', '#b32d74', '#d9896c', '#ffe680', '#1d7362',
997 998 '#364cd9', '#73003d', '#d93a00', '#998a4d', '#59b3a1', '#5965b3',
998 999 '#e5007a', '#73341d', '#665f00', '#00b38f', '#0018b3', '#59163a',
999 1000 '#b2502d', '#bfb960', '#00ffcc', '#23318c', '#a6537f', '#734939',
1000 1001 '#b2a700', '#104036', '#3d3df2', '#402031', '#e56739', '#736f39',
1001 1002 '#79f2ea', '#000059', '#401029', '#4c1400', '#ffee00', '#005953',
1002 1003 '#101040', '#990052', '#402820', '#403d10', '#00ffee', '#0000d9',
1003 1004 '#ff80c4', '#a66953', '#eeff00', '#00ccbe', '#8080ff', '#e673a1',
1004 1005 '#a62c00', '#474d00', '#1a3331', '#46468c', '#733950', '#662900',
1005 1006 '#858c23', '#238c85', '#0f0073', '#b20047', '#d9986c', '#becc00',
1006 1007 '#396f73', '#281d73', '#ff0066', '#ff6600', '#dee673', '#59adb3',
1007 1008 '#6559b3', '#590024', '#b2622d', '#98b32d', '#36ced9', '#332d59',
1008 1009 '#40001a', '#733f1d', '#526600', '#005359', '#242040', '#bf6079',
1009 1010 '#735039', '#cef23d', '#007780', '#5630bf', '#66001b', '#b24700',
1010 1011 '#acbf60', '#1d6273', '#25008c', '#731d34', '#a67453', '#50592d',
1011 1012 '#00ccff', '#6600ff', '#ff0044', '#4c1f00', '#8a994d', '#79daf2',
1012 1013 '#a173e6', '#d93662', '#402310', '#aaff00', '#2d98b3', '#8c40ff',
1013 1014 '#592d39', '#ff8c40', '#354020', '#103640', '#1a0040', '#331a20',
1014 1015 '#331400', '#334d00', '#1d5673', '#583973', '#7f0022', '#4c3626',
1015 1016 '#88cc00', '#36a3d9', '#3d0073', '#d9364c', '#33241a', '#698c23',
1016 1017 '#5995b3', '#300059', '#e57382', '#7f3300', '#366600', '#00aaff',
1017 1018 '#3a1659', '#733941', '#663600', '#74b32d', '#003c59', '#7f53a6',
1018 1019 '#73000f', '#ff8800', '#baf279', '#79caf2', '#291040', '#a6293a',
1019 1020 '#b2742d', '#587339', '#0077b3', '#632699', '#400009', '#d9a66c',
1020 1021 '#294010', '#2d4a59', '#aa00ff', '#4c131b', '#b25f00', '#5ce600',
1021 1022 '#267399', '#a336d9', '#990014', '#664e33', '#86bf60', '#0088ff',
1022 1023 '#7700b3', '#593a16', '#073300', '#1d4b73', '#ac60bf', '#e59539',
1023 1024 '#4f8c46', '#368dd9', '#5c0073'
1024 1025 ]
1025 1026
1026 1027 def rgb_to_hex_color(self, rgb_tuple):
1027 1028 """
1028 1029 Converts an rgb_tuple passed to an hex color.
1029 1030
1030 1031 :param rgb_tuple: tuple with 3 ints represents rgb color space
1031 1032 """
1032 1033 return '#' + ("".join(map(chr, rgb_tuple)).encode('hex'))
1033 1034
1034 1035 def email_to_int_list(self, email_str):
1035 1036 """
1036 1037 Get every byte of the hex digest value of email and turn it to integer.
1037 1038 It's going to be always between 0-255
1038 1039 """
1039 1040 digest = md5_safe(email_str.lower())
1040 1041 return [int(digest[i * 2:i * 2 + 2], 16) for i in range(16)]
1041 1042
1042 1043 def pick_color_bank_index(self, email_str, color_bank):
1043 1044 return self.email_to_int_list(email_str)[0] % len(color_bank)
1044 1045
1045 1046 def str2color(self, email_str):
1046 1047 """
1047 1048 Tries to map in a stable algorithm an email to color
1048 1049
1049 1050 :param email_str:
1050 1051 """
1051 1052 color_bank = self.get_color_bank()
1052 1053 # pick position (module it's length so we always find it in the
1053 1054 # bank even if it's smaller than 256 values
1054 1055 pos = self.pick_color_bank_index(email_str, color_bank)
1055 1056 return color_bank[pos]
1056 1057
1057 1058 def normalize_email(self, email_address):
1058 1059 import unicodedata
1059 1060 # default host used to fill in the fake/missing email
1060 1061 default_host = u'localhost'
1061 1062
1062 1063 if not email_address:
1063 1064 email_address = u'%s@%s' % (User.DEFAULT_USER, default_host)
1064 1065
1065 1066 email_address = safe_unicode(email_address)
1066 1067
1067 1068 if u'@' not in email_address:
1068 1069 email_address = u'%s@%s' % (email_address, default_host)
1069 1070
1070 1071 if email_address.endswith(u'@'):
1071 1072 email_address = u'%s%s' % (email_address, default_host)
1072 1073
1073 1074 email_address = unicodedata.normalize('NFKD', email_address)\
1074 1075 .encode('ascii', 'ignore')
1075 1076 return email_address
1076 1077
1077 1078 def get_initials(self):
1078 1079 """
1079 1080 Returns 2 letter initials calculated based on the input.
1080 1081 The algorithm picks first given email address, and takes first letter
1081 1082 of part before @, and then the first letter of server name. In case
1082 1083 the part before @ is in a format of `somestring.somestring2` it replaces
1083 1084 the server letter with first letter of somestring2
1084 1085
1085 1086 In case function was initialized with both first and lastname, this
1086 1087 overrides the extraction from email by first letter of the first and
1087 1088 last name. We add special logic to that functionality, In case Full name
1088 1089 is compound, like Guido Von Rossum, we use last part of the last name
1089 1090 (Von Rossum) picking `R`.
1090 1091
1091 1092 Function also normalizes the non-ascii characters to they ascii
1092 1093 representation, eg Ą => A
1093 1094 """
1094 1095 import unicodedata
1095 1096 # replace non-ascii to ascii
1096 1097 first_name = unicodedata.normalize(
1097 1098 'NFKD', safe_unicode(self.first_name)).encode('ascii', 'ignore')
1098 1099 last_name = unicodedata.normalize(
1099 1100 'NFKD', safe_unicode(self.last_name)).encode('ascii', 'ignore')
1100 1101
1101 1102 # do NFKD encoding, and also make sure email has proper format
1102 1103 email_address = self.normalize_email(self.email_address)
1103 1104
1104 1105 # first push the email initials
1105 1106 prefix, server = email_address.split('@', 1)
1106 1107
1107 1108 # check if prefix is maybe a 'firstname.lastname' syntax
1108 1109 _dot_split = prefix.rsplit('.', 1)
1109 1110 if len(_dot_split) == 2:
1110 1111 initials = [_dot_split[0][0], _dot_split[1][0]]
1111 1112 else:
1112 1113 initials = [prefix[0], server[0]]
1113 1114
1114 1115 # then try to replace either firtname or lastname
1115 1116 fn_letter = (first_name or " ")[0].strip()
1116 1117 ln_letter = (last_name.split(' ', 1)[-1] or " ")[0].strip()
1117 1118
1118 1119 if fn_letter:
1119 1120 initials[0] = fn_letter
1120 1121
1121 1122 if ln_letter:
1122 1123 initials[1] = ln_letter
1123 1124
1124 1125 return ''.join(initials).upper()
1125 1126
1126 1127 def get_img_data_by_type(self, font_family, img_type):
1127 1128 default_user = """
1128 1129 <svg xmlns="http://www.w3.org/2000/svg"
1129 1130 version="1.1" x="0px" y="0px" width="{size}" height="{size}"
1130 1131 viewBox="-15 -10 439.165 429.164"
1131 1132
1132 1133 xml:space="preserve"
1133 1134 style="background:{background};" >
1134 1135
1135 1136 <path d="M204.583,216.671c50.664,0,91.74-48.075,
1136 1137 91.74-107.378c0-82.237-41.074-107.377-91.74-107.377
1137 1138 c-50.668,0-91.74,25.14-91.74,107.377C112.844,
1138 1139 168.596,153.916,216.671,
1139 1140 204.583,216.671z" fill="{text_color}"/>
1140 1141 <path d="M407.164,374.717L360.88,
1141 1142 270.454c-2.117-4.771-5.836-8.728-10.465-11.138l-71.83-37.392
1142 1143 c-1.584-0.823-3.502-0.663-4.926,0.415c-20.316,
1143 1144 15.366-44.203,23.488-69.076,23.488c-24.877,
1144 1145 0-48.762-8.122-69.078-23.488
1145 1146 c-1.428-1.078-3.346-1.238-4.93-0.415L58.75,
1146 1147 259.316c-4.631,2.41-8.346,6.365-10.465,11.138L2.001,374.717
1147 1148 c-3.191,7.188-2.537,15.412,1.75,22.005c4.285,
1148 1149 6.592,11.537,10.526,19.4,10.526h362.861c7.863,0,15.117-3.936,
1149 1150 19.402-10.527 C409.699,390.129,
1150 1151 410.355,381.902,407.164,374.717z" fill="{text_color}"/>
1151 1152 </svg>""".format(
1152 1153 size=self.size,
1153 1154 background='#979797', # @grey4
1154 1155 text_color=self.text_color,
1155 1156 font_family=font_family)
1156 1157
1157 1158 return {
1158 1159 "default_user": default_user
1159 1160 }[img_type]
1160 1161
1161 1162 def get_img_data(self, svg_type=None):
1162 1163 """
1163 1164 generates the svg metadata for image
1164 1165 """
1165 1166
1166 1167 font_family = ','.join([
1167 1168 'proximanovaregular',
1168 1169 'Proxima Nova Regular',
1169 1170 'Proxima Nova',
1170 1171 'Arial',
1171 1172 'Lucida Grande',
1172 1173 'sans-serif'
1173 1174 ])
1174 1175 if svg_type:
1175 1176 return self.get_img_data_by_type(font_family, svg_type)
1176 1177
1177 1178 initials = self.get_initials()
1178 1179 img_data = """
1179 1180 <svg xmlns="http://www.w3.org/2000/svg" pointer-events="none"
1180 1181 width="{size}" height="{size}"
1181 1182 style="width: 100%; height: 100%; background-color: {background}"
1182 1183 viewBox="0 0 {size} {size}">
1183 1184 <text text-anchor="middle" y="50%" x="50%" dy="0.35em"
1184 1185 pointer-events="auto" fill="{text_color}"
1185 1186 font-family="{font_family}"
1186 1187 style="font-weight: 400; font-size: {f_size}px;">{text}
1187 1188 </text>
1188 1189 </svg>""".format(
1189 1190 size=self.size,
1190 1191 f_size=self.size/1.85, # scale the text inside the box nicely
1191 1192 background=self.background,
1192 1193 text_color=self.text_color,
1193 1194 text=initials.upper(),
1194 1195 font_family=font_family)
1195 1196
1196 1197 return img_data
1197 1198
1198 1199 def generate_svg(self, svg_type=None):
1199 1200 img_data = self.get_img_data(svg_type)
1200 1201 return "data:image/svg+xml;base64,%s" % img_data.encode('base64')
1201 1202
1202 1203
1203 1204 def initials_gravatar(email_address, first_name, last_name, size=30):
1204 1205 svg_type = None
1205 1206 if email_address == User.DEFAULT_USER_EMAIL:
1206 1207 svg_type = 'default_user'
1207 1208 klass = InitialsGravatar(email_address, first_name, last_name, size)
1208 1209 return klass.generate_svg(svg_type=svg_type)
1209 1210
1210 1211
1211 1212 def gravatar_url(email_address, size=30):
1212 1213 # doh, we need to re-import those to mock it later
1213 1214 from pylons import tmpl_context as c
1214 1215
1215 1216 _use_gravatar = c.visual.use_gravatar
1216 1217 _gravatar_url = c.visual.gravatar_url or User.DEFAULT_GRAVATAR_URL
1217 1218
1218 1219 email_address = email_address or User.DEFAULT_USER_EMAIL
1219 1220 if isinstance(email_address, unicode):
1220 1221 # hashlib crashes on unicode items
1221 1222 email_address = safe_str(email_address)
1222 1223
1223 1224 # empty email or default user
1224 1225 if not email_address or email_address == User.DEFAULT_USER_EMAIL:
1225 1226 return initials_gravatar(User.DEFAULT_USER_EMAIL, '', '', size=size)
1226 1227
1227 1228 if _use_gravatar:
1228 1229 # TODO: Disuse pyramid thread locals. Think about another solution to
1229 1230 # get the host and schema here.
1230 1231 request = get_current_request()
1231 1232 tmpl = safe_str(_gravatar_url)
1232 1233 tmpl = tmpl.replace('{email}', email_address)\
1233 1234 .replace('{md5email}', md5_safe(email_address.lower())) \
1234 1235 .replace('{netloc}', request.host)\
1235 1236 .replace('{scheme}', request.scheme)\
1236 1237 .replace('{size}', safe_str(size))
1237 1238 return tmpl
1238 1239 else:
1239 1240 return initials_gravatar(email_address, '', '', size=size)
1240 1241
1241 1242
1242 1243 class Page(_Page):
1243 1244 """
1244 1245 Custom pager to match rendering style with paginator
1245 1246 """
1246 1247
1247 1248 def _get_pos(self, cur_page, max_page, items):
1248 1249 edge = (items / 2) + 1
1249 1250 if (cur_page <= edge):
1250 1251 radius = max(items / 2, items - cur_page)
1251 1252 elif (max_page - cur_page) < edge:
1252 1253 radius = (items - 1) - (max_page - cur_page)
1253 1254 else:
1254 1255 radius = items / 2
1255 1256
1256 1257 left = max(1, (cur_page - (radius)))
1257 1258 right = min(max_page, cur_page + (radius))
1258 1259 return left, cur_page, right
1259 1260
1260 1261 def _range(self, regexp_match):
1261 1262 """
1262 1263 Return range of linked pages (e.g. '1 2 [3] 4 5 6 7 8').
1263 1264
1264 1265 Arguments:
1265 1266
1266 1267 regexp_match
1267 1268 A "re" (regular expressions) match object containing the
1268 1269 radius of linked pages around the current page in
1269 1270 regexp_match.group(1) as a string
1270 1271
1271 1272 This function is supposed to be called as a callable in
1272 1273 re.sub.
1273 1274
1274 1275 """
1275 1276 radius = int(regexp_match.group(1))
1276 1277
1277 1278 # Compute the first and last page number within the radius
1278 1279 # e.g. '1 .. 5 6 [7] 8 9 .. 12'
1279 1280 # -> leftmost_page = 5
1280 1281 # -> rightmost_page = 9
1281 1282 leftmost_page, _cur, rightmost_page = self._get_pos(self.page,
1282 1283 self.last_page,
1283 1284 (radius * 2) + 1)
1284 1285 nav_items = []
1285 1286
1286 1287 # Create a link to the first page (unless we are on the first page
1287 1288 # or there would be no need to insert '..' spacers)
1288 1289 if self.page != self.first_page and self.first_page < leftmost_page:
1289 1290 nav_items.append(self._pagerlink(self.first_page, self.first_page))
1290 1291
1291 1292 # Insert dots if there are pages between the first page
1292 1293 # and the currently displayed page range
1293 1294 if leftmost_page - self.first_page > 1:
1294 1295 # Wrap in a SPAN tag if nolink_attr is set
1295 1296 text = '..'
1296 1297 if self.dotdot_attr:
1297 1298 text = HTML.span(c=text, **self.dotdot_attr)
1298 1299 nav_items.append(text)
1299 1300
1300 1301 for thispage in xrange(leftmost_page, rightmost_page + 1):
1301 1302 # Hilight the current page number and do not use a link
1302 1303 if thispage == self.page:
1303 1304 text = '%s' % (thispage,)
1304 1305 # Wrap in a SPAN tag if nolink_attr is set
1305 1306 if self.curpage_attr:
1306 1307 text = HTML.span(c=text, **self.curpage_attr)
1307 1308 nav_items.append(text)
1308 1309 # Otherwise create just a link to that page
1309 1310 else:
1310 1311 text = '%s' % (thispage,)
1311 1312 nav_items.append(self._pagerlink(thispage, text))
1312 1313
1313 1314 # Insert dots if there are pages between the displayed
1314 1315 # page numbers and the end of the page range
1315 1316 if self.last_page - rightmost_page > 1:
1316 1317 text = '..'
1317 1318 # Wrap in a SPAN tag if nolink_attr is set
1318 1319 if self.dotdot_attr:
1319 1320 text = HTML.span(c=text, **self.dotdot_attr)
1320 1321 nav_items.append(text)
1321 1322
1322 1323 # Create a link to the very last page (unless we are on the last
1323 1324 # page or there would be no need to insert '..' spacers)
1324 1325 if self.page != self.last_page and rightmost_page < self.last_page:
1325 1326 nav_items.append(self._pagerlink(self.last_page, self.last_page))
1326 1327
1327 1328 ## prerender links
1328 1329 #_page_link = url.current()
1329 1330 #nav_items.append(literal('<link rel="prerender" href="%s?page=%s">' % (_page_link, str(int(self.page)+1))))
1330 1331 #nav_items.append(literal('<link rel="prefetch" href="%s?page=%s">' % (_page_link, str(int(self.page)+1))))
1331 1332 return self.separator.join(nav_items)
1332 1333
1333 1334 def pager(self, format='~2~', page_param='page', partial_param='partial',
1334 1335 show_if_single_page=False, separator=' ', onclick=None,
1335 1336 symbol_first='<<', symbol_last='>>',
1336 1337 symbol_previous='<', symbol_next='>',
1337 1338 link_attr={'class': 'pager_link', 'rel': 'prerender'},
1338 1339 curpage_attr={'class': 'pager_curpage'},
1339 1340 dotdot_attr={'class': 'pager_dotdot'}, **kwargs):
1340 1341
1341 1342 self.curpage_attr = curpage_attr
1342 1343 self.separator = separator
1343 1344 self.pager_kwargs = kwargs
1344 1345 self.page_param = page_param
1345 1346 self.partial_param = partial_param
1346 1347 self.onclick = onclick
1347 1348 self.link_attr = link_attr
1348 1349 self.dotdot_attr = dotdot_attr
1349 1350
1350 1351 # Don't show navigator if there is no more than one page
1351 1352 if self.page_count == 0 or (self.page_count == 1 and not show_if_single_page):
1352 1353 return ''
1353 1354
1354 1355 from string import Template
1355 1356 # Replace ~...~ in token format by range of pages
1356 1357 result = re.sub(r'~(\d+)~', self._range, format)
1357 1358
1358 1359 # Interpolate '%' variables
1359 1360 result = Template(result).safe_substitute({
1360 1361 'first_page': self.first_page,
1361 1362 'last_page': self.last_page,
1362 1363 'page': self.page,
1363 1364 'page_count': self.page_count,
1364 1365 'items_per_page': self.items_per_page,
1365 1366 'first_item': self.first_item,
1366 1367 'last_item': self.last_item,
1367 1368 'item_count': self.item_count,
1368 1369 'link_first': self.page > self.first_page and \
1369 1370 self._pagerlink(self.first_page, symbol_first) or '',
1370 1371 'link_last': self.page < self.last_page and \
1371 1372 self._pagerlink(self.last_page, symbol_last) or '',
1372 1373 'link_previous': self.previous_page and \
1373 1374 self._pagerlink(self.previous_page, symbol_previous) \
1374 1375 or HTML.span(symbol_previous, class_="pg-previous disabled"),
1375 1376 'link_next': self.next_page and \
1376 1377 self._pagerlink(self.next_page, symbol_next) \
1377 1378 or HTML.span(symbol_next, class_="pg-next disabled")
1378 1379 })
1379 1380
1380 1381 return literal(result)
1381 1382
1382 1383
1383 1384 #==============================================================================
1384 1385 # REPO PAGER, PAGER FOR REPOSITORY
1385 1386 #==============================================================================
1386 1387 class RepoPage(Page):
1387 1388
1388 1389 def __init__(self, collection, page=1, items_per_page=20,
1389 1390 item_count=None, url=None, **kwargs):
1390 1391
1391 1392 """Create a "RepoPage" instance. special pager for paging
1392 1393 repository
1393 1394 """
1394 1395 self._url_generator = url
1395 1396
1396 1397 # Safe the kwargs class-wide so they can be used in the pager() method
1397 1398 self.kwargs = kwargs
1398 1399
1399 1400 # Save a reference to the collection
1400 1401 self.original_collection = collection
1401 1402
1402 1403 self.collection = collection
1403 1404
1404 1405 # The self.page is the number of the current page.
1405 1406 # The first page has the number 1!
1406 1407 try:
1407 1408 self.page = int(page) # make it int() if we get it as a string
1408 1409 except (ValueError, TypeError):
1409 1410 self.page = 1
1410 1411
1411 1412 self.items_per_page = items_per_page
1412 1413
1413 1414 # Unless the user tells us how many items the collections has
1414 1415 # we calculate that ourselves.
1415 1416 if item_count is not None:
1416 1417 self.item_count = item_count
1417 1418 else:
1418 1419 self.item_count = len(self.collection)
1419 1420
1420 1421 # Compute the number of the first and last available page
1421 1422 if self.item_count > 0:
1422 1423 self.first_page = 1
1423 1424 self.page_count = int(math.ceil(float(self.item_count) /
1424 1425 self.items_per_page))
1425 1426 self.last_page = self.first_page + self.page_count - 1
1426 1427
1427 1428 # Make sure that the requested page number is the range of
1428 1429 # valid pages
1429 1430 if self.page > self.last_page:
1430 1431 self.page = self.last_page
1431 1432 elif self.page < self.first_page:
1432 1433 self.page = self.first_page
1433 1434
1434 1435 # Note: the number of items on this page can be less than
1435 1436 # items_per_page if the last page is not full
1436 1437 self.first_item = max(0, (self.item_count) - (self.page *
1437 1438 items_per_page))
1438 1439 self.last_item = ((self.item_count - 1) - items_per_page *
1439 1440 (self.page - 1))
1440 1441
1441 1442 self.items = list(self.collection[self.first_item:self.last_item + 1])
1442 1443
1443 1444 # Links to previous and next page
1444 1445 if self.page > self.first_page:
1445 1446 self.previous_page = self.page - 1
1446 1447 else:
1447 1448 self.previous_page = None
1448 1449
1449 1450 if self.page < self.last_page:
1450 1451 self.next_page = self.page + 1
1451 1452 else:
1452 1453 self.next_page = None
1453 1454
1454 1455 # No items available
1455 1456 else:
1456 1457 self.first_page = None
1457 1458 self.page_count = 0
1458 1459 self.last_page = None
1459 1460 self.first_item = None
1460 1461 self.last_item = None
1461 1462 self.previous_page = None
1462 1463 self.next_page = None
1463 1464 self.items = []
1464 1465
1465 1466 # This is a subclass of the 'list' type. Initialise the list now.
1466 1467 list.__init__(self, reversed(self.items))
1467 1468
1468 1469
1469 1470 def changed_tooltip(nodes):
1470 1471 """
1471 1472 Generates a html string for changed nodes in commit page.
1472 1473 It limits the output to 30 entries
1473 1474
1474 1475 :param nodes: LazyNodesGenerator
1475 1476 """
1476 1477 if nodes:
1477 1478 pref = ': <br/> '
1478 1479 suf = ''
1479 1480 if len(nodes) > 30:
1480 1481 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
1481 1482 return literal(pref + '<br/> '.join([safe_unicode(x.path)
1482 1483 for x in nodes[:30]]) + suf)
1483 1484 else:
1484 1485 return ': ' + _('No Files')
1485 1486
1486 1487
1487 1488 def breadcrumb_repo_link(repo):
1488 1489 """
1489 1490 Makes a breadcrumbs path link to repo
1490 1491
1491 1492 ex::
1492 1493 group >> subgroup >> repo
1493 1494
1494 1495 :param repo: a Repository instance
1495 1496 """
1496 1497
1497 1498 path = [
1498 1499 link_to(group.name, url('repo_group_home', group_name=group.group_name))
1499 1500 for group in repo.groups_with_parents
1500 1501 ] + [
1501 1502 link_to(repo.just_name, url('summary_home', repo_name=repo.repo_name))
1502 1503 ]
1503 1504
1504 1505 return literal(' &raquo; '.join(path))
1505 1506
1506 1507
1507 1508 def format_byte_size_binary(file_size):
1508 1509 """
1509 1510 Formats file/folder sizes to standard.
1510 1511 """
1511 1512 formatted_size = format_byte_size(file_size, binary=True)
1512 1513 return formatted_size
1513 1514
1514 1515
1515 1516 def fancy_file_stats(stats):
1516 1517 """
1517 1518 Displays a fancy two colored bar for number of added/deleted
1518 1519 lines of code on file
1519 1520
1520 1521 :param stats: two element list of added/deleted lines of code
1521 1522 """
1522 1523 from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \
1523 1524 MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE
1524 1525
1525 1526 def cgen(l_type, a_v, d_v):
1526 1527 mapping = {'tr': 'top-right-rounded-corner-mid',
1527 1528 'tl': 'top-left-rounded-corner-mid',
1528 1529 'br': 'bottom-right-rounded-corner-mid',
1529 1530 'bl': 'bottom-left-rounded-corner-mid'}
1530 1531 map_getter = lambda x: mapping[x]
1531 1532
1532 1533 if l_type == 'a' and d_v:
1533 1534 #case when added and deleted are present
1534 1535 return ' '.join(map(map_getter, ['tl', 'bl']))
1535 1536
1536 1537 if l_type == 'a' and not d_v:
1537 1538 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
1538 1539
1539 1540 if l_type == 'd' and a_v:
1540 1541 return ' '.join(map(map_getter, ['tr', 'br']))
1541 1542
1542 1543 if l_type == 'd' and not a_v:
1543 1544 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
1544 1545
1545 1546 a, d = stats['added'], stats['deleted']
1546 1547 width = 100
1547 1548
1548 1549 if stats['binary']: # binary operations like chmod/rename etc
1549 1550 lbl = []
1550 1551 bin_op = 0 # undefined
1551 1552
1552 1553 # prefix with bin for binary files
1553 1554 if BIN_FILENODE in stats['ops']:
1554 1555 lbl += ['bin']
1555 1556
1556 1557 if NEW_FILENODE in stats['ops']:
1557 1558 lbl += [_('new file')]
1558 1559 bin_op = NEW_FILENODE
1559 1560 elif MOD_FILENODE in stats['ops']:
1560 1561 lbl += [_('mod')]
1561 1562 bin_op = MOD_FILENODE
1562 1563 elif DEL_FILENODE in stats['ops']:
1563 1564 lbl += [_('del')]
1564 1565 bin_op = DEL_FILENODE
1565 1566 elif RENAMED_FILENODE in stats['ops']:
1566 1567 lbl += [_('rename')]
1567 1568 bin_op = RENAMED_FILENODE
1568 1569
1569 1570 # chmod can go with other operations, so we add a + to lbl if needed
1570 1571 if CHMOD_FILENODE in stats['ops']:
1571 1572 lbl += [_('chmod')]
1572 1573 if bin_op == 0:
1573 1574 bin_op = CHMOD_FILENODE
1574 1575
1575 1576 lbl = '+'.join(lbl)
1576 1577 b_a = '<div class="bin bin%s %s" style="width:100%%">%s</div>' \
1577 1578 % (bin_op, cgen('a', a_v='', d_v=0), lbl)
1578 1579 b_d = '<div class="bin bin1" style="width:0%%"></div>'
1579 1580 return literal('<div style="width:%spx">%s%s</div>' % (width, b_a, b_d))
1580 1581
1581 1582 t = stats['added'] + stats['deleted']
1582 1583 unit = float(width) / (t or 1)
1583 1584
1584 1585 # needs > 9% of width to be visible or 0 to be hidden
1585 1586 a_p = max(9, unit * a) if a > 0 else 0
1586 1587 d_p = max(9, unit * d) if d > 0 else 0
1587 1588 p_sum = a_p + d_p
1588 1589
1589 1590 if p_sum > width:
1590 1591 #adjust the percentage to be == 100% since we adjusted to 9
1591 1592 if a_p > d_p:
1592 1593 a_p = a_p - (p_sum - width)
1593 1594 else:
1594 1595 d_p = d_p - (p_sum - width)
1595 1596
1596 1597 a_v = a if a > 0 else ''
1597 1598 d_v = d if d > 0 else ''
1598 1599
1599 1600 d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (
1600 1601 cgen('a', a_v, d_v), a_p, a_v
1601 1602 )
1602 1603 d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (
1603 1604 cgen('d', a_v, d_v), d_p, d_v
1604 1605 )
1605 1606 return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
1606 1607
1607 1608
1608 1609 def urlify_text(text_, safe=True):
1609 1610 """
1610 1611 Extrac urls from text and make html links out of them
1611 1612
1612 1613 :param text_:
1613 1614 """
1614 1615
1615 1616 url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@#.&+]'''
1616 1617 '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
1617 1618
1618 1619 def url_func(match_obj):
1619 1620 url_full = match_obj.groups()[0]
1620 1621 return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
1621 1622 _newtext = url_pat.sub(url_func, text_)
1622 1623 if safe:
1623 1624 return literal(_newtext)
1624 1625 return _newtext
1625 1626
1626 1627
1627 1628 def urlify_commits(text_, repository):
1628 1629 """
1629 1630 Extract commit ids from text and make link from them
1630 1631
1631 1632 :param text_:
1632 1633 :param repository: repo name to build the URL with
1633 1634 """
1634 1635 from pylons import url # doh, we need to re-import url to mock it later
1635 1636 URL_PAT = re.compile(r'(^|\s)([0-9a-fA-F]{12,40})($|\s)')
1636 1637
1637 1638 def url_func(match_obj):
1638 1639 commit_id = match_obj.groups()[1]
1639 1640 pref = match_obj.groups()[0]
1640 1641 suf = match_obj.groups()[2]
1641 1642
1642 1643 tmpl = (
1643 1644 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1644 1645 '%(commit_id)s</a>%(suf)s'
1645 1646 )
1646 1647 return tmpl % {
1647 1648 'pref': pref,
1648 1649 'cls': 'revision-link',
1649 1650 'url': url('changeset_home', repo_name=repository,
1650 1651 revision=commit_id, qualified=True),
1651 1652 'commit_id': commit_id,
1652 1653 'suf': suf
1653 1654 }
1654 1655
1655 1656 newtext = URL_PAT.sub(url_func, text_)
1656 1657
1657 1658 return newtext
1658 1659
1659 1660
1660 1661 def _process_url_func(match_obj, repo_name, uid, entry,
1661 1662 return_raw_data=False):
1662 1663 pref = ''
1663 1664 if match_obj.group().startswith(' '):
1664 1665 pref = ' '
1665 1666
1666 1667 issue_id = ''.join(match_obj.groups())
1667 1668 tmpl = (
1668 1669 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1669 1670 '%(issue-prefix)s%(id-repr)s'
1670 1671 '</a>')
1671 1672
1672 1673 (repo_name_cleaned,
1673 1674 parent_group_name) = RepoGroupModel().\
1674 1675 _get_group_name_and_parent(repo_name)
1675 1676
1676 1677 # variables replacement
1677 1678 named_vars = {
1678 1679 'id': issue_id,
1679 1680 'repo': repo_name,
1680 1681 'repo_name': repo_name_cleaned,
1681 1682 'group_name': parent_group_name
1682 1683 }
1683 1684 # named regex variables
1684 1685 named_vars.update(match_obj.groupdict())
1685 1686 _url = string.Template(entry['url']).safe_substitute(**named_vars)
1686 1687
1687 1688 data = {
1688 1689 'pref': pref,
1689 1690 'cls': 'issue-tracker-link',
1690 1691 'url': _url,
1691 1692 'id-repr': issue_id,
1692 1693 'issue-prefix': entry['pref'],
1693 1694 'serv': entry['url'],
1694 1695 }
1695 1696 if return_raw_data:
1696 1697 return {
1697 1698 'id': issue_id,
1698 1699 'url': _url
1699 1700 }
1700 1701 return tmpl % data
1701 1702
1702 1703
1703 1704 def process_patterns(text_string, repo_name, config=None):
1704 1705 repo = None
1705 1706 if repo_name:
1706 1707 # Retrieving repo_name to avoid invalid repo_name to explode on
1707 1708 # IssueTrackerSettingsModel but still passing invalid name further down
1708 1709 repo = Repository.get_by_repo_name(repo_name, cache=True)
1709 1710
1710 1711 settings_model = IssueTrackerSettingsModel(repo=repo)
1711 1712 active_entries = settings_model.get_settings(cache=True)
1712 1713
1713 1714 issues_data = []
1714 1715 newtext = text_string
1715 1716 for uid, entry in active_entries.items():
1716 1717 log.debug('found issue tracker entry with uid %s' % (uid,))
1717 1718
1718 1719 if not (entry['pat'] and entry['url']):
1719 1720 log.debug('skipping due to missing data')
1720 1721 continue
1721 1722
1722 1723 log.debug('issue tracker entry: uid: `%s` PAT:%s URL:%s PREFIX:%s'
1723 1724 % (uid, entry['pat'], entry['url'], entry['pref']))
1724 1725
1725 1726 try:
1726 1727 pattern = re.compile(r'%s' % entry['pat'])
1727 1728 except re.error:
1728 1729 log.exception(
1729 1730 'issue tracker pattern: `%s` failed to compile',
1730 1731 entry['pat'])
1731 1732 continue
1732 1733
1733 1734 data_func = partial(
1734 1735 _process_url_func, repo_name=repo_name, entry=entry, uid=uid,
1735 1736 return_raw_data=True)
1736 1737
1737 1738 for match_obj in pattern.finditer(text_string):
1738 1739 issues_data.append(data_func(match_obj))
1739 1740
1740 1741 url_func = partial(
1741 1742 _process_url_func, repo_name=repo_name, entry=entry, uid=uid)
1742 1743
1743 1744 newtext = pattern.sub(url_func, newtext)
1744 1745 log.debug('processed prefix:uid `%s`' % (uid,))
1745 1746
1746 1747 return newtext, issues_data
1747 1748
1748 1749
1749 1750 def urlify_commit_message(commit_text, repository=None):
1750 1751 """
1751 1752 Parses given text message and makes proper links.
1752 1753 issues are linked to given issue-server, and rest is a commit link
1753 1754
1754 1755 :param commit_text:
1755 1756 :param repository:
1756 1757 """
1757 1758 from pylons import url # doh, we need to re-import url to mock it later
1758 1759
1759 1760 def escaper(string):
1760 1761 return string.replace('<', '&lt;').replace('>', '&gt;')
1761 1762
1762 1763 newtext = escaper(commit_text)
1763 1764
1764 1765 # extract http/https links and make them real urls
1765 1766 newtext = urlify_text(newtext, safe=False)
1766 1767
1767 1768 # urlify commits - extract commit ids and make link out of them, if we have
1768 1769 # the scope of repository present.
1769 1770 if repository:
1770 1771 newtext = urlify_commits(newtext, repository)
1771 1772
1772 1773 # process issue tracker patterns
1773 1774 newtext, issues = process_patterns(newtext, repository or '')
1774 1775
1775 1776 return literal(newtext)
1776 1777
1777 1778
1778 1779 def rst(source, mentions=False):
1779 1780 return literal('<div class="rst-block">%s</div>' %
1780 1781 MarkupRenderer.rst(source, mentions=mentions))
1781 1782
1782 1783
1783 1784 def markdown(source, mentions=False):
1784 1785 return literal('<div class="markdown-block">%s</div>' %
1785 1786 MarkupRenderer.markdown(source, flavored=True,
1786 1787 mentions=mentions))
1787 1788
1788 1789 def renderer_from_filename(filename, exclude=None):
1789 1790 return MarkupRenderer.renderer_from_filename(filename, exclude=exclude)
1790 1791
1791 1792
1792 1793 def render(source, renderer='rst', mentions=False):
1793 1794 if renderer == 'rst':
1794 1795 return rst(source, mentions=mentions)
1795 1796 if renderer == 'markdown':
1796 1797 return markdown(source, mentions=mentions)
1797 1798
1798 1799
1799 1800 def commit_status(repo, commit_id):
1800 1801 return ChangesetStatusModel().get_status(repo, commit_id)
1801 1802
1802 1803
1803 1804 def commit_status_lbl(commit_status):
1804 1805 return dict(ChangesetStatus.STATUSES).get(commit_status)
1805 1806
1806 1807
1807 1808 def commit_time(repo_name, commit_id):
1808 1809 repo = Repository.get_by_repo_name(repo_name)
1809 1810 commit = repo.get_commit(commit_id=commit_id)
1810 1811 return commit.date
1811 1812
1812 1813
1813 1814 def get_permission_name(key):
1814 1815 return dict(Permission.PERMS).get(key)
1815 1816
1816 1817
1817 1818 def journal_filter_help():
1818 1819 return _(
1819 1820 'Example filter terms:\n' +
1820 1821 ' repository:vcs\n' +
1821 1822 ' username:marcin\n' +
1822 1823 ' action:*push*\n' +
1823 1824 ' ip:127.0.0.1\n' +
1824 1825 ' date:20120101\n' +
1825 1826 ' date:[20120101100000 TO 20120102]\n' +
1826 1827 '\n' +
1827 1828 'Generate wildcards using \'*\' character:\n' +
1828 1829 ' "repository:vcs*" - search everything starting with \'vcs\'\n' +
1829 1830 ' "repository:*vcs*" - search for repository containing \'vcs\'\n' +
1830 1831 '\n' +
1831 1832 'Optional AND / OR operators in queries\n' +
1832 1833 ' "repository:vcs OR repository:test"\n' +
1833 1834 ' "username:test AND repository:test*"\n'
1834 1835 )
1835 1836
1836 1837
1837 1838 def not_mapped_error(repo_name):
1838 1839 flash(_('%s repository is not mapped to db perhaps'
1839 1840 ' it was created or renamed from the filesystem'
1840 1841 ' please run the application again'
1841 1842 ' in order to rescan repositories') % repo_name, category='error')
1842 1843
1843 1844
1844 1845 def ip_range(ip_addr):
1845 1846 from rhodecode.model.db import UserIpMap
1846 1847 s, e = UserIpMap._get_ip_range(ip_addr)
1847 1848 return '%s - %s' % (s, e)
1848 1849
1849 1850
1850 1851 def form(url, method='post', needs_csrf_token=True, **attrs):
1851 1852 """Wrapper around webhelpers.tags.form to prevent CSRF attacks."""
1852 1853 if method.lower() != 'get' and needs_csrf_token:
1853 1854 raise Exception(
1854 1855 'Forms to POST/PUT/DELETE endpoints should have (in general) a ' +
1855 1856 'CSRF token. If the endpoint does not require such token you can ' +
1856 1857 'explicitly set the parameter needs_csrf_token to false.')
1857 1858
1858 1859 return wh_form(url, method=method, **attrs)
1859 1860
1860 1861
1861 1862 def secure_form(url, method="POST", multipart=False, **attrs):
1862 1863 """Start a form tag that points the action to an url. This
1863 1864 form tag will also include the hidden field containing
1864 1865 the auth token.
1865 1866
1866 1867 The url options should be given either as a string, or as a
1867 1868 ``url()`` function. The method for the form defaults to POST.
1868 1869
1869 1870 Options:
1870 1871
1871 1872 ``multipart``
1872 1873 If set to True, the enctype is set to "multipart/form-data".
1873 1874 ``method``
1874 1875 The method to use when submitting the form, usually either
1875 1876 "GET" or "POST". If "PUT", "DELETE", or another verb is used, a
1876 1877 hidden input with name _method is added to simulate the verb
1877 1878 over POST.
1878 1879
1879 1880 """
1880 1881 from webhelpers.pylonslib.secure_form import insecure_form
1881 1882 form = insecure_form(url, method, multipart, **attrs)
1882 1883 token = csrf_input()
1883 1884 return literal("%s\n%s" % (form, token))
1884 1885
1885 1886 def csrf_input():
1886 1887 return literal(
1887 1888 '<input type="hidden" id="{}" name="{}" value="{}">'.format(
1888 1889 csrf_token_key, csrf_token_key, get_csrf_token()))
1889 1890
1890 1891 def dropdownmenu(name, selected, options, enable_filter=False, **attrs):
1891 1892 select_html = select(name, selected, options, **attrs)
1892 1893 select2 = """
1893 1894 <script>
1894 1895 $(document).ready(function() {
1895 1896 $('#%s').select2({
1896 1897 containerCssClass: 'drop-menu',
1897 1898 dropdownCssClass: 'drop-menu-dropdown',
1898 1899 dropdownAutoWidth: true%s
1899 1900 });
1900 1901 });
1901 1902 </script>
1902 1903 """
1903 1904 filter_option = """,
1904 1905 minimumResultsForSearch: -1
1905 1906 """
1906 1907 input_id = attrs.get('id') or name
1907 1908 filter_enabled = "" if enable_filter else filter_option
1908 1909 select_script = literal(select2 % (input_id, filter_enabled))
1909 1910
1910 1911 return literal(select_html+select_script)
1911 1912
1912 1913
1913 1914 def get_visual_attr(tmpl_context_var, attr_name):
1914 1915 """
1915 1916 A safe way to get a variable from visual variable of template context
1916 1917
1917 1918 :param tmpl_context_var: instance of tmpl_context, usually present as `c`
1918 1919 :param attr_name: name of the attribute we fetch from the c.visual
1919 1920 """
1920 1921 visual = getattr(tmpl_context_var, 'visual', None)
1921 1922 if not visual:
1922 1923 return
1923 1924 else:
1924 1925 return getattr(visual, attr_name, None)
1925 1926
1926 1927
1927 1928 def get_last_path_part(file_node):
1928 1929 if not file_node.path:
1929 1930 return u''
1930 1931
1931 1932 path = safe_unicode(file_node.path.split('/')[-1])
1932 1933 return u'../' + path
1933 1934
1934 1935
1935 1936 def route_path(*args, **kwds):
1936 1937 """
1937 1938 Wrapper around pyramids `route_path` function. It is used to generate
1938 1939 URLs from within pylons views or templates. This will be removed when
1939 1940 pyramid migration if finished.
1940 1941 """
1941 1942 req = get_current_request()
1942 1943 return req.route_path(*args, **kwds)
1943 1944
1944 1945
1945 1946 def static_url(*args, **kwds):
1946 1947 """
1947 1948 Wrapper around pyramids `route_path` function. It is used to generate
1948 1949 URLs from within pylons views or templates. This will be removed when
1949 1950 pyramid migration if finished.
1950 1951 """
1951 1952 req = get_current_request()
1952 1953 return req.static_url(*args, **kwds)
1953 1954
1954 1955
1955 1956 def resource_path(*args, **kwds):
1956 1957 """
1957 1958 Wrapper around pyramids `route_path` function. It is used to generate
1958 1959 URLs from within pylons views or templates. This will be removed when
1959 1960 pyramid migration if finished.
1960 1961 """
1961 1962 req = get_current_request()
1962 1963 return req.resource_path(*args, **kwds)
@@ -1,139 +1,139 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <!DOCTYPE html>
3 3
4 4 <%
5 5 c.template_context['repo_name'] = getattr(c, 'repo_name', '')
6 6
7 7 if hasattr(c, 'rhodecode_db_repo'):
8 8 c.template_context['repo_type'] = c.rhodecode_db_repo.repo_type
9 9 c.template_context['repo_landing_commit'] = c.rhodecode_db_repo.landing_rev[1]
10 10
11 11 if getattr(c, 'rhodecode_user', None) and c.rhodecode_user.user_id:
12 12 c.template_context['rhodecode_user']['username'] = c.rhodecode_user.username
13 13 c.template_context['rhodecode_user']['email'] = c.rhodecode_user.email
14 14 c.template_context['rhodecode_user']['notification_status'] = c.rhodecode_user.get_instance().user_data.get('notification_status', True)
15 15
16 16 c.template_context['visual']['default_renderer'] = h.get_visual_attr(c, 'default_renderer')
17 17 %>
18 18
19 19 <html xmlns="http://www.w3.org/1999/xhtml">
20 20 <head>
21 21 <title>${self.title()}</title>
22 22 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
23 23 <%def name="robots()">
24 24 <meta name="robots" content="index, nofollow"/>
25 25 </%def>
26 26 ${self.robots()}
27 27 <link rel="icon" href="${h.asset('images/favicon.ico', ver=c.rhodecode_version_hash)}" sizes="16x16 32x32" type="image/png" />
28 28
29 29 ## CSS definitions
30 30 <%def name="css()">
31 31 <link rel="stylesheet" type="text/css" href="${h.asset('css/style.css', ver=c.rhodecode_version_hash)}" media="screen"/>
32 32 <!--[if lt IE 9]>
33 33 <link rel="stylesheet" type="text/css" href="${h.asset('css/ie.css', ver=c.rhodecode_version_hash)}" media="screen"/>
34 34 <![endif]-->
35 35 ## EXTRA FOR CSS
36 36 ${self.css_extra()}
37 37 </%def>
38 38 ## CSS EXTRA - optionally inject some extra CSS stuff needed for specific websites
39 39 <%def name="css_extra()">
40 40 </%def>
41 41
42 42 ${self.css()}
43 43
44 44 ## JAVASCRIPT
45 45 <%def name="js()">
46 46 <script src="${h.asset('js/rhodecode/i18n/%s.js' % c.language, ver=c.rhodecode_version_hash)}"></script>
47 47 <script type="text/javascript">
48 48 // register templateContext to pass template variables to JS
49 49 var templateContext = ${h.json.dumps(c.template_context)|n};
50 50
51 51 var REPO_NAME = "${getattr(c, 'repo_name', '')}";
52 52 %if hasattr(c, 'rhodecode_db_repo'):
53 53 var REPO_LANDING_REV = '${c.rhodecode_db_repo.landing_rev[1]}';
54 54 var REPO_TYPE = '${c.rhodecode_db_repo.repo_type}';
55 55 %else:
56 56 var REPO_LANDING_REV = '';
57 57 var REPO_TYPE = '';
58 58 %endif
59 59 var APPLICATION_URL = "${h.url('home').rstrip('/')}";
60 60 var ASSET_URL = "${h.asset('')}";
61 61 var DEFAULT_RENDERER = "${h.get_visual_attr(c, 'default_renderer')}";
62 62 var CSRF_TOKEN = "${getattr(c, 'csrf_token', '')}";
63 63 % if getattr(c, 'rhodecode_user', None):
64 64 var USER = {name:'${c.rhodecode_user.username}'};
65 65 % else:
66 66 var USER = {name:null};
67 67 % endif
68 68
69 69 var APPENLIGHT = {
70 70 enabled: ${'true' if getattr(c, 'appenlight_enabled', False) else 'false'},
71 71 key: '${getattr(c, "appenlight_api_public_key", "")}',
72 72 % if getattr(c, 'appenlight_server_url', None):
73 73 serverUrl: '${getattr(c, "appenlight_server_url", "")}',
74 74 % endif
75 75 requestInfo: {
76 76 % if getattr(c, 'rhodecode_user', None):
77 77 ip: '${c.rhodecode_user.ip_addr}',
78 78 username: '${c.rhodecode_user.username}'
79 79 % endif
80 80 }
81 81 };
82 82 </script>
83 83 <!--[if lt IE 9]>
84 84 <script language="javascript" type="text/javascript" src="${h.asset('js/excanvas.min.js')}"></script>
85 85 <![endif]-->
86 86 <script language="javascript" type="text/javascript" src="${h.asset('js/rhodecode/routes.js', ver=c.rhodecode_version_hash)}"></script>
87 87 <script language="javascript" type="text/javascript" src="${h.asset('js/scripts.js', ver=c.rhodecode_version_hash)}"></script>
88 ## avoide esaping the %N
89 <script>CodeMirror.modeURL = "${h.asset('') + 'js/mode/%N/%N.js'}";</script>
88 ## avoide escaping the %N
89 <script>CodeMirror.modeURL = "${h.asset('') + 'js/mode/%N/%N.js?ver='+c.rhodecode_version_hash}";</script>
90 90
91 91
92 92 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
93 93 ${self.js_extra()}
94 94
95 95 <script type="text/javascript">
96 96 $(document).ready(function(){
97 97 show_more_event();
98 98 timeagoActivate();
99 99 })
100 100 </script>
101 101
102 102 </%def>
103 103
104 104 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
105 105 <%def name="js_extra()"></%def>
106 106 ${self.js()}
107 107
108 108 <%def name="head_extra()"></%def>
109 109 ${self.head_extra()}
110 110 <%include file="/base/plugins_base.html"/>
111 111
112 112 ## extra stuff
113 113 %if c.pre_code:
114 114 ${c.pre_code|n}
115 115 %endif
116 116 </head>
117 117 <body id="body">
118 118 <noscript>
119 119 <div class="noscript-error">
120 120 ${_('Please enable JavaScript to use RhodeCode Enterprise')}
121 121 </div>
122 122 </noscript>
123 123 ## IE hacks
124 124 <!--[if IE 7]>
125 125 <script>$(document.body).addClass('ie7')</script>
126 126 <![endif]-->
127 127 <!--[if IE 8]>
128 128 <script>$(document.body).addClass('ie8')</script>
129 129 <![endif]-->
130 130 <!--[if IE 9]>
131 131 <script>$(document.body).addClass('ie9')</script>
132 132 <![endif]-->
133 133
134 134 ${next.body()}
135 135 %if c.post_code:
136 136 ${c.post_code|n}
137 137 %endif
138 138 </body>
139 139 </html>
@@ -1,1162 +1,1162 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%namespace name="base" file="/base/base.html"/>
3 3 <%inherit file="/debug_style/index.html"/>
4 4
5 5 <%def name="breadcrumbs_links()">
6 6 ${h.link_to(_('Style'), h.url('debug_style_home'))}
7 7 &raquo;
8 8 ${c.active}
9 9 </%def>
10 10
11 11 <%def name="js_extra()">
12 <script type="text/javascript" src="${h.asset('js/mergerly.js')}"></script>
12 <script type="text/javascript" src="${h.asset('js/mergerly.js', ver=c.rhodecode_version_hash)}"></script>
13 13 </%def>
14 14
15 15 <%def name="css_extra()">
16 <link rel="stylesheet" type="text/css" href="${h.asset('css/mergerly.css')}"/>
16 <link rel="stylesheet" type="text/css" href="${h.asset('css/mergerly.css', ver=c.rhodecode_version_hash)}"/>
17 17 </%def>
18 18
19 19
20 20 <%def name="real_main()">
21 21 <div class="box">
22 22 <div class="title">
23 23 ${self.breadcrumbs()}
24 24 </div>
25 25
26 26 ##main
27 27 <div class='sidebar-col-wrapper'>
28 28 ${self.sidebar()}
29 29
30 30 <div class="main-content">
31 31
32 32
33 33
34 34 <h2>Code Blocks</h2>
35 35
36 36 <dl class="dl-horizontal">
37 37 <dt><code>.codeblock</code></dt>
38 38 <dd>Used as a wrapping element around <code>.code-header</code> and
39 39 <code>.code-body</code>. Used to show the content of a file or a
40 40 Gist.</dd>
41 41
42 42 <dt><code>.diffblock</code></dt>
43 43 <dd>Used as a wrapping element to show a diff in a Commit or Pull
44 44 Request page. Contains usually <code>.code-header</code>,
45 45 <code>.code-body</code> and in the edit case a <code>.message</code>.
46 46 </dd>
47 47 </dl>
48 48
49 49
50 50 <p>Code Blocks are used in the following areas:</p>
51 51
52 52 <ul>
53 53 <li>Commit: Showing the Diff (still called Changeset in a few
54 54 places).</li>
55 55 <li>File: Display a file, annotations, and edit a file.</li>
56 56 <li>Gist: Show the Gist and edit it.</li>
57 57 <li>Pull Request: Display the Diff of a Pull Request.</li>
58 58 </ul>
59 59
60 60
61 61
62 62 <!--
63 63 Compare Commits
64 64 -->
65 65 <h2>Compare Commits</h2>
66 66
67 67 <div id="c-e589e34d6be8-5ab783e6d81b" class="diffblock margined comm">
68 68 <div class="code-header">
69 69 <div title="Go back to changed files overview">
70 70 <a href="#changes_box">
71 71 <i class="icon-circle-arrow-up"></i>
72 72 </a>
73 73 </div>
74 74 <div class="changeset_header">
75 75 <div class="changeset_file">
76 76 <i class="icon-file"></i>
77 77 <a href="/example/files/e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d/rhodecode/public/css/code-block.less">rhodecode/public/css/code-block.less</a>
78 78 </div>
79 79 <div class="diff-actions">
80 80 <a href="/example/diff/rhodecode/public/css/code-block.less?fulldiff=1&amp;diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&amp;diff=diff&amp;diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Show full diff for this file">
81 81 <img class="icon" src="/images/icons/page_white_go.png">
82 82 </a>
83 83 <a href="/example/diff-2way/rhodecode/public/css/code-block.less?fulldiff=1&amp;diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&amp;diff=diff&amp;diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Show full side-by-side diff for this file">
84 84 <img class="icon" src="/images/icons/application_double.png">
85 85 </a>
86 86 <a href="/example/diff/rhodecode/public/css/code-block.less?diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&amp;diff=raw&amp;diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Raw diff" tt_title="Raw diff">
87 87 <img class="icon" src="/images/icons/page_white.png">
88 88 </a>
89 89 <a href="/example/diff/rhodecode/public/css/code-block.less?diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&amp;diff=download&amp;diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Download diff">
90 90 <img class="icon" src="/images/icons/page_save.png">
91 91 </a>
92 92 <a class="tooltip" href="/example/changeset/d12301bafcc0aea15c9283d3af018daee2b04cd9...80ead1899f50a894889e19ffeb49c9cebf5bf045?c-e589e34d6be8-5ab783e6d81b=WS%3A1&amp;c-e589e34d6be8-5ab783e6d81b=C%3A3#c-e589e34d6be8-5ab783e6d81b" title="Ignore white space"><img alt="Ignore white space" class="icon" src="/images/icons/text_strikethrough.png"></a>
93 93 <a class="tooltip" href="/example/changeset/d12301bafcc0aea15c9283d3af018daee2b04cd9...80ead1899f50a894889e19ffeb49c9cebf5bf045?c-e589e34d6be8-5ab783e6d81b=C%3A6#c-e589e34d6be8-5ab783e6d81b" title="increase diff context to 6 lines"><img alt="increase diff context to 6 lines" class="icon" src="/images/icons/table_add.png"></a>
94 94 </div>
95 95 <span>
96 96 <label>
97 97 Show inline comments
98 98 <input checked="checked" class="show-inline-comments" id="" id_for="c-e589e34d6be8-5ab783e6d81b" name="" type="checkbox" value="1">
99 99 </label>
100 100 </span>
101 101 </div>
102 102 </div>
103 103 <div class="code-body">
104 104 <div class="full_f_path" path="rhodecode/public/css/code-block.less"></div>
105 105 <table class="code-difftable">
106 106 <tbody><tr class="line context">
107 107 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o...">...</a></td>
108 108 <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n...">...</a></td>
109 109 <td class="code no-comment">
110 110 <pre>@@ -391,7 +391,7 @@
111 111 </pre>
112 112 </td>
113 113 </tr>
114 114 <tr class="line unmod">
115 115 <td id="rhodecodepubliccsscode-blockless_o391" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o391">391</a></td>
116 116 <td id="rhodecodepubliccsscode-blockless_n391" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n391">391</a></td>
117 117 <td class="code no-comment">
118 118 <pre>} /* Existing line, it might have a quite long content actually and in this case we might need some horizontal scrolling. The remaining text here is just used to make this line very long.
119 119 </pre>
120 120 </td>
121 121 </tr>
122 122 <tr class="line unmod">
123 123 <td id="rhodecodepubliccsscode-blockless_o392" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o392">392</a></td>
124 124 <td id="rhodecodepubliccsscode-blockless_n392" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n392">392</a></td>
125 125 <td class="code no-comment">
126 126 <pre></pre>
127 127 </td>
128 128 </tr>
129 129 <tr class="line unmod">
130 130 <td id="rhodecodepubliccsscode-blockless_o393" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o393">393</a></td>
131 131 <td id="rhodecodepubliccsscode-blockless_n393" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n393">393</a></td>
132 132 <td class="code no-comment">
133 133 <pre>.code-body.textarea.editor,
134 134 </pre>
135 135 </td>
136 136 </tr>
137 137 <tr class="line del">
138 138 <td id="rhodecodepubliccsscode-blockless_o394" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o394">394</a></td>
139 139 <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n"></a></td>
140 140 <td class="code no-comment">
141 141 <pre>div.code-body{
142 142 </pre>
143 143 </td>
144 144 </tr>
145 145 <tr class="line add">
146 146 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td>
147 147 <td id="rhodecodepubliccsscode-blockless_n394" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n394">394</a></td>
148 148 <td class="code no-comment">
149 149 <pre>div.code-body<ins> </ins>{
150 150 </pre>
151 151 </td>
152 152 </tr>
153 153 <tr class="line unmod">
154 154 <td id="rhodecodepubliccsscode-blockless_o395" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o395">395</a></td>
155 155 <td id="rhodecodepubliccsscode-blockless_n395" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n395">395</a></td>
156 156 <td class="code no-comment">
157 157 <pre> float: left;
158 158 </pre>
159 159 </td>
160 160 </tr>
161 161 <tr class="line unmod">
162 162 <td id="rhodecodepubliccsscode-blockless_o396" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o396">396</a></td>
163 163 <td id="rhodecodepubliccsscode-blockless_n396" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n396">396</a></td>
164 164 <td class="code no-comment">
165 165 <pre> position: relative;
166 166 </pre>
167 167 </td>
168 168 </tr>
169 169 <tr class="line unmod">
170 170 <td id="rhodecodepubliccsscode-blockless_o397" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o397">397</a></td>
171 171 <td id="rhodecodepubliccsscode-blockless_n397" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n397">397</a></td>
172 172 <td class="code no-comment">
173 173 <pre> max-width: none;
174 174 </pre>
175 175 </td>
176 176 </tr>
177 177 <tr class="line context">
178 178 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o...">...</a></td>
179 179 <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n...">...</a></td>
180 180 <td class="code no-comment">
181 181 <pre>@@ -399,3 +399,6 @@
182 182 </pre>
183 183 </td>
184 184 </tr>
185 185 <tr class="line unmod">
186 186 <td id="rhodecodepubliccsscode-blockless_o399" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o399">399</a></td>
187 187 <td id="rhodecodepubliccsscode-blockless_n399" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n399">399</a></td>
188 188 <td class="code no-comment">
189 189 <pre> box-sizing: border-box;
190 190 </pre>
191 191 </td>
192 192 </tr>
193 193 <tr class="line unmod">
194 194 <td id="rhodecodepubliccsscode-blockless_o400" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o400">400</a></td>
195 195 <td id="rhodecodepubliccsscode-blockless_n400" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n400">400</a></td>
196 196 <td class="code no-comment">
197 197 <pre>}
198 198 </pre>
199 199 </td>
200 200 </tr>
201 201 <tr class="line unmod">
202 202 <td id="rhodecodepubliccsscode-blockless_o401" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o401">401</a></td>
203 203 <td id="rhodecodepubliccsscode-blockless_n401" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n401">401</a></td>
204 204 <td class="code no-comment">
205 205 <pre></pre>
206 206 </td>
207 207 </tr>
208 208 <tr class="line add">
209 209 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td>
210 210 <td id="rhodecodepubliccsscode-blockless_n402" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n402">402</a></td>
211 211 <td class="code no-comment">
212 212 <pre>.code-body td{
213 213 </pre>
214 214 </td>
215 215 </tr>
216 216 <tr class="line add">
217 217 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td>
218 218 <td id="rhodecodepubliccsscode-blockless_n403" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n403">403</a></td>
219 219 <td class="code no-comment">
220 220 <pre> line-height: 1.2em;
221 221 </pre>
222 222 </td>
223 223 </tr>
224 224 <tr class="line add">
225 225 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td>
226 226 <td id="rhodecodepubliccsscode-blockless_n404" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n404">404</a></td>
227 227 <td class="code no-comment">
228 228 <pre>}
229 229 </pre>
230 230 </td>
231 231 </tr>
232 232 <tr class="line context">
233 233 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o...">...</a></td>
234 234 <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n...">...</a></td>
235 235 <td class="code no-comment">
236 236 <pre> No newline at end of file
237 237 </pre>
238 238 </td>
239 239 </tr>
240 240 </tbody></table>
241 241 </div>
242 242 </div>
243 243
244 244
245 245
246 246
247 247
248 248
249 249 <!--
250 250 Pull Request
251 251 -->
252 252
253 253 <h2>Pull Request</h2>
254 254
255 255 <div class="cs_files">
256 256 <table class="compare_view_files">
257 257
258 258 <tbody><tr class="cs_M collapse_file" fid="c--5f1d017cf13b">
259 259 <td class="cs_icon_td">
260 260 <span class="collapse_file_icon" fid="c--5f1d017cf13b"></span>
261 261 </td>
262 262 <td class="cs_icon_td">
263 263 <div class="flag_status not_reviewed hidden"></div>
264 264 </td>
265 265 <td id="a_c--5f1d017cf13b">
266 266 <a class="compare_view_filepath" href="#a_c--5f1d017cf13b">
267 267 rhodecode/public/css/main.less
268 268 </a>
269 269 <span id="diff_c--5f1d017cf13b" class="diff_links" style="">
270 270 <a href="/example/diff/rhodecode/public/css/main.less?fulldiff=1&amp;diff1=f73e9946825c8a7ef2c1178cd1e67986d5831f8f&amp;diff=diff&amp;diff2=27eb56cf467ca849112536d62decb2ed020b3ebc">
271 271 Unified Diff
272 272 </a>
273 273 |
274 274 <a href="/example/diff-2way/rhodecode/public/css/main.less?fulldiff=1&amp;diff1=f73e9946825c8a7ef2c1178cd1e67986d5831f8f&amp;diff=diff&amp;diff2=27eb56cf467ca849112536d62decb2ed020b3ebc">
275 275 Side-by-side Diff
276 276 </a>
277 277 </span>
278 278 </td>
279 279 <td>
280 280 <div class="changes pull-right"><div style="width:100px"><div class="added top-left-rounded-corner-mid bottom-left-rounded-corner-mid" style="width:33.3333333333%">1</div><div class="deleted top-right-rounded-corner-mid bottom-right-rounded-corner-mid" style="width:66.6666666667%">2</div></div></div>
281 281 <div class="comment-bubble pull-right" data-path="rhodecode/public/css/main.less">
282 282 <i class="icon-comment"></i>
283 283 </div>
284 284 </td>
285 285 </tr>
286 286 <tr id="tr_c--5f1d017cf13b">
287 287 <td></td>
288 288 <td></td>
289 289 <td class="injected_diff" colspan="2">
290 290
291 291 <div class="diff-container" id="diff-container-140360026534904">
292 292 <div id="c--5f1d017cf13b_target"></div>
293 293 <div id="c--5f1d017cf13b" class="diffblock margined comm">
294 294 <div class="code-body">
295 295 <div class="full_f_path" path="rhodecode/public/css/main.less" style="display: none;"></div>
296 296 <table class="code-difftable">
297 297 <tbody><tr class="line context">
298 298 <td class="lineno old"><a href="#rhodecodepubliccssmainless_o...">...</a></td>
299 299 <td class="lineno new"><a href="#rhodecodepubliccssmainless_n...">...</a></td>
300 300 <td class="code ">
301 301 <pre>@@ -2110,7 +2110,6 @@
302 302 </pre>
303 303 </td>
304 304 </tr>
305 305 <tr class="line unmod">
306 306 <td id="rhodecodepubliccssmainless_o2110" class="lineno old"><a href="#rhodecodepubliccssmainless_o2110">2110</a></td>
307 307 <td id="rhodecodepubliccssmainless_n2110" class="lineno new"><a href="#rhodecodepubliccssmainless_n2110">2110</a></td>
308 308 <td class="code ">
309 309 <pre><span class="tab-escape"> </span>width: auto !important;
310 310 </pre>
311 311 </td>
312 312 </tr>
313 313 <tr class="line unmod">
314 314 <td id="rhodecodepubliccssmainless_o2111" class="lineno old"><a href="#rhodecodepubliccssmainless_o2111">2111</a></td>
315 315 <td id="rhodecodepubliccssmainless_n2111" class="lineno new"><a href="#rhodecodepubliccssmainless_n2111">2111</a></td>
316 316 <td class="code ">
317 317 <pre><span class="tab-escape"> </span>min-width: 160px;
318 318 </pre>
319 319 </td>
320 320 </tr>
321 321 <tr class="line unmod">
322 322 <td id="rhodecodepubliccssmainless_o2112" class="lineno old"><a href="#rhodecodepubliccssmainless_o2112">2112</a></td>
323 323 <td id="rhodecodepubliccssmainless_n2112" class="lineno new"><a href="#rhodecodepubliccssmainless_n2112">2112</a></td>
324 324 <td class="code ">
325 325 <pre><span class="tab-escape"> </span>margin: @padding @padding @padding 0;
326 326 </pre>
327 327 </td>
328 328 </tr>
329 329 <tr class="line del">
330 330 <td id="rhodecodepubliccssmainless_o2113" class="lineno old"><a href="#rhodecodepubliccssmainless_o2113">2113</a></td>
331 331 <td class="lineno new"><a href="#rhodecodepubliccssmainless_n"></a></td>
332 332 <td class="code ">
333 333 <pre><span class="tab-escape"> </span>padding: .9em; /* Old comment which was making this line a very long line so that we might have to deal with it by either adding horizontal scrolling or some smart way of breaking this line. */
334 334 </pre>
335 335 </td>
336 336 </tr>
337 337 <tr class="line unmod">
338 338 <td id="rhodecodepubliccssmainless_o2114" class="lineno old"><a href="#rhodecodepubliccssmainless_o2114">2114</a></td>
339 339 <td id="rhodecodepubliccssmainless_n2113" class="lineno new"><a href="#rhodecodepubliccssmainless_n2113">2113</a></td>
340 340 <td class="code ">
341 341 <pre> line-height: 1em;
342 342 </pre>
343 343 </td>
344 344 </tr>
345 345 <tr class="line unmod">
346 346 <td id="rhodecodepubliccssmainless_o2115" class="lineno old"><a href="#rhodecodepubliccssmainless_o2115">2115</a></td>
347 347 <td id="rhodecodepubliccssmainless_n2114" class="lineno new"><a href="#rhodecodepubliccssmainless_n2114">2114</a></td>
348 348 <td class="code ">
349 349 <pre><span class="tab-escape"> </span>z-index: 100;//js sets the menu below it to 9999
350 350 </pre>
351 351 </td>
352 352 </tr>
353 353 <tr class="line unmod">
354 354 <td id="rhodecodepubliccssmainless_o2116" class="lineno old"><a href="#rhodecodepubliccssmainless_o2116">2116</a></td>
355 355 <td id="rhodecodepubliccssmainless_n2115" class="lineno new"><a href="#rhodecodepubliccssmainless_n2115">2115</a></td>
356 356 <td class="code ">
357 357 <pre><span class="tab-escape"> </span>background-color: white;
358 358 </pre>
359 359 </td>
360 360 </tr>
361 361 <tr class="line context">
362 362 <td class="lineno old"><a href="#rhodecodepubliccssmainless_o...">...</a></td>
363 363 <td class="lineno new"><a href="#rhodecodepubliccssmainless_n...">...</a></td>
364 364 <td class="code ">
365 365 <pre>@@ -2118,7 +2117,7 @@
366 366 </pre>
367 367 </td>
368 368 </tr>
369 369 <tr class="line unmod">
370 370 <td id="rhodecodepubliccssmainless_o2118" class="lineno old"><a href="#rhodecodepubliccssmainless_o2118">2118</a></td>
371 371 <td id="rhodecodepubliccssmainless_n2117" class="lineno new"><a href="#rhodecodepubliccssmainless_n2117">2117</a></td>
372 372 <td class="code ">
373 373 <pre></pre>
374 374 </td>
375 375 </tr>
376 376 <tr class="line unmod">
377 377 <td id="rhodecodepubliccssmainless_o2119" class="lineno old"><a href="#rhodecodepubliccssmainless_o2119">2119</a></td>
378 378 <td id="rhodecodepubliccssmainless_n2118" class="lineno new"><a href="#rhodecodepubliccssmainless_n2118">2118</a></td>
379 379 <td class="code ">
380 380 <pre><span class="tab-escape"> </span>a {
381 381 </pre>
382 382 </td>
383 383 </tr>
384 384 <tr class="line unmod">
385 385 <td id="rhodecodepubliccssmainless_o2120" class="lineno old"><a href="#rhodecodepubliccssmainless_o2120">2120</a></td>
386 386 <td id="rhodecodepubliccssmainless_n2119" class="lineno new"><a href="#rhodecodepubliccssmainless_n2119">2119</a></td>
387 387 <td class="code ">
388 388 <pre><span class="tab-escape"> </span><span class="tab-escape"> </span>display:block;
389 389 </pre>
390 390 </td>
391 391 </tr>
392 392 <tr class="line del">
393 393 <td id="rhodecodepubliccssmainless_o2121" class="lineno old"><a href="#rhodecodepubliccssmainless_o2121">2121</a></td>
394 394 <td class="lineno new"><a href="#rhodecodepubliccssmainless_n"></a></td>
395 395 <td class="code ">
396 396 <pre><span class="tab-escape"> </span><del><span< del=""> <del>class=</del><del>"tab-escape"</del><del>&gt; </del>padding: <del>0</del>;
397 397 </span<></del></pre>
398 398 </td>
399 399 </tr>
400 400 <tr class="line add">
401 401 <td class="lineno old"><a href="#rhodecodepubliccssmainless_o"></a></td>
402 402 <td id="rhodecodepubliccssmainless_n2120" class="lineno new"><a href="#rhodecodepubliccssmainless_n2120">2120</a></td>
403 403 <td class="code ">
404 404 <pre><span class="tab-escape"> </span><ins> </ins> <ins> </ins><ins> </ins>padding: <ins>.9em</ins>;
405 405 </pre>
406 406 </td>
407 407 </tr>
408 408 <tr class="line unmod">
409 409 <td id="rhodecodepubliccssmainless_o2122" class="lineno old"><a href="#rhodecodepubliccssmainless_o2122">2122</a></td>
410 410 <td id="rhodecodepubliccssmainless_n2121" class="lineno new"><a href="#rhodecodepubliccssmainless_n2121">2121</a></td>
411 411 <td class="code ">
412 412 <pre></pre>
413 413 </td>
414 414 </tr>
415 415 <tr class="line unmod">
416 416 <td id="rhodecodepubliccssmainless_o2123" class="lineno old"><a href="#rhodecodepubliccssmainless_o2123">2123</a></td>
417 417 <td id="rhodecodepubliccssmainless_n2122" class="lineno new"><a href="#rhodecodepubliccssmainless_n2122">2122</a></td>
418 418 <td class="code ">
419 419 <pre><span class="tab-escape"> </span><span class="tab-escape"> </span>&amp;:after {
420 420 </pre>
421 421 </td>
422 422 </tr>
423 423 <tr class="line unmod">
424 424 <td id="rhodecodepubliccssmainless_o2124" class="lineno old"><a href="#rhodecodepubliccssmainless_o2124">2124</a></td>
425 425 <td id="rhodecodepubliccssmainless_n2123" class="lineno new"><a href="#rhodecodepubliccssmainless_n2123">2123</a></td>
426 426 <td class="code ">
427 427 <pre><span class="tab-escape"> </span><span class="tab-escape"> </span><span class="tab-escape"> </span>content: "\00A0\25BE";
428 428 </pre>
429 429 </td>
430 430 </tr>
431 431 </tbody></table>
432 432 </div>
433 433 </div>
434 434 </div>
435 435
436 436 </td>
437 437 </tr>
438 438 </tbody></table>
439 439 </div>
440 440
441 441
442 442
443 443
444 444
445 445
446 446
447 447
448 448
449 449 <!--
450 450 File View
451 451 -->
452 452
453 453 ##TODO: lisa: I believe this needs to be updated as the layout has changed.
454 454 <h2>File View</h2>
455 455
456 456 <div class="codeblock">
457 457 <div class="code-header">
458 458 <div class="stats">
459 459 <div class="img">
460 460 <i class="icon-file"></i>
461 461 <span class="revision_id item"><a href="/example/changeset/fc252256eb0fcb4f2613e66f0126ea27967ae28c">r5487:fc252256eb0f</a></span>
462 462 <span>1.2 KiB</span>
463 463 <span class="item last">text/x-python</span>
464 464 <div class="buttons">
465 465
466 466 <a id="file_history_overview" class="btn btn-mini" href="#">
467 467 <i class="icon-time"></i> history
468 468 </a>
469 469 <a id="file_history_overview_full" class="btn btn-mini" style="display: none" href="/example/changelog/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py">
470 470 <i class="icon-time"></i> show full history
471 471 </a>
472 472 <a class="btn btn-mini" href="/example/annotate/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py">annotation</a>
473 473 <a class="btn btn-mini" href="/example/raw/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py">raw</a>
474 474 <a class="btn btn-mini" href="/example/rawfile/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py">
475 475 <i class="icon-archive"></i> download
476 476 </a>
477 477
478 478 <a class="btn btn-mini disabled tooltip" href="#" title="Editing files allowed only when on branch head commit">edit</a>
479 479 <a class="btn btn-mini btn-danger disabled tooltip" href="#" title="Deleting files allowed only when on branch head commit">delete</a>
480 480 </div>
481 481 </div>
482 482 </div>
483 483 <div id="file_history_container"></div>
484 484 <div class="author">
485 485 <div class="gravatar">
486 486 <img alt="gravatar" src="https://secure.gravatar.com/avatar/99e27b99c64003ca8c9875c9e3843495?d=identicon&amp;s=32" height="16" width="16">
487 487 </div>
488 488 <div title="Marcin Kuzminski <marcin@python-works.com>" class="user">Marcin Kuzminski - <span class="tooltip" title="Wed, 02 Jul 2014 08:48:15">6m and 12d ago</span></div>
489 489 </div>
490 490 <div id="trimmed_message_box" class="commit">License changes</div>
491 491 <div id="message_expand" style="display: none;">
492 492 <i class="icon-resize-vertical"></i>
493 493 expand
494 494 <i class="icon-resize-vertical"></i>
495 495 </div>
496 496 </div>
497 497 <div class="code-body">
498 498 <table class="code-highlighttable"><tbody><tr><td class="linenos"><div class="linenodiv"><pre><a href="#L1"> 1</a>
499 499 <a href="#L2"> 2</a>
500 500 <a href="#L3"> 3</a>
501 501 <a href="#L4"> 4</a>
502 502 <a href="#L5"> 5</a>
503 503 <a href="#L6"> 6</a>
504 504 <a href="#L7"> 7</a>
505 505 <a href="#L8"> 8</a>
506 506 <a href="#L9"> 9</a>
507 507 <a href="#L10">10</a>
508 508 <a href="#L11">11</a>
509 509 <a href="#L12">12</a>
510 510 <a href="#L13">13</a>
511 511 <a href="#L14">14</a>
512 512 <a href="#L15">15</a>
513 513 <a href="#L16">16</a>
514 514 <a href="#L17">17</a>
515 515 <a href="#L18">18</a>
516 516 <a href="#L19">19</a>
517 517 <a href="#L20">20</a>
518 518 <a href="#L21">21</a>
519 519 <a href="#L22">22</a>
520 520 <a href="#L23">23</a>
521 521 <a href="#L24">24</a>
522 522 <a href="#L25">25</a>
523 523 <a href="#L26">26</a>
524 524 <a href="#L27">27</a>
525 525 <a href="#L28">28</a>
526 526 <a href="#L29">29</a>
527 527 <a href="#L30">30</a>
528 528 <a href="#L31">31</a>
529 529 <a href="#L32">32</a>
530 530 <a href="#L33">33</a>
531 531 <a href="#L34">34</a>
532 532 <a href="#L35">35</a>
533 533 <a href="#L36">36</a>
534 534 <a href="#L37">37</a>
535 535 <a href="#L38">38</a>
536 536 <a href="#L39">39</a>
537 537 <a href="#L40">40</a>
538 538 <a href="#L41">41</a>
539 539 <a href="#L42">42</a></pre></div></td><td id="hlcode" class="code"><div class="code-highlight"><pre><div id="L1"><a name="L-1"></a><span class="c"># -*- coding: utf-8 -*-</span>
540 540 </div><div id="L2"><a name="L-2"></a>
541 541 </div><div id="L3"><a name="L-3"></a><span class="c"># Published under Business Source License.</span>
542 542 </div><div id="L4"><a name="L-4"></a><span class="c"># Read the full license text at https://rhodecode.com/licenses.</span>
543 543 </div><div id="L5"><a name="L-5"></a><span class="sd">"""</span>
544 544 </div><div id="L6"><a name="L-6"></a><span class="sd">rhodecode.websetup</span>
545 545 </div><div id="L7"><a name="L-7"></a><span class="sd">~~~~~~~~~~~~~~~~~~</span>
546 546 </div><div id="L8"><a name="L-8"></a>
547 547 </div><div id="L9"><a name="L-9"></a><span class="sd">Weboperations and setup for rhodecode. Intentionally long line to show what will happen if this line does not fit onto the screen. It might have some horizontal scrolling applied or some other fancy mechanism to deal with it.</span>
548 548 </div><div id="L10"><a name="L-10"></a>
549 549 </div><div id="L11"><a name="L-11"></a><span class="sd">:created_on: Dec 11, 2010</span>
550 550 </div><div id="L12"><a name="L-12"></a><span class="sd">:author: marcink</span>
551 551 </div><div id="L13"><a name="L-13"></a><span class="sd">:copyright: (c) 2013-2015 RhodeCode GmbH.</span>
552 552 </div><div id="L14"><a name="L-14"></a><span class="sd">:license: Business Source License, see LICENSE for more details.</span>
553 553 </div><div id="L15"><a name="L-15"></a><span class="sd">"""</span>
554 554 </div><div id="L16"><a name="L-16"></a>
555 555 </div><div id="L17"><a name="L-17"></a><span class="kn">import</span> <span class="nn">logging</span>
556 556 </div><div id="L18"><a name="L-18"></a>
557 557 </div><div id="L19"><a name="L-19"></a><span class="kn">from</span> <span class="nn">rhodecode.config.environment</span> <span class="kn">import</span> <span class="n">load_environment</span>
558 558 </div><div id="L20"><a name="L-20"></a><span class="kn">from</span> <span class="nn">rhodecode.lib.db_manage</span> <span class="kn">import</span> <span class="n">DbManage</span>
559 559 </div><div id="L21"><a name="L-21"></a><span class="kn">from</span> <span class="nn">rhodecode.model.meta</span> <span class="kn">import</span> <span class="n">Session</span>
560 560 </div><div id="L22"><a name="L-22"></a>
561 561 </div><div id="L23"><a name="L-23"></a>
562 562 </div><div id="L24"><a name="L-24"></a><span class="n">log</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>
563 563 </div><div id="L25"><a name="L-25"></a>
564 564 </div><div id="L26"><a name="L-26"></a>
565 565 </div><div id="L27"><a name="L-27"></a><span class="k">def</span> <span class="nf">setup_app</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">conf</span><span class="p">,</span> <span class="nb">vars</span><span class="p">):</span>
566 566 </div><div id="L28"><a name="L-28"></a> <span class="sd">"""Place any commands to setup rhodecode here"""</span>
567 567 </div><div id="L29"><a name="L-29"></a> <span class="n">dbconf</span> <span class="o">=</span> <span class="n">conf</span><span class="p">[</span><span class="s">'sqlalchemy.db1.url'</span><span class="p">]</span>
568 568 </div><div id="L30"><a name="L-30"></a> <span class="n">dbmanage</span> <span class="o">=</span> <span class="n">DbManage</span><span class="p">(</span><span class="n">log_sql</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">dbconf</span><span class="o">=</span><span class="n">dbconf</span><span class="p">,</span> <span class="n">root</span><span class="o">=</span><span class="n">conf</span><span class="p">[</span><span class="s">'here'</span><span class="p">],</span>
569 569 </div><div id="L31"><a name="L-31"></a> <span class="n">tests</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">cli_args</span><span class="o">=</span><span class="n">command</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">__dict__</span><span class="p">)</span>
570 570 </div><div id="L32"><a name="L-32"></a> <span class="n">dbmanage</span><span class="o">.</span><span class="n">create_tables</span><span class="p">(</span><span class="n">override</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
571 571 </div><div id="L33"><a name="L-33"></a> <span class="n">dbmanage</span><span class="o">.</span><span class="n">set_db_version</span><span class="p">()</span>
572 572 </div><div id="L34"><a name="L-34"></a> <span class="n">opts</span> <span class="o">=</span> <span class="n">dbmanage</span><span class="o">.</span><span class="n">config_prompt</span><span class="p">(</span><span class="bp">None</span><span class="p">)</span>
573 573 </div><div id="L35"><a name="L-35"></a> <span class="n">dbmanage</span><span class="o">.</span><span class="n">create_settings</span><span class="p">(</span><span class="n">opts</span><span class="p">)</span>
574 574 </div><div id="L36"><a name="L-36"></a> <span class="n">dbmanage</span><span class="o">.</span><span class="n">create_default_user</span><span class="p">()</span>
575 575 </div><div id="L37"><a name="L-37"></a> <span class="n">dbmanage</span><span class="o">.</span><span class="n">admin_prompt</span><span class="p">()</span>
576 576 </div><div id="L38"><a name="L-38"></a> <span class="n">dbmanage</span><span class="o">.</span><span class="n">create_permissions</span><span class="p">()</span>
577 577 </div><div id="L39"><a name="L-39"></a> <span class="n">dbmanage</span><span class="o">.</span><span class="n">populate_default_permissions</span><span class="p">()</span>
578 578 </div><div id="L40"><a name="L-40"></a> <span class="n">Session</span><span class="p">()</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
579 579 </div><div id="L41"><a name="L-41"></a> <span class="n">load_environment</span><span class="p">(</span><span class="n">conf</span><span class="o">.</span><span class="n">global_conf</span><span class="p">,</span> <span class="n">conf</span><span class="o">.</span><span class="n">local_conf</span><span class="p">,</span> <span class="n">initial</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
580 580 </div><div id="L42"><a name="L-42"></a> <span class="n">DbManage</span><span class="o">.</span><span class="n">check_waitress</span><span class="p">()</span>
581 581 </div></pre></div>
582 582 </td></tr></tbody></table>
583 583 </div>
584 584 </div>
585 585
586 586
587 587
588 588
589 589
590 590
591 591
592 592
593 593
594 594 <!--
595 595 Gist Edit
596 596 -->
597 597
598 598
599 599 <h2>Gist Edit</h2>
600 600
601 601 <div class="codeblock">
602 602 <div class="code-header">
603 603 <div class="form">
604 604 <div class="fields">
605 605 <input id="filename" name="filename" placeholder="name this file..." size="30" type="text">
606 606 <div class="select2-container drop-menu" id="s2id_mimetype"><a href="javascript:void(0)" class="select2-choice" tabindex="-1"> <span class="select2-chosen" id="select2-chosen-3">Python</span><abbr class="select2-search-choice-close"></abbr> <span class="select2-arrow" role="presentation"><b role="presentation"></b></span></a><label for="s2id_autogen3" class="select2-offscreen"></label><input class="select2-focusser select2-offscreen" type="text" aria-haspopup="true" role="button" aria-labelledby="select2-chosen-3" id="s2id_autogen3"><div class="select2-drop select2-display-none drop-menu-dropdown select2-with-searchbox"> <div class="select2-search"> <label for="s2id_autogen3_search" class="select2-offscreen"></label> <input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="select2-input" role="combobox" aria-expanded="true" aria-autocomplete="list" aria-owns="select2-results-3" id="s2id_autogen3_search" placeholder=""> </div> <ul class="select2-results" role="listbox" id="select2-results-3"> </ul></div></div><select id="mimetype" name="mimetype" tabindex="-1" title="" style="display: none;">
607 607 <option selected="selected" value="plain">plain</option>
608 608 <option value="text/apl" mode="apl">APL</option><option value="text/x-asterisk" mode="asterisk">Asterisk</option><option value="text/x-csrc" mode="clike">C</option><option value="text/x-c++src" mode="clike">C++</option><option value="text/x-cobol" mode="cobol">Cobol</option><option value="text/x-java" mode="clike">Java</option><option value="text/x-csharp" mode="clike">C#</option><option value="text/x-scala" mode="clike">Scala</option><option value="text/x-clojure" mode="clojure">Clojure</option><option value="text/x-coffeescript" mode="coffeescript">CoffeeScript</option><option value="text/x-common-lisp" mode="commonlisp">Common Lisp</option><option value="text/css" mode="css">CSS</option><option value="text/x-d" mode="d">D</option><option value="text/x-diff" mode="diff">diff</option><option value="application/xml-dtd" mode="dtd">DTD</option><option value="text/x-dylan" mode="dylan">Dylan</option><option value="text/x-ecl" mode="ecl">ECL</option><option value="text/x-eiffel" mode="eiffel">Eiffel</option><option value="text/x-erlang" mode="erlang">Erlang</option><option value="text/x-fortran" mode="fortran">Fortran</option><option value="text/x-fsharp" mode="mllike">F#</option><option value="text/x-gas" mode="gas">Gas</option><option value="text/x-go" mode="go">GO</option><option value="text/x-feature" mode="gherkin">Gherkin</option><option value="text/x-go" mode="go">Go</option><option value="text/x-groovy" mode="groovy">Groovy</option><option value="text/x-haml" mode="haml">HAML</option><option value="text/x-haskell" mode="haskell">Haskell</option><option value="text/x-haxe" mode="haxe">Haxe</option><option value="application/x-aspx" mode="htmlembedded">ASP.NET</option><option value="application/x-ejs" mode="htmlembedded">Embedded Javascript</option><option value="application/x-jsp" mode="htmlembedded">JavaServer Pages</option><option value="text/html" mode="htmlmixed">HTML</option><option value="message/http" mode="http">HTTP</option><option value="text/x-jade" mode="jade">Jade</option><option value="text/javascript" mode="javascript">JavaScript</option><option value="application/json" mode="javascript">JSON</option><option value="application/typescript" mode="javascript">TypeScript</option><option value="jinja2" mode="jinja2">Jinja2</option><option value="text/x-julia" mode="julia">Julia</option><option value="text/x-less" mode="less">LESS</option><option value="text/x-livescript" mode="livescript">LiveScript</option><option value="text/x-lua" mode="lua">Lua</option><option value="text/x-markdown" mode="markdown">Markdown (GitHub-flavour)</option><option value="text/mirc" mode="mirc">mIRC</option><option value="text/x-nginx-conf" mode="nginx">Nginx</option><option value="text/n-triples" mode="ntriples">NTriples</option><option value="text/x-ocaml" mode="ocaml">OCaml</option><option value="text/x-ocaml" mode="mllike">OCaml</option><option value="text/x-octave" mode="octave">Octave</option><option value="text/x-pascal" mode="pascal">Pascal</option><option value="null" mode="pegjs">PEG.js</option><option value="text/x-perl" mode="perl">Perl</option><option value="text/x-php" mode="php">PHP</option><option value="text/x-pig" mode="pig">Pig</option><option value="text/plain" mode="null">Plain Text</option><option value="text/x-properties" mode="properties">Properties files</option><option value="text/x-python" mode="python">Python</option><option value="text/x-puppet" mode="puppet">Puppet</option><option value="text/x-rsrc" mode="r">R</option><option value="text/x-rst" mode="rst">reStructuredText</option><option value="text/x-ruby" mode="ruby">Ruby</option><option value="text/x-rustsrc" mode="rust">Rust</option><option value="text/x-sass" mode="sass">Sass</option><option value="text/x-scheme" mode="scheme">Scheme</option><option value="text/x-scss" mode="css">SCSS</option><option value="text/x-sh" mode="shell">Shell</option><option value="application/sieve" mode="sieve">Sieve</option><option value="text/x-stsrc" mode="smalltalk">Smalltalk</option><option value="text/x-smarty" mode="smarty">Smarty</option><option value="text/x-smarty" mode="smartymixed">SmartyMixed</option><option value="text/x-solr" mode="solr">Solr</option><option value="application/x-sparql-query" mode="sparql">SPARQL</option><option value="text/x-sql" mode="sql">SQL</option><option value="text/x-mariadb" mode="sql">MariaDB</option><option value="text/x-stex" mode="stex">sTeX</option><option value="text/x-latex" mode="stex">LaTeX</option><option value="text/x-systemverilog" mode="verilog">SystemVerilog</option><option value="text/x-tcl" mode="tcl">Tcl</option><option value="text/x-tiddlywiki" mode="tiddlywiki">TiddlyWiki </option><option value="text/tiki" mode="tiki">Tiki wiki</option><option value="text/x-toml" mode="toml">TOML</option><option value="text/turtle" mode="turtle">Turtle</option><option value="text/x-vb" mode="vb">VB.NET</option><option value="text/vbscript" mode="vbscript">VBScript</option><option value="text/velocity" mode="velocity">Velocity</option><option value="text/x-verilog" mode="verilog">Verilog</option><option value="application/xml" mode="xml">XML</option><option value="text/html" mode="xml">HTML</option><option value="application/xquery" mode="xquery">XQuery</option><option value="text/x-yaml" mode="yaml">YAML</option><option value="text/x-z80" mode="z80">Z80</option></select>
609 609 <script>
610 610 $(document).ready(function() {
611 611 $('#mimetype').select2({
612 612 containerCssClass: 'drop-menu',
613 613 dropdownCssClass: 'drop-menu-dropdown',
614 614 dropdownAutoWidth: true
615 615 });
616 616 });
617 617 </script>
618 618
619 619 </div>
620 620 </div>
621 621 </div>
622 622 <div id="editor_container">
623 623 <div id="editor_pre"></div>
624 624 <textarea id="editor" name="content" style="display: none;"></textarea><div class="CodeMirror cm-s-default"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 484px; left: 219.4091796875px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" style="position: absolute; padding: 0px; width: 1000px; height: 1em; outline: none;" tabindex="0"></textarea></div><div class="CodeMirror-hscrollbar" style="left: 29px; min-height: 18px;"><div style="height: 100%; min-height: 1px; width: 0px;"></div></div><div class="CodeMirror-vscrollbar" style="min-width: 18px; display: block; bottom: 0px;"><div style="min-width: 1px; height: 619px;"></div></div><div class="CodeMirror-scrollbar-filler"></div><div class="CodeMirror-gutter-filler"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="min-width: 700.269653320313px; margin-left: 29px; min-height: 619px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines"><div style="position: relative; outline: none;"><div class="CodeMirror-measure"><div class="CodeMirror-linenumber CodeMirror-gutter-elt"><div>47</div></div></div><div style="position: relative; z-index: 1; display: none;"></div><div class="CodeMirror-code"><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">1</div></div><pre><span class="cm-keyword">import</span> <span class="cm-variable">re</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">2</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">3</div></div><pre><span class="cm-keyword">from</span> <span class="cm-variable">django</span>.<span class="cm-variable">utils</span>.<span class="cm-variable">text</span> <span class="cm-keyword">import</span> <span class="cm-variable">compress_sequence</span>, <span class="cm-variable">compress_string</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">4</div></div><pre><span class="cm-keyword">from</span> <span class="cm-variable">django</span>.<span class="cm-variable">utils</span>.<span class="cm-variable">cache</span> <span class="cm-keyword">import</span> <span class="cm-variable">patch_vary_headers</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">5</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">6</div></div><pre><span class="cm-variable">re_accepts_gzip</span> = <span class="cm-variable">re</span>.<span class="cm-builtin">compile</span>(<span class="cm-string">r'\bgzip\b'</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">7</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">8</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">9</div></div><pre><span class="cm-keyword">class</span> <span class="cm-def">GZipMiddleware</span>(<span class="cm-builtin">object</span>): # Intentionally long line to show what will happen if this line does not fit onto the screen. It might have some horizontal scrolling applied or some other fancy mechanism to deal with it.</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">10</div></div><pre> <span class="cm-string">"""</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">11</div></div><pre><span class="cm-string"> This middleware compresses content if the browser allows gzip compression.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">12</div></div><pre><span class="cm-string"> It sets the Vary header accordingly, so that caches will base their storage</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">13</div></div><pre><span class="cm-string"> on the Accept-Encoding header.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">14</div></div><pre><span class="cm-string"> """</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">15</div></div><pre> <span class="cm-keyword">def</span> <span class="cm-def">process_response</span>(<span class="cm-variable-2">self</span>, <span class="cm-variable">request</span>, <span class="cm-variable">response</span>):</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">16</div></div><pre> <span class="cm-comment"># It's not worth attempting to compress really short responses.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">17</div></div><pre> <span class="cm-keyword">if</span> <span class="cm-operator">not</span> <span class="cm-variable">response</span>.<span class="cm-variable">streaming</span> <span class="cm-operator">and</span> <span class="cm-builtin">len</span>(<span class="cm-variable">response</span>.<span class="cm-variable">content</span>) <span class="cm-operator">&lt;</span> <span class="cm-number">200</span>:</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">18</div></div><pre> <span class="cm-keyword">return</span> <span class="cm-variable">response</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">19</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">20</div></div><pre> <span class="cm-comment"># Avoid gzipping if we've already got a content-encoding.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">21</div></div><pre> <span class="cm-keyword">if</span> <span class="cm-variable">response</span>.<span class="cm-variable">has_header</span>(<span class="cm-string">'Content-Encoding'</span>):</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">22</div></div><pre> <span class="cm-keyword">return</span> <span class="cm-variable">response</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">23</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">24</div></div><pre> <span class="cm-variable">patch_vary_headers</span>(<span class="cm-variable">response</span>, (<span class="cm-string">'Accept-Encoding'</span>,))</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">25</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">26</div></div><pre> <span class="cm-variable">ae</span> = <span class="cm-variable">request</span>.<span class="cm-variable">META</span>.<span class="cm-variable">get</span>(<span class="cm-string">'HTTP_ACCEPT_ENCODING'</span>, <span class="cm-string">''</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">27</div></div><pre> <span class="cm-keyword">if</span> <span class="cm-operator">not</span> <span class="cm-variable">re_accepts_gzip</span>.<span class="cm-variable">search</span>(<span class="cm-variable">ae</span>):</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">28</div></div><pre> <span class="cm-keyword">return</span> <span class="cm-variable">response</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">29</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">30</div></div><pre> <span class="cm-keyword">if</span> <span class="cm-variable">response</span>.<span class="cm-variable">streaming</span>:</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">31</div></div><pre> <span class="cm-comment"># Delete the `Content-Length` header for streaming content, because</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">32</div></div><pre> <span class="cm-comment"># we won't know the compressed size until we stream it.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">33</div></div><pre> <span class="cm-variable">response</span>.<span class="cm-variable">streaming_content</span> = <span class="cm-variable">compress_sequence</span>(<span class="cm-variable">response</span>.<span class="cm-variable">streaming_content</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">34</div></div><pre> <span class="cm-keyword">del</span> <span class="cm-variable">response</span>[<span class="cm-string">'Content-Length'</span>]</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">35</div></div><pre> <span class="cm-keyword">else</span>:</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">36</div></div><pre> <span class="cm-comment"># Return the compressed content only if it's actually shorter.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">37</div></div><pre> <span class="cm-variable">compressed_content</span> = <span class="cm-variable">compress_string</span>(<span class="cm-variable">response</span>.<span class="cm-variable">content</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">38</div></div><pre> <span class="cm-keyword">if</span> <span class="cm-builtin">len</span>(<span class="cm-variable">compressed_content</span>) <span class="cm-operator">&gt;=</span> <span class="cm-builtin">len</span>(<span class="cm-variable">response</span>.<span class="cm-variable">content</span>):</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">39</div></div><pre> <span class="cm-keyword">return</span> <span class="cm-variable">response</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">40</div></div><pre> <span class="cm-variable">response</span>.<span class="cm-variable">content</span> = <span class="cm-variable">compressed_content</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">41</div></div><pre> <span class="cm-variable">response</span>[<span class="cm-string">'Content-Length'</span>] = <span class="cm-builtin">str</span>(<span class="cm-builtin">len</span>(<span class="cm-variable">response</span>.<span class="cm-variable">content</span>))</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">42</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">43</div></div><pre> <span class="cm-keyword">if</span> <span class="cm-variable">response</span>.<span class="cm-variable">has_header</span>(<span class="cm-string">'ETag'</span>):</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">44</div></div><pre> <span class="cm-variable">response</span>[<span class="cm-string">'ETag'</span>] = <span class="cm-variable">re</span>.<span class="cm-variable">sub</span>(<span class="cm-string">'"$'</span>, <span class="cm-string">';gzip"'</span>, <span class="cm-variable">response</span>[<span class="cm-string">'ETag'</span>])</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">45</div></div><pre> <span class="cm-variable">response</span>[<span class="cm-string">'Content-Encoding'</span>] = <span class="cm-string">'gzip'</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">46</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">47</div></div><pre> <span class="cm-keyword">return</span> <span class="cm-variable">response</span></pre></div></div><div class="CodeMirror-cursor" style="left: 189.4091796875px; top: 598px; height: 13px;">&nbsp;</div><div class="CodeMirror-cursor CodeMirror-secondarycursor" style="display: none;">&nbsp;</div></div></div></div></div><div style="position: absolute; height: 30px; width: 1px; top: 619px;"></div><div class="CodeMirror-gutters" style="height: 619px;"><div class="CodeMirror-gutter CodeMirror-linenumbers" style="width: 28px;"></div></div></div></div>
625 625 </div>
626 626 </div>
627 627
628 628
629 629
630 630
631 631
632 632 <!--
633 633 File Edit
634 634 -->
635 635
636 636 <h2>File Edit</h2>
637 637
638 638 <div class="codeblock">
639 639 <div class="code-header">
640 640 <div class="stats">
641 641 <i class="icon-file"></i>
642 642 <span class="item"><a href="/example/changeset/80ead1899f50a894889e19ffeb49c9cebf5bf045">r8248:80ead1899f50</a></span>
643 643 <span class="item">1.2 KiB</span>
644 644 <span class="item last">text/x-python</span>
645 645 <div class="buttons">
646 646 <a class="btn btn-mini" href="/example/changelog/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py">
647 647 <i class="icon-time"></i> history
648 648 </a>
649 649
650 650 <a class="btn btn-mini" href="/example/files/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py">source</a>
651 651 <a class="btn btn-mini" href="/example/raw/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py">raw</a>
652 652 <a class="btn btn-mini" href="/example/rawfile/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py">
653 653 <i class="icon-archive"></i> download
654 654 </a>
655 655 </div>
656 656 </div>
657 657 <div class="form">
658 658 <label for="set_mode">Editing file:</label>
659 659 rhodecode /
660 660 <input type="text" name="filename" value="websetup.py">
661 661
662 662 <div class="select2-container drop-menu" id="s2id_set_mode"><a href="javascript:void(0)" class="select2-choice" tabindex="-1"> <span class="select2-chosen" id="select2-chosen-2">plain</span><abbr class="select2-search-choice-close"></abbr> <span class="select2-arrow" role="presentation"><b role="presentation"></b></span></a><label for="s2id_autogen2" class="select2-offscreen">Editing file:</label><input class="select2-focusser select2-offscreen" type="text" aria-haspopup="true" role="button" aria-labelledby="select2-chosen-2" id="s2id_autogen2"><div class="select2-drop select2-display-none drop-menu-dropdown select2-with-searchbox"> <div class="select2-search"> <label for="s2id_autogen2_search" class="select2-offscreen">Editing file:</label> <input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="select2-input" role="combobox" aria-expanded="true" aria-autocomplete="list" aria-owns="select2-results-2" id="s2id_autogen2_search" placeholder=""> </div> <ul class="select2-results" role="listbox" id="select2-results-2"> </ul></div></div><select id="set_mode" name="set_mode" tabindex="-1" title="Editing file:" style="display: none;">
663 663 <option selected="selected" value="plain">plain</option>
664 664 <option value="apl">APL</option><option value="asterisk">Asterisk</option><option value="clike">C</option><option value="clike">C++</option><option value="cobol">Cobol</option><option value="clike">Java</option><option value="clike">C#</option><option value="clike">Scala</option><option value="clojure">Clojure</option><option value="coffeescript">CoffeeScript</option><option value="commonlisp">Common Lisp</option><option value="css">CSS</option><option value="d">D</option><option value="diff">diff</option><option value="dtd">DTD</option><option value="dylan">Dylan</option><option value="ecl">ECL</option><option value="eiffel">Eiffel</option><option value="erlang">Erlang</option><option value="fortran">Fortran</option><option value="mllike">F#</option><option value="gas">Gas</option><option value="go">GO</option><option value="gherkin">Gherkin</option><option value="go">Go</option><option value="groovy">Groovy</option><option value="haml">HAML</option><option value="haskell">Haskell</option><option value="haxe">Haxe</option><option value="htmlembedded">ASP.NET</option><option value="htmlembedded">Embedded Javascript</option><option value="htmlembedded">JavaServer Pages</option><option value="htmlmixed">HTML</option><option value="http">HTTP</option><option value="jade">Jade</option><option value="javascript">JavaScript</option><option value="javascript">JSON</option><option value="javascript">TypeScript</option><option value="jinja2">Jinja2</option><option value="julia">Julia</option><option value="less">LESS</option><option value="livescript">LiveScript</option><option value="lua">Lua</option><option value="markdown">Markdown (GitHub-flavour)</option><option value="mirc">mIRC</option><option value="nginx">Nginx</option><option value="ntriples">NTriples</option><option value="ocaml">OCaml</option><option value="mllike">OCaml</option><option value="octave">Octave</option><option value="pascal">Pascal</option><option value="pegjs">PEG.js</option><option value="perl">Perl</option><option value="php">PHP</option><option value="pig">Pig</option><option value="null">Plain Text</option><option value="properties">Properties files</option><option value="python" selected="selected">Python</option><option value="puppet">Puppet</option><option value="r">R</option><option value="rst">reStructuredText</option><option value="ruby">Ruby</option><option value="rust">Rust</option><option value="sass">Sass</option><option value="scheme">Scheme</option><option value="css">SCSS</option><option value="shell">Shell</option><option value="sieve">Sieve</option><option value="smalltalk">Smalltalk</option><option value="smarty">Smarty</option><option value="smartymixed">SmartyMixed</option><option value="solr">Solr</option><option value="sparql">SPARQL</option><option value="sql">SQL</option><option value="sql">MariaDB</option><option value="stex">sTeX</option><option value="stex">LaTeX</option><option value="verilog">SystemVerilog</option><option value="tcl">Tcl</option><option value="tiddlywiki">TiddlyWiki </option><option value="tiki">Tiki wiki</option><option value="toml">TOML</option><option value="turtle">Turtle</option><option value="vb">VB.NET</option><option value="vbscript">VBScript</option><option value="velocity">Velocity</option><option value="verilog">Verilog</option><option value="xml">XML</option><option value="xml">HTML</option><option value="xquery">XQuery</option><option value="yaml">YAML</option><option value="z80">Z80</option></select>
665 665 <script>
666 666 $(document).ready(function() {
667 667 $('#set_mode').select2({
668 668 containerCssClass: 'drop-menu',
669 669 dropdownCssClass: 'drop-menu-dropdown',
670 670 dropdownAutoWidth: true
671 671 });
672 672 });
673 673 </script>
674 674
675 675 <label for="line_wrap">line wraps</label>
676 676 <div class="select2-container drop-menu" id="s2id_line_wrap"><a href="javascript:void(0)" class="select2-choice" tabindex="-1"> <span class="select2-chosen" id="select2-chosen-3">off</span><abbr class="select2-search-choice-close"></abbr> <span class="select2-arrow" role="presentation"><b role="presentation"></b></span></a><label for="s2id_autogen3" class="select2-offscreen">line wraps</label><input class="select2-focusser select2-offscreen" type="text" aria-haspopup="true" role="button" aria-labelledby="select2-chosen-3" id="s2id_autogen3"><div class="select2-drop select2-display-none drop-menu-dropdown"> <div class="select2-search select2-search-hidden select2-offscreen"> <label for="s2id_autogen3_search" class="select2-offscreen">line wraps</label> <input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="select2-input" role="combobox" aria-expanded="true" aria-autocomplete="list" aria-owns="select2-results-3" id="s2id_autogen3_search" placeholder=""> </div> <ul class="select2-results" role="listbox" id="select2-results-3"> </ul></div></div><select id="line_wrap" name="line_wrap" tabindex="-1" title="line wraps" style="display: none;">
677 677 <option value="on">on</option>
678 678 <option selected="selected" value="off">off</option>
679 679 </select>
680 680 <script>
681 681 $(document).ready(function() {
682 682 $('#line_wrap').select2({
683 683 containerCssClass: 'drop-menu',
684 684 dropdownCssClass: 'drop-menu-dropdown',
685 685 dropdownAutoWidth: true,
686 686 minimumResultsForSearch: -1
687 687
688 688 });
689 689 });
690 690 </script>
691 691
692 692 <div id="render_preview" class="btn btn-mini hidden disabled">Preview</div>
693 693 </div>
694 694 </div>
695 695 <div id="editor_container">
696 696 <pre id="editor_pre"></pre>
697 697 <textarea id="editor" name="content" style="display: none;"># -*- coding: utf-8 -*-
698 698
699 699 # Published under Commercial License.
700 700 # Read the full license text at https://rhodecode.com/licenses.
701 701 """
702 702 rhodecode.websetup
703 703 ~~~~~~~~~~~~~~~~~~
704 704
705 705 Weboperations and setup for rhodecode
706 706
707 707 :created_on: Dec 11, 2010
708 708 :author: marcink
709 709 :copyright: (c) 2013-2015 RhodeCode GmbH.
710 710 :license: Commercial License, see LICENSE for more details.
711 711 """
712 712
713 713 import logging
714 714
715 715 from rhodecode.config.environment import load_environment
716 716 from rhodecode.lib.db_manage import DbManage
717 717 from rhodecode.model.meta import Session
718 718
719 719
720 720 log = logging.getLogger(__name__)
721 721
722 722
723 723 def setup_app(command, conf, vars):
724 724 """Place any commands to setup rhodecode here"""
725 725 dbconf = conf['sqlalchemy.db1.url']
726 726 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=conf['here'],
727 727 tests=False, cli_args=command.options.__dict__)
728 728 dbmanage.create_tables(override=True)
729 729 dbmanage.set_db_version()
730 730 opts = dbmanage.config_prompt(None)
731 731 dbmanage.create_settings(opts)
732 732 dbmanage.create_default_user()
733 733 dbmanage.admin_prompt()
734 734 dbmanage.create_permissions()
735 735 dbmanage.populate_default_permissions()
736 736 Session().commit()
737 737 load_environment(conf.global_conf, conf.local_conf, initial=True)
738 738 </textarea><div class="CodeMirror cm-s-default CodeMirror-focused"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 5px; left: 34px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" style="position: absolute; padding: 0px; width: 1000px; height: 1em; outline: none;" tabindex="0"></textarea></div><div class="CodeMirror-hscrollbar" style="left: 29px; min-height: 18px;"><div style="height: 100%; min-height: 1px; width: 0px;"></div></div><div class="CodeMirror-vscrollbar" style="display: block; bottom: 0px; min-width: 18px;"><div style="min-width: 1px; height: 554px;"></div></div><div class="CodeMirror-scrollbar-filler"></div><div class="CodeMirror-gutter-filler"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="min-width: 579.350463867188px; margin-left: 29px; min-height: 554px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines"><div style="position: relative; outline: none;"><div class="CodeMirror-measure"><div style="width: 50px; height: 50px; overflow-x: scroll;"></div></div><div style="position: relative; z-index: 1; display: none;"></div><div class="CodeMirror-code"><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">1</div></div><pre><span class="cm-comment"># -*- coding: utf-8 -*-</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">2</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">3</div></div><pre><span class="cm-comment"># Published under Commercial License.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">4</div></div><pre><span class="cm-comment"># Read the full license text at https://rhodecode.com/licenses.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">5</div></div><pre><span class="cm-string">"""</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">6</div></div><pre><span class="cm-string">rhodecode.websetup</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">7</div></div><pre><span class="cm-string">~~~~~~~~~~~~~~~~~~</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">8</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">9</div></div><pre><span class="cm-string">Weboperations and setup for rhodecode</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">10</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">11</div></div><pre><span class="cm-string">:created_on: Dec 11, 2010</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">12</div></div><pre><span class="cm-string">:author: marcink</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">13</div></div><pre><span class="cm-string">:copyright: (c) 2013-2015 RhodeCode GmbH.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">14</div></div><pre><span class="cm-string">:license: Commercial License, see LICENSE for more details.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">15</div></div><pre><span class="cm-string">"""</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">16</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">17</div></div><pre><span class="cm-keyword">import</span> <span class="cm-variable">logging</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">18</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">19</div></div><pre><span class="cm-keyword">from</span> <span class="cm-variable">rhodecode</span>.<span class="cm-variable">config</span>.<span class="cm-variable">environment</span> <span class="cm-keyword">import</span> <span class="cm-variable">load_environment</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">20</div></div><pre><span class="cm-keyword">from</span> <span class="cm-variable">rhodecode</span>.<span class="cm-variable">lib</span>.<span class="cm-variable">db_manage</span> <span class="cm-keyword">import</span> <span class="cm-variable">DbManage</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">21</div></div><pre><span class="cm-keyword">from</span> <span class="cm-variable">rhodecode</span>.<span class="cm-variable">model</span>.<span class="cm-variable">meta</span> <span class="cm-keyword">import</span> <span class="cm-variable">Session</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">22</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">23</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">24</div></div><pre><span class="cm-variable">log</span> = <span class="cm-variable">logging</span>.<span class="cm-variable">getLogger</span>(<span class="cm-variable">__name__</span>) # Intentionally long line to show what will happen if this line does not fit onto the screen. It might have some horizontal scrolling applied or some other fancy mechanism to deal with it.</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">25</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">26</div></div><pre>&nbsp;</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">27</div></div><pre><span class="cm-keyword">def</span> <span class="cm-def">setup_app</span>(<span class="cm-variable">command</span>, <span class="cm-variable">conf</span>, <span class="cm-builtin">vars</span>):</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">28</div></div><pre> <span class="cm-string">"""Place any commands to setup rhodecode here"""</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">29</div></div><pre> <span class="cm-variable">dbconf</span> = <span class="cm-variable">conf</span>[<span class="cm-string">'sqlalchemy.db1.url'</span>]</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">30</div></div><pre> <span class="cm-variable">dbmanage</span> = <span class="cm-variable">DbManage</span>(<span class="cm-variable">log_sql</span>=<span class="cm-builtin">True</span>, <span class="cm-variable">dbconf</span>=<span class="cm-variable">dbconf</span>, <span class="cm-variable">root</span>=<span class="cm-variable">conf</span>[<span class="cm-string">'here'</span>],</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">31</div></div><pre> <span class="cm-variable">tests</span>=<span class="cm-builtin">False</span>, <span class="cm-variable">cli_args</span>=<span class="cm-variable">command</span>.<span class="cm-variable">options</span>.<span class="cm-variable">__dict__</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">32</div></div><pre> <span class="cm-variable">dbmanage</span>.<span class="cm-variable">create_tables</span>(<span class="cm-variable">override</span>=<span class="cm-builtin">True</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">33</div></div><pre> <span class="cm-variable">dbmanage</span>.<span class="cm-variable">set_db_version</span>()</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">34</div></div><pre> <span class="cm-variable">opts</span> = <span class="cm-variable">dbmanage</span>.<span class="cm-variable">config_prompt</span>(<span class="cm-builtin">None</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">35</div></div><pre> <span class="cm-variable">dbmanage</span>.<span class="cm-variable">create_settings</span>(<span class="cm-variable">opts</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">36</div></div><pre> <span class="cm-variable">dbmanage</span>.<span class="cm-variable">create_default_user</span>()</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">37</div></div><pre> <span class="cm-variable">dbmanage</span>.<span class="cm-variable">admin_prompt</span>()</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">38</div></div><pre> <span class="cm-variable">dbmanage</span>.<span class="cm-variable">create_permissions</span>()</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">39</div></div><pre> <span class="cm-variable">dbmanage</span>.<span class="cm-variable">populate_default_permissions</span>()</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">40</div></div><pre> <span class="cm-variable">Session</span>().<span class="cm-variable">commit</span>()</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">41</div></div><pre> <span class="cm-variable">load_environment</span>(<span class="cm-variable">conf</span>.<span class="cm-variable">global_conf</span>, <span class="cm-variable">conf</span>.<span class="cm-variable">local_conf</span>, <span class="cm-variable">initial</span>=<span class="cm-builtin">True</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">42</div></div><pre>&nbsp;</pre></div></div><div class="CodeMirror-cursor" style="left: 4px; top: 0px; height: 13px;">&nbsp;</div><div class="CodeMirror-cursor CodeMirror-secondarycursor" style="display: none;">&nbsp;</div></div></div></div></div><div style="position: absolute; height: 30px; width: 1px; top: 554px;"></div><div class="CodeMirror-gutters" style="height: 554px;"><div class="CodeMirror-gutter CodeMirror-linenumbers" style="width: 28px;"></div></div></div></div>
739 739 <div id="editor_preview"></div>
740 740 </div>
741 741 <div class="message">
742 742 <label class="codeblock-label">Commit Message</label>
743 743 <textarea id="commit" name="message" placeholder="Edited file rhodecode/websetup.py via RhodeCode"></textarea>
744 744 </div>
745 745 </div>
746 746
747 747
748 748
749 749
750 750
751 751
752 752 <!--
753 753 Commit with comments
754 754 -->
755 755
756 756 <h2>Commit with comments</h2>
757 757
758 758 <div class="diff-container" id="diff-container-140360037209920">
759 759 <div id="c-4e5ee86997c6-7046e4320b26_target"></div>
760 760 <div id="c-4e5ee86997c6-7046e4320b26" class="diffblock margined comm">
761 761 <div class="code-header">
762 762 <div title="Go back to changed files overview">
763 763 <a href="#changes_box">
764 764 <i class="icon-circle-arrow-up"></i>
765 765 </a>
766 766 </div>
767 767 <div class="changeset_header">
768 768 <div class="changeset_file">
769 769 <i class="icon-file"></i>
770 770 <a href="/andersonsantos/rhodecode-dev-fork/files/4e5ee86997c64981d85cf62283af448624e26929/rhodecode/tests/functional/test_compare_local.py">rhodecode/tests/functional/test_compare_local.py</a>
771 771 </div>
772 772 <div class="diff-actions">
773 773 <a href="/andersonsantos/rhodecode-dev-fork/diff/rhodecode/tests/functional/test_compare_local.py?fulldiff=1&amp;diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&amp;diff=diff&amp;diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Show full diff for this file">
774 774 <img class="icon" src="/images/icons/page_white_go.png">
775 775 </a>
776 776 <a href="/andersonsantos/rhodecode-dev-fork/diff-2way/rhodecode/tests/functional/test_compare_local.py?fulldiff=1&amp;diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&amp;diff=diff&amp;diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Show full side-by-side diff for this file">
777 777 <img class="icon" src="/images/icons/application_double.png">
778 778 </a>
779 779 <a href="/andersonsantos/rhodecode-dev-fork/diff/rhodecode/tests/functional/test_compare_local.py?diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&amp;diff=raw&amp;diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Raw diff">
780 780 <img class="icon" src="/images/icons/page_white.png">
781 781 </a>
782 782 <a href="/andersonsantos/rhodecode-dev-fork/diff/rhodecode/tests/functional/test_compare_local.py?diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&amp;diff=download&amp;diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Download diff">
783 783 <img class="icon" src="/images/icons/page_save.png">
784 784 </a>
785 785 <a class="tooltip" href="/andersonsantos/rhodecode-dev-fork/changeset/4e5ee86997c64981d85cf62283af448624e26929?c-4e5ee86997c6-7046e4320b26=WS%3A1&amp;c-4e5ee86997c6-7046e4320b26=C%3A3#c-4e5ee86997c6-7046e4320b26" title="Ignore white space"><img alt="Ignore white space" class="icon" src="/images/icons/text_strikethrough.png"></a>
786 786 <a class="tooltip" href="/andersonsantos/rhodecode-dev-fork/changeset/4e5ee86997c64981d85cf62283af448624e26929?c-4e5ee86997c6-7046e4320b26=C%3A6#c-4e5ee86997c6-7046e4320b26" title="increase diff context to 6 lines"><img alt="increase diff context to 6 lines" class="icon" src="/images/icons/table_add.png"></a>
787 787 </div>
788 788 <span>
789 789 <label>
790 790 Show inline comments
791 791 <input checked="checked" class="show-inline-comments" id="" id_for="c-4e5ee86997c6-7046e4320b26" name="" type="checkbox" value="1">
792 792 </label>
793 793 </span>
794 794 </div>
795 795 </div>
796 796 <div class="code-body">
797 797 <div class="full_f_path" path="rhodecode/tests/functional/test_compare_local.py"></div>
798 798 <table class="code-difftable">
799 799 <tbody><tr class="line context">
800 800 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o...">...</a></td>
801 801 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n...">...</a></td>
802 802 <td class="code ">
803 803 <pre>@@ -59,7 +59,7 @@
804 804 </pre>
805 805 </td>
806 806 </tr>
807 807 <tr class="line unmod">
808 808 <td id="rhodecodetestsfunctionaltest_compare_localpy_o59" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o59">59</a></td>
809 809 <td id="rhodecodetestsfunctionaltest_compare_localpy_n59" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n59">59</a></td>
810 810 <td class="code ">
811 811 <pre> 'tag': 'v0.2.0',
812 812 </pre>
813 813 </td>
814 814 </tr>
815 815 <tr class="line unmod">
816 816 <td id="rhodecodetestsfunctionaltest_compare_localpy_o60" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o60">60</a></td>
817 817 <td id="rhodecodetestsfunctionaltest_compare_localpy_n60" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n60">60</a></td>
818 818 <td class="code ">
819 819 <pre> 'branch': 'default',
820 820 </pre>
821 821 </td>
822 822 </tr>
823 823 <tr class="line unmod">
824 824 <td id="rhodecodetestsfunctionaltest_compare_localpy_o61" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o61">61</a></td>
825 825 <td id="rhodecodetestsfunctionaltest_compare_localpy_n61" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n61">61</a></td>
826 826 <td class="code ">
827 827 <pre> 'response': # Intentionally long line to show what will happen if this line does not fit onto the screen. It might have some horizontal scrolling applied or some other fancy mechanism to deal with it.
828 828 </pre>
829 829 </td>
830 830 </tr>
831 831 <tr class="line del">
832 832 <td id="rhodecodetestsfunctionaltest_compare_localpy_o62" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o62">62</a></td>
833 833 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n"></a></td>
834 834 <td class="code ">
835 835 <pre> '147 files changed: 5700 inserted, 10176 deleted'
836 836 </pre>
837 837 </td>
838 838 </tr>
839 839 <tr class="line add">
840 840 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
841 841 <td id="rhodecodetestsfunctionaltest_compare_localpy_n62" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n62">62</a></td>
842 842 <td class="code ">
843 843 <pre><ins> </ins> '147 files changed: 5700 inserted, 10176 deleted'
844 844 </pre>
845 845 </td>
846 846 </tr>
847 847 <tr class="line unmod">
848 848 <td id="rhodecodetestsfunctionaltest_compare_localpy_o63" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o63">63</a></td>
849 849 <td id="rhodecodetestsfunctionaltest_compare_localpy_n63" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n63">63</a></td>
850 850 <td class="code ">
851 851 <pre> },
852 852 </pre>
853 853 </td>
854 854 </tr>
855 855 <tr class="line unmod">
856 856 <td id="rhodecodetestsfunctionaltest_compare_localpy_o64" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o64">64</a></td>
857 857 <td id="rhodecodetestsfunctionaltest_compare_localpy_n64" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n64">64</a></td>
858 858 <td class="code ">
859 859 <pre> 'git': {
860 860 </pre>
861 861 </td>
862 862 </tr>
863 863 <tr class="line unmod">
864 864 <td id="rhodecodetestsfunctionaltest_compare_localpy_o65" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o65">65</a></td>
865 865 <td id="rhodecodetestsfunctionaltest_compare_localpy_n65" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n65">65</a></td>
866 866 <td class="code ">
867 867 <pre> 'tag': 'v0.2.2',
868 868 </pre>
869 869 </td>
870 870 </tr>
871 871 <tr class="line context">
872 872 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o...">...</a></td>
873 873 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n...">...</a></td>
874 874 <td class="code ">
875 875 <pre>@@ -77,9 +77,11 @@
876 876 </pre>
877 877 </td>
878 878 </tr>
879 879 <tr class="line unmod">
880 880 <td id="rhodecodetestsfunctionaltest_compare_localpy_o77" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o77">77</a></td>
881 881 <td id="rhodecodetestsfunctionaltest_compare_localpy_n77" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n77">77</a></td>
882 882 <td class="code ">
883 883 <pre> target_ref=revisions[backend.alias]['tag'],
884 884 </pre>
885 885 </td>
886 886 </tr>
887 887 <tr class="line unmod">
888 888 <td id="rhodecodetestsfunctionaltest_compare_localpy_o78" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o78">78</a></td>
889 889 <td id="rhodecodetestsfunctionaltest_compare_localpy_n78" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n78">78</a></td>
890 890 <td class="code ">
891 891 <pre> ))
892 892 </pre>
893 893 </td>
894 894 </tr><tr id="comment-tr-3754" class="inline-comments"><td></td><td></td><td>
895 895
896 896 <div class="comment" id="comment-3754" line="n78">
897 897 <div class="comment-wrapp">
898 898 <div class="meta">
899 899 <span class="gravatar">
900 900 <img src="https://secure.gravatar.com/avatar/72706ebd30734451af9ff3fb59f05ff1?d=identicon&amp;s=40" height="20" width="20">
901 901 </span>
902 902 <span class="user">
903 903 anderson
904 904 </span>
905 905 <span class="date">
906 906 just now |
907 907 </span>
908 908 <span class="status-change">
909 909 Comment on commit
910 910 </span>
911 911 <a class="permalink" href="#comment-3754"></a>
912 912 </div>
913 913 <div class="text">
914 914 <div class="rst-block"><p>commented line
915 915 with multiple lines</p>
916 916 </div>
917 917 </div>
918 918 </div>
919 919 </div><div class="add-comment"><span class="btn btn-default">Add another comment</span></div>
920 920
921 921 </td></tr>
922 922 <tr class="line unmod">
923 923 <td id="rhodecodetestsfunctionaltest_compare_localpy_o79" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o79">79</a></td>
924 924 <td id="rhodecodetestsfunctionaltest_compare_localpy_n79" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n79">79</a></td>
925 925 <td class="code ">
926 926 <pre></pre>
927 927 </td>
928 928 </tr>
929 929 <tr class="line del form-open hl-comment">
930 930 <td id="rhodecodetestsfunctionaltest_compare_localpy_o80" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o80">80</a></td>
931 931 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n"></a></td>
932 932 <td class="code ">
933 933 <pre> response.mustcontain('%s@%s' % (<del>backend.repo_name,</del>
934 934 </pre>
935 935 </td>
936 936 </tr><tr id="comment-tr-undefined" class="comment-form-inline"><td></td><td></td><td>
937 937 <div class="comment-inline-form ac">
938 938 <div class="overlay"><div class="overlay-text">Submitting...</div></div>
939 939 <form action="#" class="inline-form" method="get">
940 940 <div id="edit-container_o80" class="clearfix">
941 941 <div class="comment-title pull-left">
942 942 Commenting on line o80.
943 943 </div>
944 944 <div class="comment-help pull-right">
945 945 Comments parsed using <a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html">RST</a> syntax with <span class="tooltip" title="Use @username inside this text to send notification to this RhodeCode user">@mention</span> support.
946 946 </div>
947 947 <div style="clear: both"></div>
948 948 <textarea id="text_o80" name="text" class="comment-block-ta ac-input" autocomplete="off"></textarea>
949 949 </div>
950 950 <div id="preview-container_o80" class="clearfix" style="display: none;">
951 951 <div class="comment-help">
952 952 Comment preview
953 953 </div>
954 954 <div id="preview-box_o80" class="preview-box"></div>
955 955 </div>
956 956 <div class="comment-button pull-right">
957 957 <input type="hidden" name="f_path" value="rhodecode/tests/functional/test_compare_local.py">
958 958 <input type="hidden" name="line" value="o80">
959 959 <div id="preview-btn_o80" class="btn btn-default">Preview</div>
960 960 <div id="edit-btn_o80" class="btn" style="display: none;">Edit</div>
961 961 <input class="btn btn-success save-inline-form" id="save" name="save" type="submit" value="Comment">
962 962 </div>
963 963 <div class="comment-button hide-inline-form-button">
964 964 <input class="btn hide-inline-form" id="hide-inline-form" name="hide-inline-form" type="reset" value="Cancel">
965 965 </div>
966 966 </form>
967 967 </div>
968 968 </td></tr>
969 969 <tr class="line add">
970 970 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
971 971 <td id="rhodecodetestsfunctionaltest_compare_localpy_n80" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n80">80</a></td>
972 972 <td class="code ">
973 973 <pre> response.mustcontain('%s@%s' % (
974 974 </pre>
975 975 </td>
976 976 </tr>
977 977 <tr class="line add">
978 978 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
979 979 <td id="rhodecodetestsfunctionaltest_compare_localpy_n81" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n81">81</a></td>
980 980 <td class="code ">
981 981 <pre> backend.repo_name,
982 982 </pre>
983 983 </td>
984 984 </tr>
985 985 <tr class="line unmod">
986 986 <td id="rhodecodetestsfunctionaltest_compare_localpy_o81" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o81">81</a></td>
987 987 <td id="rhodecodetestsfunctionaltest_compare_localpy_n82" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n82">82</a></td>
988 988 <td class="code ">
989 989 <pre> revisions[backend.alias]['branch']))
990 990 </pre>
991 991 </td>
992 992 </tr>
993 993 <tr class="line del">
994 994 <td id="rhodecodetestsfunctionaltest_compare_localpy_o82" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o82">82</a></td>
995 995 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n"></a></td>
996 996 <td class="code ">
997 997 <pre> response.mustcontain('%s@%s' % (<del>backend.repo_name,</del>
998 998 </pre>
999 999 </td>
1000 1000 </tr>
1001 1001 <tr class="line add">
1002 1002 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
1003 1003 <td id="rhodecodetestsfunctionaltest_compare_localpy_n83" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n83">83</a></td>
1004 1004 <td class="code ">
1005 1005 <pre> response.mustcontain('%s@%s' % (
1006 1006 </pre>
1007 1007 </td>
1008 1008 </tr>
1009 1009 <tr class="line add">
1010 1010 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
1011 1011 <td id="rhodecodetestsfunctionaltest_compare_localpy_n84" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n84">84</a></td>
1012 1012 <td class="code ">
1013 1013 <pre> backend.repo_name,
1014 1014 </pre>
1015 1015 </td>
1016 1016 </tr>
1017 1017 <tr class="line unmod">
1018 1018 <td id="rhodecodetestsfunctionaltest_compare_localpy_o83" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o83">83</a></td>
1019 1019 <td id="rhodecodetestsfunctionaltest_compare_localpy_n85" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n85">85</a></td>
1020 1020 <td class="code ">
1021 1021 <pre> revisions[backend.alias]['tag']))
1022 1022 </pre>
1023 1023 </td>
1024 1024 </tr>
1025 1025 <tr class="line unmod">
1026 1026 <td id="rhodecodetestsfunctionaltest_compare_localpy_o84" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o84">84</a></td>
1027 1027 <td id="rhodecodetestsfunctionaltest_compare_localpy_n86" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n86">86</a></td>
1028 1028 <td class="code ">
1029 1029 <pre> response.mustcontain(revisions[backend.alias]['response'])
1030 1030 </pre>
1031 1031 </td>
1032 1032 </tr>
1033 1033 <tr class="line unmod">
1034 1034 <td id="rhodecodetestsfunctionaltest_compare_localpy_o85" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o85">85</a></td>
1035 1035 <td id="rhodecodetestsfunctionaltest_compare_localpy_n87" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n87">87</a></td>
1036 1036 <td class="code ">
1037 1037 <pre></pre>
1038 1038 </td>
1039 1039 </tr>
1040 1040 </tbody></table>
1041 1041 </div>
1042 1042 </div>
1043 1043 </div>
1044 1044
1045 1045
1046 1046
1047 1047 <!--
1048 1048 Side-by-side diff
1049 1049 -->
1050 1050
1051 1051 <h2>Side-by-side diff</h2>
1052 1052
1053 1053 <div class="box">
1054 1054 <div class="diff-container" style="overflow-x: hidden">
1055 1055 <div class="diffblock comm" style="margin:3px; padding:1px">
1056 1056 <div class="code-header">
1057 1057 <div class="changeset_header">
1058 1058 <div class="changeset_file">
1059 1059 <i class="icon-file"></i>
1060 1060 <a href="/pygments/files/ea295cfb622620f5ba13e226ec531e3fe5296399/tests/test_basic_api.py">tests/test_basic_api.py</a>
1061 1061 [mode: <span id="selected_mode">python</span>]
1062 1062 </div>
1063 1063 <div class="diff-actions">
1064 1064 <a href="/pygments/diff/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&amp;diff=diff&amp;diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&amp;fulldiff=1" class="tooltip" title="Show full diff for this file">
1065 1065 <img class="icon" src="/images/icons/page_white_go.png">
1066 1066 </a>
1067 1067 <a href="/pygments/diff-2way/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&amp;diff=diff&amp;diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&amp;fulldiff=1" class="tooltip" title="Show full side-by-side diff for this file" tt_title="Show full side-by-side diff for this file">
1068 1068 <img class="icon" src="/images/icons/application_double.png">
1069 1069 </a>
1070 1070 <a href="/pygments/diff/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&amp;diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&amp;diff=raw" class="tooltip" title="Raw diff">
1071 1071 <img class="icon" src="/images/icons/page_white.png">
1072 1072 </a>
1073 1073 <a href="/pygments/diff/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&amp;diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&amp;diff=download" class="tooltip" title="Download diff">
1074 1074 <img class="icon" src="/images/icons/page_save.png">
1075 1075 </a>
1076 1076 <label><input id="ignorews" name="ignorews" type="checkbox" value="1">ignore white space</label>
1077 1077 <label><input id="edit_mode" name="edit_mode" type="checkbox" value="1">turn on edit mode</label>
1078 1078
1079 1079 </div>
1080 1080 <div style="float: right; padding: 0px 10px 0px 0px">
1081 1081 r1538:de45f950b669 ... r1539:ea295cfb6226
1082 1082 </div>
1083 1083 </div>
1084 1084 </div>
1085 1085 <div id="compare"></div>
1086 1086 </div>
1087 1087 </div>
1088 1088
1089 1089 <script>
1090 1090 $(document).ready(function () {
1091 1091 var example_lines = '1\n2\n3\n4\n5\n6\n7\n8\n9\n \n';
1092 1092
1093 1093 $('#compare').mergely({
1094 1094 width: 'auto',
1095 1095 height: '600',
1096 1096 fgcolor: {a:'#ddffdd',c:'#cccccc',d:'#ffdddd'},
1097 1097 bgcolor: '#fff',
1098 1098 viewport: true,
1099 1099 cmsettings: {mode: 'text/plain', readOnly: true, lineWrapping: false, lineNumbers: true},
1100 1100 lhs: function(setValue) {
1101 1101 if("False" == "True"){
1102 1102 setValue('Binary file')
1103 1103 }
1104 1104 else if("MercurialCommit" == "EmptyCommit"){
1105 1105 setValue('');
1106 1106 }
1107 1107 else{
1108 1108 var left_value = example_lines.slice(0, 10) +
1109 1109 '123456789 '.repeat(10) +
1110 1110 '\n'+
1111 1111 example_lines.slice(10, 20);
1112 1112 setValue(left_value + example_lines.repeat(9));
1113 1113 }
1114 1114
1115 1115 },
1116 1116 rhs: function(setValue) {
1117 1117 if("False" == "True"){
1118 1118 setValue('Binary file')
1119 1119 }
1120 1120 else if("MercurialCommit" == "EmptyCommit"){
1121 1121 setValue('');
1122 1122 }
1123 1123 else{
1124 1124 var right_value = example_lines +
1125 1125 example_lines.slice(0, 8) +
1126 1126 'abcdefghi '.repeat(10) +
1127 1127 '\n'+
1128 1128 example_lines.slice(8, 20);
1129 1129 setValue(right_value + example_lines.repeat(9));
1130 1130 }
1131 1131 },
1132 1132 });
1133 1133
1134 1134 var detected_mode = detectCodeMirrorModeFromExt('test_basic_api.py', true);
1135 1135 if(detected_mode){
1136 1136 setCodeMirrorMode($('#compare').mergely('cm', 'lhs'), detected_mode);
1137 1137 setCodeMirrorMode($('#compare').mergely('cm', 'rhs'), detected_mode);
1138 1138 $('#selected_mode').html(detected_mode);
1139 1139 }
1140 1140
1141 1141 $('#ignorews').change(function(e){
1142 1142 var val = e.currentTarget.checked;
1143 1143 $('#compare').mergely('options', {ignorews: val});
1144 1144 $('#compare').mergely('update');
1145 1145 })
1146 1146 $('#edit_mode').change(function(e){
1147 1147 var val = !e.currentTarget.checked;
1148 1148 $('#compare').mergely('cm', 'lhs').setOption('readOnly', val);
1149 1149 $('#compare').mergely('cm', 'rhs').setOption('readOnly', val);
1150 1150 $('#compare').mergely('update');
1151 1151 })
1152 1152 });
1153 1153 </script>
1154 1154
1155 1155 </div>
1156 1156
1157 1157 <!-- end examples -->
1158 1158
1159 1159 </div>
1160 1160 </div>
1161 1161 </div>
1162 1162 </%def>
@@ -1,64 +1,64 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <!DOCTYPE html>
3 3 <html xmlns="http://www.w3.org/1999/xhtml">
4 4 <head>
5 5 <title>Error - ${c.error_message}</title>
6 6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 7 <meta name="robots" content="index, nofollow"/>
8 8 <link rel="icon" href="${h.asset('images/favicon.ico')}" sizes="16x16 32x32" type="image/png" />
9 9
10 10
11 11 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
12 12 %if c.redirect_time:
13 13 <meta http-equiv="refresh" content="${c.redirect_time}; url=${c.url_redirect}"/>
14 14 %endif
15 15
16 <link rel="stylesheet" type="text/css" href="${h.asset('css/style.css')}" media="screen"/>
16 <link rel="stylesheet" type="text/css" href="${h.asset('css/style.css', ver=c.rhodecode_version_hash)}" media="screen"/>
17 17 <!--[if IE]>
18 18 <link rel="stylesheet" type="text/css" href="${h.asset('css/ie.css')}" media="screen"/>
19 19 <![endif]-->
20 20 <style>body { background:#eeeeee; }</style>
21 21
22 <script type="text/javascript" src="${h.asset('js/scripts.js')}"></script>
22 <script type="text/javascript" src="${h.asset('js/scripts.js', ver=c.rhodecode_version_hash)}"></script>
23 23 </head>
24 24 <body>
25 25 <%include file="/base/flash_msg.html"/>
26 26
27 27 <div class="wrapper error_page">
28 28 <div class="sidebar">
29 29 <a href="${h.url('home')}"><img class="error-page-logo" src="${h.asset('images/RhodeCode_Logo_Black.png')}" alt="RhodeCode"/></a>
30 30 </div>
31 31 <div class="main-content">
32 32 <h1>
33 33 <span class="error-branding">
34 34 ${h.branding(c.rhodecode_name)}
35 35 </span><br/>
36 36 ${c.error_message} | <span class="error_message">${c.error_explanation}</span>
37 37 </h1>
38 38 %if c.redirect_time:
39 39 <p>${_('You will be redirected to %s in %s seconds') % (c.redirect_module,c.redirect_time)}</p>
40 40 %endif
41 41 <div class="inner-column">
42 42 <h4>Possible Cause</h4>
43 43 <ul>
44 44 <li>The resource may have been deleted.</li>
45 45 <li>You may not have access to this repository.</li>
46 46 <li>The link may be incorrect.</li>
47 47 </ul>
48 48 </div>
49 49 <div class="inner-column">
50 50 <h4>Support</h4>
51 51 <p>For support, go to <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>.
52 52 It may be useful to include your log file; see the log file locations <a href="${h.url('enterprise_log_file_locations')}">here</a>.
53 53 </p>
54 54 </div>
55 55 <div class="inner-column">
56 56 <h4>Documentation</h4>
57 57 <p>For more information, see <a href="${h.url('enterprise_docs')}">docs.rhodecode.com</a>.</p>
58 58 </div>
59 59 </div>
60 60 </div>
61 61
62 62 </body>
63 63
64 64 </html>
@@ -1,381 +1,390 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import json
22 22
23 23 from mock import patch
24 24 import pytest
25 from pylons import tmpl_context as c
25 26
26 27 import rhodecode
27 28 from rhodecode.lib.utils import map_groups
28 29 from rhodecode.model.db import Repository, User, RepoGroup
29 30 from rhodecode.model.meta import Session
30 31 from rhodecode.model.repo import RepoModel
31 32 from rhodecode.model.repo_group import RepoGroupModel
32 33 from rhodecode.model.settings import SettingsModel
33 34 from rhodecode.tests import TestController, url, TEST_USER_ADMIN_LOGIN
34 35 from rhodecode.tests.fixture import Fixture
35 36
36 37
37 38 fixture = Fixture()
38 39
39 40
40 41 class TestHomeController(TestController):
41 42
42 43 def test_index(self):
43 44 self.log_user()
44 45 response = self.app.get(url(controller='home', action='index'))
45 46 # if global permission is set
46 47 response.mustcontain('Add Repository')
47 48
48 49 # search for objects inside the JavaScript JSON
49 50 for repo in Repository.getAll():
50 51 response.mustcontain('"name_raw": "%s"' % repo.repo_name)
51 52
53 def test_index_contains_statics_with_ver(self):
54 self.log_user()
55 response = self.app.get(url(controller='home', action='index'))
56
57 rhodecode_version_hash = c.rhodecode_version_hash
58 response.mustcontain('style.css?ver={0}'.format(rhodecode_version_hash))
59 response.mustcontain('scripts.js?ver={0}'.format(rhodecode_version_hash))
60
52 61 def test_index_contains_backend_specific_details(self, backend):
53 62 self.log_user()
54 63 response = self.app.get(url(controller='home', action='index'))
55 64 tip = backend.repo.get_commit().raw_id
56 65
57 66 # html in javascript variable:
58 67 response.mustcontain(r'<i class=\"icon-%s\"' % (backend.alias, ))
59 68 response.mustcontain(r'href=\"/%s\"' % (backend.repo_name, ))
60 69
61 70 response.mustcontain("""/%s/changeset/%s""" % (backend.repo_name, tip))
62 71 response.mustcontain("""Added a symlink""")
63 72
64 73 def test_index_with_anonymous_access_disabled(self):
65 74 with fixture.anon_access(False):
66 75 response = self.app.get(url(controller='home', action='index'),
67 76 status=302)
68 77 assert 'login' in response.location
69 78
70 79 def test_index_page_on_groups(self, autologin_user, repo_group):
71 80 response = self.app.get(url('repo_group_home', group_name='gr1'))
72 81 response.mustcontain("gr1/repo_in_group")
73 82
74 83 def test_index_page_on_group_with_trailing_slash(
75 84 self, autologin_user, repo_group):
76 85 response = self.app.get(url('repo_group_home', group_name='gr1') + '/')
77 86 response.mustcontain("gr1/repo_in_group")
78 87
79 88 @pytest.fixture(scope='class')
80 89 def repo_group(self, request):
81 90 gr = fixture.create_repo_group('gr1')
82 91 fixture.create_repo(name='gr1/repo_in_group', repo_group=gr)
83 92
84 93 @request.addfinalizer
85 94 def cleanup():
86 95 RepoModel().delete('gr1/repo_in_group')
87 96 RepoGroupModel().delete(repo_group='gr1', force_delete=True)
88 97 Session().commit()
89 98
90 99 def test_index_with_name_with_tags(self, autologin_user):
91 100 user = User.get_by_username('test_admin')
92 101 user.name = '<img src="/image1" onload="alert(\'Hello, World!\');">'
93 102 user.lastname = (
94 103 '<img src="/image2" onload="alert(\'Hello, World!\');">')
95 104 Session().add(user)
96 105 Session().commit()
97 106
98 107 response = self.app.get(url(controller='home', action='index'))
99 108 response.mustcontain(
100 109 '&lt;img src=&#34;/image1&#34; onload=&#34;'
101 110 'alert(&#39;Hello, World!&#39;);&#34;&gt;')
102 111 response.mustcontain(
103 112 '&lt;img src=&#34;/image2&#34; onload=&#34;'
104 113 'alert(&#39;Hello, World!&#39;);&#34;&gt;')
105 114
106 115 @pytest.mark.parametrize("name, state", [
107 116 ('Disabled', False),
108 117 ('Enabled', True),
109 118 ])
110 119 def test_index_show_version(self, autologin_user, name, state):
111 120 version_string = 'RhodeCode Enterprise %s' % rhodecode.__version__
112 121
113 122 sett = SettingsModel().create_or_update_setting(
114 123 'show_version', state, 'bool')
115 124 Session().add(sett)
116 125 Session().commit()
117 126 SettingsModel().invalidate_settings_cache()
118 127
119 128 response = self.app.get(url(controller='home', action='index'))
120 129 if state is True:
121 130 response.mustcontain(version_string)
122 131 if state is False:
123 132 response.mustcontain(no=[version_string])
124 133
125 134
126 135 class TestUserAutocompleteData(TestController):
127 136 def test_returns_list_of_users(self, user_util):
128 137 self.log_user()
129 138 user = user_util.create_user(is_active=True)
130 139 user_name = user.username
131 140 response = self.app.get(
132 141 url(controller='home', action='user_autocomplete_data'),
133 142 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
134 143 result = json.loads(response.body)
135 144 values = [suggestion['value'] for suggestion in result['suggestions']]
136 145 assert user_name in values
137 146
138 147 def test_returns_inactive_users_when_active_flag_sent(self, user_util):
139 148 self.log_user()
140 149 user = user_util.create_user(is_active=False)
141 150 user_name = user.username
142 151 response = self.app.get(
143 152 url(controller='home', action='user_autocomplete_data',
144 153 user_groups='true', active='0'),
145 154 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
146 155 result = json.loads(response.body)
147 156 values = [suggestion['value'] for suggestion in result['suggestions']]
148 157 assert user_name in values
149 158
150 159 def test_returns_groups_when_user_groups_sent(self, user_util):
151 160 self.log_user()
152 161 group = user_util.create_user_group(user_groups_active=True)
153 162 group_name = group.users_group_name
154 163 response = self.app.get(
155 164 url(controller='home', action='user_autocomplete_data',
156 165 user_groups='true'),
157 166 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
158 167 result = json.loads(response.body)
159 168 values = [suggestion['value'] for suggestion in result['suggestions']]
160 169 assert group_name in values
161 170
162 171 def test_result_is_limited_when_query_is_sent(self):
163 172 self.log_user()
164 173 fake_result = [
165 174 {
166 175 'first_name': 'John',
167 176 'value_display': 'hello{} (John Smith)'.format(i),
168 177 'icon_link': '/images/user14.png',
169 178 'value': 'hello{}'.format(i),
170 179 'last_name': 'Smith',
171 180 'username': 'hello{}'.format(i),
172 181 'id': i,
173 182 'value_type': u'user'
174 183 }
175 184 for i in range(10)
176 185 ]
177 186 users_patcher = patch.object(
178 187 RepoModel, 'get_users', return_value=fake_result)
179 188 groups_patcher = patch.object(
180 189 RepoModel, 'get_user_groups', return_value=fake_result)
181 190
182 191 query = 'hello'
183 192 with users_patcher as users_mock, groups_patcher as groups_mock:
184 193 response = self.app.get(
185 194 url(controller='home', action='user_autocomplete_data',
186 195 user_groups='true', query=query),
187 196 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
188 197
189 198 result = json.loads(response.body)
190 199 users_mock.assert_called_once_with(
191 200 name_contains=query, only_active=True)
192 201 groups_mock.assert_called_once_with(
193 202 name_contains=query, only_active=True)
194 203 assert len(result['suggestions']) == 20
195 204
196 205
197 206 def assert_and_get_content(result):
198 207 repos = []
199 208 groups = []
200 209 commits = []
201 210 for data in result:
202 211 for data_item in data['children']:
203 212 assert data_item['id']
204 213 assert data_item['text']
205 214 assert data_item['url']
206 215 if data_item['type'] == 'repo':
207 216 repos.append(data_item)
208 217 elif data_item['type'] == 'group':
209 218 groups.append(data_item)
210 219 elif data_item['type'] == 'commit':
211 220 commits.append(data_item)
212 221 else:
213 222 raise Exception('invalid type %s' % data_item['type'])
214 223
215 224 return repos, groups, commits
216 225
217 226
218 227 class TestGotoSwitcherData(TestController):
219 228 required_repos_with_groups = [
220 229 'abc',
221 230 'abc-fork',
222 231 'forks/abcd',
223 232 'abcd',
224 233 'abcde',
225 234 'a/abc',
226 235 'aa/abc',
227 236 'aaa/abc',
228 237 'aaaa/abc',
229 238 'repos_abc/aaa/abc',
230 239 'abc_repos/abc',
231 240 'abc_repos/abcd',
232 241 'xxx/xyz',
233 242 'forked-abc/a/abc'
234 243 ]
235 244
236 245 @pytest.fixture(autouse=True, scope='class')
237 246 def prepare(self, request, pylonsapp):
238 247 for repo_and_group in self.required_repos_with_groups:
239 248 # create structure of groups and return the last group
240 249
241 250 repo_group = map_groups(repo_and_group)
242 251
243 252 RepoModel()._create_repo(
244 253 repo_and_group, 'hg', 'test-ac', TEST_USER_ADMIN_LOGIN,
245 254 repo_group=getattr(repo_group, 'group_id', None))
246 255
247 256 Session().commit()
248 257
249 258 request.addfinalizer(self.cleanup)
250 259
251 260 def cleanup(self):
252 261 # first delete all repos
253 262 for repo_and_groups in self.required_repos_with_groups:
254 263 repo = Repository.get_by_repo_name(repo_and_groups)
255 264 if repo:
256 265 RepoModel().delete(repo)
257 266 Session().commit()
258 267
259 268 # then delete all empty groups
260 269 for repo_and_groups in self.required_repos_with_groups:
261 270 if '/' in repo_and_groups:
262 271 r_group = repo_and_groups.rsplit('/', 1)[0]
263 272 repo_group = RepoGroup.get_by_group_name(r_group)
264 273 if not repo_group:
265 274 continue
266 275 parents = repo_group.parents
267 276 RepoGroupModel().delete(repo_group, force_delete=True)
268 277 Session().commit()
269 278
270 279 for el in reversed(parents):
271 280 RepoGroupModel().delete(el, force_delete=True)
272 281 Session().commit()
273 282
274 283 def test_returns_list_of_repos_and_groups(self):
275 284 self.log_user()
276 285
277 286 response = self.app.get(
278 287 url(controller='home', action='goto_switcher_data'),
279 288 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
280 289 result = json.loads(response.body)['results']
281 290
282 291 repos, groups, commits = assert_and_get_content(result)
283 292
284 293 assert len(repos) == len(Repository.get_all())
285 294 assert len(groups) == len(RepoGroup.get_all())
286 295 assert len(commits) == 0
287 296
288 297 def test_returns_list_of_repos_and_groups_filtered(self):
289 298 self.log_user()
290 299
291 300 response = self.app.get(
292 301 url(controller='home', action='goto_switcher_data'),
293 302 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', },
294 303 params={'query': 'abc'}, status=200)
295 304 result = json.loads(response.body)['results']
296 305
297 306 repos, groups, commits = assert_and_get_content(result)
298 307
299 308 assert len(repos) == 13
300 309 assert len(groups) == 5
301 310 assert len(commits) == 0
302 311
303 312 def test_returns_list_of_properly_sorted_and_filtered(self):
304 313 self.log_user()
305 314
306 315 response = self.app.get(
307 316 url(controller='home', action='goto_switcher_data'),
308 317 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', },
309 318 params={'query': 'abc'}, status=200)
310 319 result = json.loads(response.body)['results']
311 320
312 321 repos, groups, commits = assert_and_get_content(result)
313 322
314 323 test_repos = [x['text'] for x in repos[:4]]
315 324 assert ['abc', 'abcd', 'a/abc', 'abcde'] == test_repos
316 325
317 326 test_groups = [x['text'] for x in groups[:4]]
318 327 assert ['abc_repos', 'repos_abc',
319 328 'forked-abc', 'forked-abc/a'] == test_groups
320 329
321 330
322 331 class TestRepoListData(TestController):
323 332 def test_returns_list_of_repos_and_groups(self, user_util):
324 333 self.log_user()
325 334
326 335 response = self.app.get(
327 336 url(controller='home', action='repo_list_data'),
328 337 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
329 338 result = json.loads(response.body)['results']
330 339
331 340 repos, groups, commits = assert_and_get_content(result)
332 341
333 342 assert len(repos) == len(Repository.get_all())
334 343 assert len(groups) == 0
335 344 assert len(commits) == 0
336 345
337 346 def test_returns_list_of_repos_and_groups_filtered(self):
338 347 self.log_user()
339 348
340 349 response = self.app.get(
341 350 url(controller='home', action='repo_list_data'),
342 351 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', },
343 352 params={'query': 'vcs_test_git'}, status=200)
344 353 result = json.loads(response.body)['results']
345 354
346 355 repos, groups, commits = assert_and_get_content(result)
347 356
348 357 assert len(repos) == len(Repository.query().filter(
349 358 Repository.repo_name.ilike('%vcs_test_git%')).all())
350 359 assert len(groups) == 0
351 360 assert len(commits) == 0
352 361
353 362 def test_returns_list_of_repos_and_groups_filtered_with_type(self):
354 363 self.log_user()
355 364
356 365 response = self.app.get(
357 366 url(controller='home', action='repo_list_data'),
358 367 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', },
359 368 params={'query': 'vcs_test_git', 'repo_type': 'git'}, status=200)
360 369 result = json.loads(response.body)['results']
361 370
362 371 repos, groups, commits = assert_and_get_content(result)
363 372
364 373 assert len(repos) == len(Repository.query().filter(
365 374 Repository.repo_name.ilike('%vcs_test_git%')).all())
366 375 assert len(groups) == 0
367 376 assert len(commits) == 0
368 377
369 378 def test_returns_list_of_repos_non_ascii_query(self):
370 379 self.log_user()
371 380 response = self.app.get(
372 381 url(controller='home', action='repo_list_data'),
373 382 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', },
374 383 params={'query': 'ć_vcs_test_ą', 'repo_type': 'git'}, status=200)
375 384 result = json.loads(response.body)['results']
376 385
377 386 repos, groups, commits = assert_and_get_content(result)
378 387
379 388 assert len(repos) == 0
380 389 assert len(groups) == 0
381 390 assert len(commits) == 0
General Comments 0
You need to be logged in to leave comments. Login now