Reformat using black
This commit is contained in:
parent
efee4ad081
commit
a87fb49918
221 changed files with 19127 additions and 7310 deletions
|
@ -8,19 +8,33 @@ from statici18n.templatetags.statici18n import inlinei18n
|
|||
|
||||
from judge.highlight_code import highlight_code
|
||||
from judge.user_translations import gettext
|
||||
from . import (camo, chat, datetime, filesize, gravatar, language, markdown, rating, reference, render, social,
|
||||
spaceless, submission, timedelta)
|
||||
from . import (
|
||||
camo,
|
||||
chat,
|
||||
datetime,
|
||||
filesize,
|
||||
gravatar,
|
||||
language,
|
||||
markdown,
|
||||
rating,
|
||||
reference,
|
||||
render,
|
||||
social,
|
||||
spaceless,
|
||||
submission,
|
||||
timedelta,
|
||||
)
|
||||
from . import registry
|
||||
|
||||
registry.function('str', str)
|
||||
registry.filter('str', str)
|
||||
registry.filter('json', json.dumps)
|
||||
registry.filter('highlight', highlight_code)
|
||||
registry.filter('urlquote', urlquote)
|
||||
registry.filter('roundfloat', round)
|
||||
registry.function('inlinei18n', inlinei18n)
|
||||
registry.function('mptt_tree', get_cached_trees)
|
||||
registry.function('user_trans', gettext)
|
||||
registry.function("str", str)
|
||||
registry.filter("str", str)
|
||||
registry.filter("json", json.dumps)
|
||||
registry.filter("highlight", highlight_code)
|
||||
registry.filter("urlquote", urlquote)
|
||||
registry.filter("roundfloat", round)
|
||||
registry.function("inlinei18n", inlinei18n)
|
||||
registry.function("mptt_tree", get_cached_trees)
|
||||
registry.function("user_trans", gettext)
|
||||
|
||||
|
||||
@registry.function
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
from judge.utils.camo import client as camo_client
|
||||
from . import registry
|
||||
|
||||
|
||||
@registry.filter
|
||||
def camo(url):
|
||||
if camo_client is None:
|
||||
return url
|
||||
return camo_client.rewrite_url(url)
|
||||
return camo_client.rewrite_url(url)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from . import registry
|
||||
from chat_box.utils import encrypt_url
|
||||
|
||||
|
||||
@registry.function
|
||||
def chat_param(request_profile, profile):
|
||||
return encrypt_url(request_profile.id, profile.id)
|
||||
return encrypt_url(request_profile.id, profile.id)
|
||||
|
|
|
@ -10,7 +10,7 @@ from . import registry
|
|||
def localtime_wrapper(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(datetime, *args, **kwargs):
|
||||
if getattr(datetime, 'convert_to_local_time', True):
|
||||
if getattr(datetime, "convert_to_local_time", True):
|
||||
datetime = localtime(datetime)
|
||||
return func(datetime, *args, **kwargs)
|
||||
|
||||
|
@ -22,6 +22,6 @@ registry.filter(localtime_wrapper(time))
|
|||
|
||||
|
||||
@registry.function
|
||||
@registry.render_with('widgets/relative-time.html')
|
||||
def relative_time(time, format=_('N j, Y, g:i a'), rel=_('{time}'), abs=_('on {time}')):
|
||||
return {'time': time, 'format': format, 'rel_format': rel, 'abs_format': abs}
|
||||
@registry.render_with("widgets/relative-time.html")
|
||||
def relative_time(time, format=_("N j, Y, g:i a"), rel=_("{time}"), abs=_("on {time}")):
|
||||
return {"time": time, "format": format, "rel_format": rel, "abs_format": abs}
|
||||
|
|
|
@ -13,24 +13,28 @@ def _format_size(bytes, callback):
|
|||
PB = 1 << 50
|
||||
|
||||
if bytes < KB:
|
||||
return callback('', bytes)
|
||||
return callback("", bytes)
|
||||
elif bytes < MB:
|
||||
return callback('K', bytes / KB)
|
||||
return callback("K", bytes / KB)
|
||||
elif bytes < GB:
|
||||
return callback('M', bytes / MB)
|
||||
return callback("M", bytes / MB)
|
||||
elif bytes < TB:
|
||||
return callback('G', bytes / GB)
|
||||
return callback("G", bytes / GB)
|
||||
elif bytes < PB:
|
||||
return callback('T', bytes / TB)
|
||||
return callback("T", bytes / TB)
|
||||
else:
|
||||
return callback('P', bytes / PB)
|
||||
return callback("P", bytes / PB)
|
||||
|
||||
|
||||
@registry.filter
|
||||
def kbdetailformat(bytes):
|
||||
return avoid_wrapping(_format_size(bytes * 1024, lambda x, y: ['%d %sB', '%.2f %sB'][bool(x)] % (y, x)))
|
||||
return avoid_wrapping(
|
||||
_format_size(
|
||||
bytes * 1024, lambda x, y: ["%d %sB", "%.2f %sB"][bool(x)] % (y, x)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@registry.filter
|
||||
def kbsimpleformat(kb):
|
||||
return _format_size(kb * 1024, lambda x, y: '%.0f%s' % (y, x or 'B'))
|
||||
return _format_size(kb * 1024, lambda x, y: "%.0f%s" % (y, x or "B"))
|
||||
|
|
|
@ -17,9 +17,13 @@ def gravatar(email, size=80, default=None):
|
|||
elif isinstance(email, AbstractUser):
|
||||
email = email.email
|
||||
|
||||
gravatar_url = '//www.gravatar.com/avatar/' + hashlib.md5(utf8bytes(email.strip().lower())).hexdigest() + '?'
|
||||
args = {'d': 'identicon', 's': str(size)}
|
||||
gravatar_url = (
|
||||
"//www.gravatar.com/avatar/"
|
||||
+ hashlib.md5(utf8bytes(email.strip().lower())).hexdigest()
|
||||
+ "?"
|
||||
)
|
||||
args = {"d": "identicon", "s": str(size)}
|
||||
if default:
|
||||
args['f'] = 'y'
|
||||
args["f"] = "y"
|
||||
gravatar_url += urlencode(args)
|
||||
return gravatar_url
|
||||
|
|
|
@ -3,7 +3,7 @@ from django.utils import translation
|
|||
from . import registry
|
||||
|
||||
|
||||
@registry.function('language_info')
|
||||
@registry.function("language_info")
|
||||
def get_language_info(language):
|
||||
# ``language`` is either a language code string or a sequence
|
||||
# with the language code as its first item
|
||||
|
@ -13,6 +13,6 @@ def get_language_info(language):
|
|||
return translation.get_language_info(str(language))
|
||||
|
||||
|
||||
@registry.function('language_info_list')
|
||||
@registry.function("language_info_list")
|
||||
def get_language_info_list(langs):
|
||||
return [get_language_info(lang) for lang in langs]
|
||||
|
|
|
@ -12,22 +12,28 @@ from lxml.etree import ParserError, XMLSyntaxError
|
|||
from judge.highlight_code import highlight_code
|
||||
from judge.jinja2.markdown.lazy_load import lazy_load as lazy_load_processor
|
||||
from judge.jinja2.markdown.math import MathInlineGrammar, MathInlineLexer, MathRenderer
|
||||
from judge.jinja2.markdown.spoiler import SpoilerInlineGrammar, SpoilerInlineLexer, SpoilerRenderer
|
||||
from judge.jinja2.markdown.spoiler import (
|
||||
SpoilerInlineGrammar,
|
||||
SpoilerInlineLexer,
|
||||
SpoilerRenderer,
|
||||
)
|
||||
from judge.utils.camo import client as camo_client
|
||||
from judge.utils.texoid import TEXOID_ENABLED, TexoidRenderer
|
||||
from .. import registry
|
||||
|
||||
logger = logging.getLogger('judge.html')
|
||||
logger = logging.getLogger("judge.html")
|
||||
|
||||
NOFOLLOW_WHITELIST = settings.NOFOLLOW_EXCLUDED
|
||||
|
||||
|
||||
class CodeSafeInlineGrammar(mistune.InlineGrammar):
|
||||
double_emphasis = re.compile(r'^\*{2}([\s\S]+?)()\*{2}(?!\*)') # **word**
|
||||
emphasis = re.compile(r'^\*((?:\*\*|[^\*])+?)()\*(?!\*)') # *word*
|
||||
double_emphasis = re.compile(r"^\*{2}([\s\S]+?)()\*{2}(?!\*)") # **word**
|
||||
emphasis = re.compile(r"^\*((?:\*\*|[^\*])+?)()\*(?!\*)") # *word*
|
||||
|
||||
|
||||
class AwesomeInlineGrammar(MathInlineGrammar, SpoilerInlineGrammar, CodeSafeInlineGrammar):
|
||||
class AwesomeInlineGrammar(
|
||||
MathInlineGrammar, SpoilerInlineGrammar, CodeSafeInlineGrammar
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
|
@ -37,8 +43,8 @@ class AwesomeInlineLexer(MathInlineLexer, SpoilerInlineLexer, mistune.InlineLexe
|
|||
|
||||
class AwesomeRenderer(MathRenderer, SpoilerRenderer, mistune.Renderer):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.nofollow = kwargs.pop('nofollow', True)
|
||||
self.texoid = TexoidRenderer() if kwargs.pop('texoid', False) else None
|
||||
self.nofollow = kwargs.pop("nofollow", True)
|
||||
self.texoid = TexoidRenderer() if kwargs.pop("texoid", False) else None
|
||||
self.parser = HTMLParser()
|
||||
super(AwesomeRenderer, self).__init__(*args, **kwargs)
|
||||
|
||||
|
@ -51,18 +57,18 @@ class AwesomeRenderer(MathRenderer, SpoilerRenderer, mistune.Renderer):
|
|||
else:
|
||||
if url.netloc and url.netloc not in NOFOLLOW_WHITELIST:
|
||||
return ' rel="nofollow"'
|
||||
return ''
|
||||
return ""
|
||||
|
||||
def autolink(self, link, is_email=False):
|
||||
text = link = mistune.escape(link)
|
||||
if is_email:
|
||||
link = 'mailto:%s' % link
|
||||
link = "mailto:%s" % link
|
||||
return '<a href="%s"%s>%s</a>' % (link, self._link_rel(link), text)
|
||||
|
||||
def table(self, header, body):
|
||||
return (
|
||||
'<table class="table">\n<thead>%s</thead>\n'
|
||||
'<tbody>\n%s</tbody>\n</table>\n'
|
||||
"<tbody>\n%s</tbody>\n</table>\n"
|
||||
) % (header, body)
|
||||
|
||||
def link(self, link, title, text):
|
||||
|
@ -70,40 +76,53 @@ class AwesomeRenderer(MathRenderer, SpoilerRenderer, mistune.Renderer):
|
|||
if not title:
|
||||
return '<a href="%s"%s>%s</a>' % (link, self._link_rel(link), text)
|
||||
title = mistune.escape(title, quote=True)
|
||||
return '<a href="%s" title="%s"%s>%s</a>' % (link, title, self._link_rel(link), text)
|
||||
return '<a href="%s" title="%s"%s>%s</a>' % (
|
||||
link,
|
||||
title,
|
||||
self._link_rel(link),
|
||||
text,
|
||||
)
|
||||
|
||||
def block_code(self, code, lang=None):
|
||||
if not lang:
|
||||
return '\n<pre><code>%s</code></pre>\n' % mistune.escape(code).rstrip()
|
||||
return "\n<pre><code>%s</code></pre>\n" % mistune.escape(code).rstrip()
|
||||
return highlight_code(code, lang)
|
||||
|
||||
def block_html(self, html):
|
||||
if self.texoid and html.startswith('<latex'):
|
||||
attr = html[6:html.index('>')]
|
||||
latex = html[html.index('>') + 1:html.rindex('<')]
|
||||
if self.texoid and html.startswith("<latex"):
|
||||
attr = html[6 : html.index(">")]
|
||||
latex = html[html.index(">") + 1 : html.rindex("<")]
|
||||
latex = self.parser.unescape(latex)
|
||||
result = self.texoid.get_result(latex)
|
||||
if not result:
|
||||
return '<pre>%s</pre>' % mistune.escape(latex, smart_amp=False)
|
||||
elif 'error' not in result:
|
||||
img = ('''<img src="%(svg)s" onerror="this.src='%(png)s';this.onerror=null"'''
|
||||
'width="%(width)s" height="%(height)s"%(tail)s>') % {
|
||||
'svg': result['svg'], 'png': result['png'],
|
||||
'width': result['meta']['width'], 'height': result['meta']['height'],
|
||||
'tail': ' /' if self.options.get('use_xhtml') else '',
|
||||
return "<pre>%s</pre>" % mistune.escape(latex, smart_amp=False)
|
||||
elif "error" not in result:
|
||||
img = (
|
||||
'''<img src="%(svg)s" onerror="this.src='%(png)s';this.onerror=null"'''
|
||||
'width="%(width)s" height="%(height)s"%(tail)s>'
|
||||
) % {
|
||||
"svg": result["svg"],
|
||||
"png": result["png"],
|
||||
"width": result["meta"]["width"],
|
||||
"height": result["meta"]["height"],
|
||||
"tail": " /" if self.options.get("use_xhtml") else "",
|
||||
}
|
||||
style = ['max-width: 100%',
|
||||
'height: %s' % result['meta']['height'],
|
||||
'max-height: %s' % result['meta']['height'],
|
||||
'width: %s' % result['meta']['height']]
|
||||
if 'inline' in attr:
|
||||
tag = 'span'
|
||||
style = [
|
||||
"max-width: 100%",
|
||||
"height: %s" % result["meta"]["height"],
|
||||
"max-height: %s" % result["meta"]["height"],
|
||||
"width: %s" % result["meta"]["height"],
|
||||
]
|
||||
if "inline" in attr:
|
||||
tag = "span"
|
||||
else:
|
||||
tag = 'div'
|
||||
style += ['text-align: center']
|
||||
return '<%s style="%s">%s</%s>' % (tag, ';'.join(style), img, tag)
|
||||
tag = "div"
|
||||
style += ["text-align: center"]
|
||||
return '<%s style="%s">%s</%s>' % (tag, ";".join(style), img, tag)
|
||||
else:
|
||||
return '<pre>%s</pre>' % mistune.escape(result['error'], smart_amp=False)
|
||||
return "<pre>%s</pre>" % mistune.escape(
|
||||
result["error"], smart_amp=False
|
||||
)
|
||||
return super(AwesomeRenderer, self).block_html(html)
|
||||
|
||||
def header(self, text, level, *args, **kwargs):
|
||||
|
@ -113,30 +132,41 @@ class AwesomeRenderer(MathRenderer, SpoilerRenderer, mistune.Renderer):
|
|||
@registry.filter
|
||||
def markdown(value, style, math_engine=None, lazy_load=False):
|
||||
styles = settings.MARKDOWN_STYLES.get(style, settings.MARKDOWN_DEFAULT_STYLE)
|
||||
escape = styles.get('safe_mode', True)
|
||||
nofollow = styles.get('nofollow', True)
|
||||
texoid = TEXOID_ENABLED and styles.get('texoid', False)
|
||||
math = hasattr(settings, 'MATHOID_URL') and styles.get('math', False)
|
||||
escape = styles.get("safe_mode", True)
|
||||
nofollow = styles.get("nofollow", True)
|
||||
texoid = TEXOID_ENABLED and styles.get("texoid", False)
|
||||
math = hasattr(settings, "MATHOID_URL") and styles.get("math", False)
|
||||
|
||||
post_processors = []
|
||||
if styles.get('use_camo', False) and camo_client is not None:
|
||||
if styles.get("use_camo", False) and camo_client is not None:
|
||||
post_processors.append(camo_client.update_tree)
|
||||
if lazy_load:
|
||||
post_processors.append(lazy_load_processor)
|
||||
|
||||
renderer = AwesomeRenderer(escape=escape, nofollow=nofollow, texoid=texoid,
|
||||
math=math and math_engine is not None, math_engine=math_engine)
|
||||
markdown = mistune.Markdown(renderer=renderer, inline=AwesomeInlineLexer,
|
||||
parse_block_html=1, parse_inline_html=1)
|
||||
renderer = AwesomeRenderer(
|
||||
escape=escape,
|
||||
nofollow=nofollow,
|
||||
texoid=texoid,
|
||||
math=math and math_engine is not None,
|
||||
math_engine=math_engine,
|
||||
)
|
||||
markdown = mistune.Markdown(
|
||||
renderer=renderer,
|
||||
inline=AwesomeInlineLexer,
|
||||
parse_block_html=1,
|
||||
parse_inline_html=1,
|
||||
)
|
||||
result = markdown(value)
|
||||
if post_processors:
|
||||
try:
|
||||
tree = html.fromstring(result, parser=html.HTMLParser(recover=True))
|
||||
except (XMLSyntaxError, ParserError) as e:
|
||||
if result and (not isinstance(e, ParserError) or e.args[0] != 'Document is empty'):
|
||||
logger.exception('Failed to parse HTML string')
|
||||
tree = html.Element('div')
|
||||
if result and (
|
||||
not isinstance(e, ParserError) or e.args[0] != "Document is empty"
|
||||
):
|
||||
logger.exception("Failed to parse HTML string")
|
||||
tree = html.Element("div")
|
||||
for processor in post_processors:
|
||||
processor(tree)
|
||||
result = html.tostring(tree, encoding='unicode')
|
||||
result = html.tostring(tree, encoding="unicode")
|
||||
return Markup(result)
|
||||
|
|
|
@ -5,16 +5,16 @@ from lxml import html
|
|||
|
||||
|
||||
def lazy_load(tree):
|
||||
blank = static('blank.gif')
|
||||
for img in tree.xpath('.//img'):
|
||||
src = img.get('src', '')
|
||||
if src.startswith('data') or '-math' in img.get('class', ''):
|
||||
blank = static("blank.gif")
|
||||
for img in tree.xpath(".//img"):
|
||||
src = img.get("src", "")
|
||||
if src.startswith("data") or "-math" in img.get("class", ""):
|
||||
continue
|
||||
noscript = html.Element('noscript')
|
||||
noscript = html.Element("noscript")
|
||||
copy = deepcopy(img)
|
||||
copy.tail = ''
|
||||
copy.tail = ""
|
||||
noscript.append(copy)
|
||||
img.addprevious(noscript)
|
||||
img.set('data-src', src)
|
||||
img.set('src', blank)
|
||||
img.set('class', img.get('class') + ' unveil' if img.get('class') else 'unveil')
|
||||
img.set("data-src", src)
|
||||
img.set("src", blank)
|
||||
img.set("class", img.get("class") + " unveil" if img.get("class") else "unveil")
|
||||
|
|
|
@ -6,13 +6,13 @@ from django.conf import settings
|
|||
|
||||
from judge.utils.mathoid import MathoidMathParser
|
||||
|
||||
mistune._pre_tags.append('latex')
|
||||
mistune._pre_tags.append("latex")
|
||||
|
||||
|
||||
class MathInlineGrammar(mistune.InlineGrammar):
|
||||
block_math = re.compile(r'^\$\$(.*?)\$\$|^\\\[(.*?)\\\]', re.DOTALL)
|
||||
math = re.compile(r'^~(.*?)~|^\\\((.*?)\\\)', re.DOTALL)
|
||||
text = re.compile(r'^[\s\S]+?(?=[\\<!\[_*`~$]|\\[\[(]|https?://| {2,}\n|$)')
|
||||
block_math = re.compile(r"^\$\$(.*?)\$\$|^\\\[(.*?)\\\]", re.DOTALL)
|
||||
math = re.compile(r"^~(.*?)~|^\\\((.*?)\\\)", re.DOTALL)
|
||||
text = re.compile(r"^[\s\S]+?(?=[\\<!\[_*`~$]|\\[\[(]|https?://| {2,}\n|$)")
|
||||
|
||||
|
||||
class MathInlineLexer(mistune.InlineLexer):
|
||||
|
@ -21,8 +21,10 @@ class MathInlineLexer(mistune.InlineLexer):
|
|||
def __init__(self, *args, **kwargs):
|
||||
self.default_rules = self.default_rules[:]
|
||||
self.inline_html_rules = self.default_rules
|
||||
self.default_rules.insert(self.default_rules.index('strikethrough') + 1, 'math')
|
||||
self.default_rules.insert(self.default_rules.index('strikethrough') + 1, 'block_math')
|
||||
self.default_rules.insert(self.default_rules.index("strikethrough") + 1, "math")
|
||||
self.default_rules.insert(
|
||||
self.default_rules.index("strikethrough") + 1, "block_math"
|
||||
)
|
||||
super(MathInlineLexer, self).__init__(*args, **kwargs)
|
||||
|
||||
def output_block_math(self, m):
|
||||
|
@ -35,14 +37,14 @@ class MathInlineLexer(mistune.InlineLexer):
|
|||
tag = m.group(1)
|
||||
text = m.group(3)
|
||||
if self._parse_inline_html and text:
|
||||
if tag == 'a':
|
||||
if tag == "a":
|
||||
self._in_link = True
|
||||
text = self.output(text)
|
||||
self._in_link = False
|
||||
else:
|
||||
text = self.output(text)
|
||||
extra = m.group(2) or ''
|
||||
html = '<%s%s>%s</%s>' % (tag, extra, text, tag)
|
||||
extra = m.group(2) or ""
|
||||
html = "<%s%s>%s</%s>" % (tag, extra, text, tag)
|
||||
else:
|
||||
html = m.group(0)
|
||||
return self.renderer.inline_html(html)
|
||||
|
@ -50,18 +52,18 @@ class MathInlineLexer(mistune.InlineLexer):
|
|||
|
||||
class MathRenderer(mistune.Renderer):
|
||||
def __init__(self, *args, **kwargs):
|
||||
if kwargs.pop('math', False) and settings.MATHOID_URL != False:
|
||||
self.mathoid = MathoidMathParser(kwargs.pop('math_engine', None) or 'svg')
|
||||
if kwargs.pop("math", False) and settings.MATHOID_URL != False:
|
||||
self.mathoid = MathoidMathParser(kwargs.pop("math_engine", None) or "svg")
|
||||
else:
|
||||
self.mathoid = None
|
||||
super(MathRenderer, self).__init__(*args, **kwargs)
|
||||
|
||||
def block_math(self, math):
|
||||
if self.mathoid is None or not math:
|
||||
return r'\[%s\]' % mistune.escape(str(math))
|
||||
return r"\[%s\]" % mistune.escape(str(math))
|
||||
return self.mathoid.display_math(math)
|
||||
|
||||
def math(self, math):
|
||||
if self.mathoid is None or not math:
|
||||
return r'\(%s\)' % mistune.escape(str(math))
|
||||
return self.mathoid.inline_math(math)
|
||||
return r"\(%s\)" % mistune.escape(str(math))
|
||||
return self.mathoid.inline_math(math)
|
||||
|
|
|
@ -3,25 +3,28 @@ import mistune
|
|||
|
||||
|
||||
class SpoilerInlineGrammar(mistune.InlineGrammar):
|
||||
spoiler = re.compile(r'^\|\|(.+?)\s+([\s\S]+?)\s*\|\|')
|
||||
spoiler = re.compile(r"^\|\|(.+?)\s+([\s\S]+?)\s*\|\|")
|
||||
|
||||
|
||||
class SpoilerInlineLexer(mistune.InlineLexer):
|
||||
grammar_class = SpoilerInlineGrammar
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.default_rules.insert(0, 'spoiler')
|
||||
self.default_rules.insert(0, "spoiler")
|
||||
super(SpoilerInlineLexer, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
def output_spoiler(self, m):
|
||||
return self.renderer.spoiler(m.group(1), m.group(2))
|
||||
|
||||
|
||||
class SpoilerRenderer(mistune.Renderer):
|
||||
def spoiler(self, summary, text):
|
||||
return '''<details>
|
||||
return """<details>
|
||||
<summary style="color: brown">
|
||||
<span class="spoiler-summary">%s</span>
|
||||
</summary>
|
||||
<div class="spoiler-text">%s</div>
|
||||
</details>''' % (summary, text)
|
||||
</details>""" % (
|
||||
summary,
|
||||
text,
|
||||
)
|
||||
|
|
|
@ -14,22 +14,22 @@ def _get_rating_value(func, obj):
|
|||
return func(obj.rating)
|
||||
|
||||
|
||||
@registry.function('rating_class')
|
||||
@registry.function("rating_class")
|
||||
def get_rating_class(obj):
|
||||
return _get_rating_value(rating_class, obj) or 'rate-none'
|
||||
return _get_rating_value(rating_class, obj) or "rate-none"
|
||||
|
||||
|
||||
@registry.function(name='rating_name')
|
||||
@registry.function(name="rating_name")
|
||||
def get_name(obj):
|
||||
return _get_rating_value(rating_name, obj) or 'Unrated'
|
||||
return _get_rating_value(rating_name, obj) or "Unrated"
|
||||
|
||||
|
||||
@registry.function(name='rating_progress')
|
||||
@registry.function(name="rating_progress")
|
||||
def get_progress(obj):
|
||||
return _get_rating_value(rating_progress, obj) or 0.0
|
||||
|
||||
|
||||
@registry.function
|
||||
@registry.render_with('user/rating.html')
|
||||
@registry.render_with("user/rating.html")
|
||||
def rating_number(obj):
|
||||
return {'rating': obj}
|
||||
return {"rating": obj}
|
||||
|
|
|
@ -13,17 +13,17 @@ from judge.models import Contest, Problem, Profile
|
|||
from judge.ratings import rating_class, rating_progress
|
||||
from . import registry
|
||||
|
||||
rereference = re.compile(r'\[(r?user):(\w+)\]')
|
||||
rereference = re.compile(r"\[(r?user):(\w+)\]")
|
||||
|
||||
|
||||
def get_user(username, data):
|
||||
if not data:
|
||||
element = Element('span')
|
||||
element = Element("span")
|
||||
element.text = username
|
||||
return element
|
||||
|
||||
element = Element('span', {'class': Profile.get_user_css_class(*data)})
|
||||
link = Element('a', {'href': reverse('user_page', args=[username])})
|
||||
element = Element("span", {"class": Profile.get_user_css_class(*data)})
|
||||
link = Element("a", {"href": reverse("user_page", args=[username])})
|
||||
link.text = username
|
||||
element.append(link)
|
||||
return element
|
||||
|
@ -31,17 +31,21 @@ def get_user(username, data):
|
|||
|
||||
def get_user_rating(username, data):
|
||||
if not data:
|
||||
element = Element('span')
|
||||
element = Element("span")
|
||||
element.text = username
|
||||
return element
|
||||
|
||||
rating = data[1]
|
||||
element = Element('a', {'class': 'rate-group', 'href': reverse('user_page', args=[username])})
|
||||
element = Element(
|
||||
"a", {"class": "rate-group", "href": reverse("user_page", args=[username])}
|
||||
)
|
||||
if rating:
|
||||
rating_css = rating_class(rating)
|
||||
rate_box = Element('span', {'class': 'rate-box ' + rating_css})
|
||||
rate_box.append(Element('span', {'style': 'height: %3.fem' % rating_progress(rating)}))
|
||||
user = Element('span', {'class': 'rating ' + rating_css})
|
||||
rate_box = Element("span", {"class": "rate-box " + rating_css})
|
||||
rate_box.append(
|
||||
Element("span", {"style": "height: %3.fem" % rating_progress(rating)})
|
||||
)
|
||||
user = Element("span", {"class": "rating " + rating_css})
|
||||
user.text = username
|
||||
element.append(rate_box)
|
||||
element.append(user)
|
||||
|
@ -51,21 +55,24 @@ def get_user_rating(username, data):
|
|||
|
||||
|
||||
def get_user_info(usernames):
|
||||
return {name: (rank, rating) for name, rank, rating in
|
||||
Profile.objects.filter(user__username__in=usernames)
|
||||
.values_list('user__username', 'display_rank', 'rating')}
|
||||
return {
|
||||
name: (rank, rating)
|
||||
for name, rank, rating in Profile.objects.filter(
|
||||
user__username__in=usernames
|
||||
).values_list("user__username", "display_rank", "rating")
|
||||
}
|
||||
|
||||
|
||||
def get_user_from_text(text):
|
||||
user_list = set()
|
||||
for i in rereference.finditer(text):
|
||||
user_list.add(text[i.start() + 6: i.end() - 1])
|
||||
user_list.add(text[i.start() + 6 : i.end() - 1])
|
||||
return Profile.objects.filter(user__username__in=user_list)
|
||||
|
||||
|
||||
reference_map = {
|
||||
'user': (get_user, get_user_info),
|
||||
'ruser': (get_user_rating, get_user_info),
|
||||
"user": (get_user, get_user_info),
|
||||
"ruser": (get_user_rating, get_user_info),
|
||||
}
|
||||
|
||||
|
||||
|
@ -77,9 +84,9 @@ def process_reference(text):
|
|||
elements = []
|
||||
for piece in rereference.finditer(text):
|
||||
if prev is None:
|
||||
tail = text[last:piece.start()]
|
||||
tail = text[last : piece.start()]
|
||||
else:
|
||||
prev.append(text[last:piece.start()])
|
||||
prev.append(text[last : piece.start()])
|
||||
prev = list(piece.groups())
|
||||
elements.append(prev)
|
||||
last = piece.end()
|
||||
|
@ -143,52 +150,52 @@ def item_title(item):
|
|||
return item.name
|
||||
elif isinstance(item, Contest):
|
||||
return item.name
|
||||
return '<Unknown>'
|
||||
return "<Unknown>"
|
||||
|
||||
|
||||
@registry.function
|
||||
@registry.render_with('user/link.html')
|
||||
@registry.render_with("user/link.html")
|
||||
def link_user(user):
|
||||
if isinstance(user, Profile):
|
||||
user, profile = user.user, user
|
||||
elif isinstance(user, AbstractUser):
|
||||
profile = user.profile
|
||||
elif type(user).__name__ == 'ContestRankingProfile':
|
||||
elif type(user).__name__ == "ContestRankingProfile":
|
||||
user, profile = user.user, user
|
||||
else:
|
||||
raise ValueError('Expected profile or user, got %s' % (type(user),))
|
||||
return {'user': user, 'profile': profile}
|
||||
raise ValueError("Expected profile or user, got %s" % (type(user),))
|
||||
return {"user": user, "profile": profile}
|
||||
|
||||
|
||||
@registry.function
|
||||
@registry.render_with('user/link-list.html')
|
||||
@registry.render_with("user/link-list.html")
|
||||
def link_users(users):
|
||||
return {'users': users}
|
||||
return {"users": users}
|
||||
|
||||
|
||||
@registry.function
|
||||
@registry.render_with('runtime-version-fragment.html')
|
||||
@registry.render_with("runtime-version-fragment.html")
|
||||
def runtime_versions(versions):
|
||||
return {'runtime_versions': versions}
|
||||
return {"runtime_versions": versions}
|
||||
|
||||
|
||||
@registry.filter(name='absolutify')
|
||||
@registry.filter(name="absolutify")
|
||||
def absolute_links(text, url):
|
||||
tree = lxml_tree.fromstring(text)
|
||||
for anchor in tree.xpath('.//a'):
|
||||
href = anchor.get('href')
|
||||
for anchor in tree.xpath(".//a"):
|
||||
href = anchor.get("href")
|
||||
if href:
|
||||
anchor.set('href', urljoin(url, href))
|
||||
anchor.set("href", urljoin(url, href))
|
||||
return tree
|
||||
|
||||
|
||||
@registry.function(name='urljoin')
|
||||
@registry.function(name="urljoin")
|
||||
def join(first, second, *rest):
|
||||
if not rest:
|
||||
return urljoin(first, second)
|
||||
return urljoin(urljoin(first, second), *rest)
|
||||
|
||||
|
||||
@registry.filter(name='ansi2html')
|
||||
@registry.filter(name="ansi2html")
|
||||
def ansi2html(s):
|
||||
return mark_safe(Ansi2HTMLConverter(inline=True).convert(s, full=False))
|
||||
|
|
|
@ -5,7 +5,7 @@ tests = {}
|
|||
filters = {}
|
||||
extensions = []
|
||||
|
||||
__all__ = ['render_with', 'function', 'filter', 'test', 'extension']
|
||||
__all__ = ["render_with", "function", "filter", "test", "extension"]
|
||||
|
||||
|
||||
def _store_function(store, func, name=None):
|
||||
|
@ -16,6 +16,7 @@ def _store_function(store, func, name=None):
|
|||
|
||||
def _register_function(store, name, func):
|
||||
if name is None and func is None:
|
||||
|
||||
def decorator(func):
|
||||
_store_function(store, func)
|
||||
return func
|
||||
|
@ -26,6 +27,7 @@ def _register_function(store, name, func):
|
|||
_store_function(store, name)
|
||||
return name
|
||||
else:
|
||||
|
||||
def decorator(func):
|
||||
_store_function(store, func, name)
|
||||
return func
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
from django.template import (Context, Template as DjangoTemplate, TemplateSyntaxError as DjangoTemplateSyntaxError,
|
||||
VariableDoesNotExist)
|
||||
from django.template import (
|
||||
Context,
|
||||
Template as DjangoTemplate,
|
||||
TemplateSyntaxError as DjangoTemplateSyntaxError,
|
||||
VariableDoesNotExist,
|
||||
)
|
||||
|
||||
from . import registry
|
||||
|
||||
|
@ -24,4 +28,4 @@ def render_django(template, **context):
|
|||
try:
|
||||
return compile_template(template).render(Context(context))
|
||||
except (VariableDoesNotExist, DjangoTemplateSyntaxError):
|
||||
return 'Error rendering: %r' % template
|
||||
return "Error rendering: %r" % template
|
||||
|
|
|
@ -1,13 +1,29 @@
|
|||
from django.template.loader import get_template
|
||||
from django.utils.safestring import mark_safe
|
||||
from django_social_share.templatetags.social_share import post_to_facebook_url, post_to_gplus_url, post_to_twitter_url
|
||||
from django_social_share.templatetags.social_share import (
|
||||
post_to_facebook_url,
|
||||
post_to_gplus_url,
|
||||
post_to_twitter_url,
|
||||
)
|
||||
|
||||
from . import registry
|
||||
|
||||
SHARES = [
|
||||
('post_to_twitter', 'django_social_share/templatetags/post_to_twitter.html', post_to_twitter_url),
|
||||
('post_to_facebook', 'django_social_share/templatetags/post_to_facebook.html', post_to_facebook_url),
|
||||
('post_to_gplus', 'django_social_share/templatetags/post_to_gplus.html', post_to_gplus_url),
|
||||
(
|
||||
"post_to_twitter",
|
||||
"django_social_share/templatetags/post_to_twitter.html",
|
||||
post_to_twitter_url,
|
||||
),
|
||||
(
|
||||
"post_to_facebook",
|
||||
"django_social_share/templatetags/post_to_facebook.html",
|
||||
post_to_facebook_url,
|
||||
),
|
||||
(
|
||||
"post_to_gplus",
|
||||
"django_social_share/templatetags/post_to_gplus.html",
|
||||
post_to_gplus_url,
|
||||
),
|
||||
# For future versions:
|
||||
# ('post_to_linkedin', 'django_social_share/templatetags/post_to_linkedin.html', post_to_linkedin_url),
|
||||
# ('post_to_reddit', 'django_social_share/templatetags/post_to_reddit.html', post_to_reddit_url),
|
||||
|
@ -17,7 +33,7 @@ SHARES = [
|
|||
def make_func(name, template, url_func):
|
||||
def func(request, *args):
|
||||
link_text = args[-1]
|
||||
context = {'request': request, 'link_text': mark_safe(link_text)}
|
||||
context = {"request": request, "link_text": mark_safe(link_text)}
|
||||
context = url_func(context, *args[:-1])
|
||||
return mark_safe(get_template(template).render(context))
|
||||
|
||||
|
@ -31,4 +47,6 @@ for name, template, url_func in SHARES:
|
|||
|
||||
@registry.function
|
||||
def recaptcha_init(language=None):
|
||||
return get_template('snowpenguin/recaptcha/recaptcha_init.html').render({'explicit': False, 'language': language})
|
||||
return get_template("snowpenguin/recaptcha/recaptcha_init.html").render(
|
||||
{"explicit": False, "language": language}
|
||||
)
|
||||
|
|
|
@ -15,15 +15,17 @@ class SpacelessExtension(Extension):
|
|||
https://stackoverflow.com/a/23741298/1090657
|
||||
"""
|
||||
|
||||
tags = {'spaceless'}
|
||||
tags = {"spaceless"}
|
||||
|
||||
def parse(self, parser):
|
||||
lineno = next(parser.stream).lineno
|
||||
body = parser.parse_statements(['name:endspaceless'], drop_needle=True)
|
||||
body = parser.parse_statements(["name:endspaceless"], drop_needle=True)
|
||||
return nodes.CallBlock(
|
||||
self.call_method('_strip_spaces', [], [], None, None),
|
||||
[], [], body,
|
||||
self.call_method("_strip_spaces", [], [], None, None),
|
||||
[],
|
||||
[],
|
||||
body,
|
||||
).set_lineno(lineno)
|
||||
|
||||
def _strip_spaces(self, caller=None):
|
||||
return Markup(re.sub(r'>\s+<', '><', caller().unescape().strip()))
|
||||
return Markup(re.sub(r">\s+<", "><", caller().unescape().strip()))
|
||||
|
|
|
@ -2,7 +2,9 @@ from . import registry
|
|||
|
||||
|
||||
@registry.function
|
||||
def submission_layout(submission, profile_id, user, editable_problem_ids, completed_problem_ids):
|
||||
def submission_layout(
|
||||
submission, profile_id, user, editable_problem_ids, completed_problem_ids
|
||||
):
|
||||
problem_id = submission.problem_id
|
||||
can_view = False
|
||||
|
||||
|
@ -12,13 +14,15 @@ def submission_layout(submission, profile_id, user, editable_problem_ids, comple
|
|||
if profile_id == submission.user_id:
|
||||
can_view = True
|
||||
|
||||
if user.has_perm('judge.change_submission'):
|
||||
if user.has_perm("judge.change_submission"):
|
||||
can_view = True
|
||||
|
||||
if submission.problem_id in completed_problem_ids:
|
||||
can_view |= submission.problem.is_public or profile_id in submission.problem.tester_ids
|
||||
can_view |= (
|
||||
submission.problem.is_public or profile_id in submission.problem.tester_ids
|
||||
)
|
||||
|
||||
if not can_view and hasattr(submission, 'contest'):
|
||||
if not can_view and hasattr(submission, "contest"):
|
||||
contest = submission.contest.participation.contest
|
||||
if contest.is_editable_by(user):
|
||||
can_view = True
|
||||
|
|
|
@ -5,14 +5,14 @@ from . import registry
|
|||
|
||||
|
||||
@registry.filter
|
||||
def timedelta(value, display='long'):
|
||||
def timedelta(value, display="long"):
|
||||
if value is None:
|
||||
return value
|
||||
return nice_repr(value, display)
|
||||
|
||||
|
||||
@registry.filter
|
||||
def timestampdelta(value, display='long'):
|
||||
def timestampdelta(value, display="long"):
|
||||
value = datetime.timedelta(seconds=value)
|
||||
return timedelta(value, display)
|
||||
|
||||
|
@ -23,8 +23,8 @@ def seconds(timedelta):
|
|||
|
||||
|
||||
@registry.filter
|
||||
@registry.render_with('time-remaining-fragment.html')
|
||||
@registry.render_with("time-remaining-fragment.html")
|
||||
def as_countdown(time):
|
||||
time_now = datetime.datetime.now(datetime.timezone.utc)
|
||||
initial = abs(time - time_now)
|
||||
return {'countdown': time, 'initial': initial}
|
||||
return {"countdown": time, "initial": initial}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue