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