#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# @file: railgun/website/utility.py
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# This file is released under BSD 2-clause license.
import os
import colorsys
import hashlib
import cPickle as pickle
from flask.ext.babel import to_user_timezone, gettext as _
from flask.ext.login import current_user
from .context import app
def render_markdown(s):
from markdown import markdown
return markdown(
text=s,
output_format='xhtml1',
extensions=[
'extra',
'tables',
'smart_strong',
'codehilite',
'nl2br',
'toc',
'fenced_code',
]
)
[docs]def float_color(value):
"""Get a color to describe the safety level.
Safety level should be a floating number in range [0.0, 1.0].
The color will be more close to green if the safety level is more close
to 1.0, and more close to red if level is more close to 0.0.
:param value: The value of safety level.
:type value: :class:`float`
:return: An html color string, for example, "#ffffff".
"""
h = value / 3.0
l = 0.3
s = 1.0
rgb = map((lambda i: int(i * 255)), colorsys.hls_to_rgb(h, l, s))
return '#%02X%02X%02X' % tuple(rgb)
[docs]def round_score(score):
"""Get the closest number to given score, whose precision is 0.1.
:param score: The given score in floating number.
:type score: :class:`float`
:return: The rounded score.
"""
return round(score * 10) * 0.1
[docs]def get_avatar(user_or_email, size):
"""Get the gravatar url of given user.
:param user_or_email: If it is a :class:`basestring`, representing the
email address; otherwise it must carry an attribute `email`.
:type user_or_email: :class:`basestring` or :class:`object`
:param size: Size of avatar in pixels.
:type size: :class:`int`
:return: The url to the gavatar image.
"""
if isinstance(user_or_email, str) or isinstance(user_or_email, unicode):
email = user_or_email
else:
email = getattr(user_or_email, 'email', None)
if email:
hashcode = hashlib.md5(email.lower()).hexdigest()
else:
hashcode = '00000000000000000000000000000000'
# CDN of gravatar.com is blocked by GFW, so we use secure.gravatar.com
# instead.
ret = 'https://secure.gravatar.com/avatar/%(hashcode)s.jpg?s=%(size)d&d=mm'
return ret % {'hashcode': hashcode, 'size': size}
[docs]def is_email(login):
"""Check whether the given login name is an email address.
:param login: The login name.
:type login: :class:`str`
:return: :data:`True` if is email, :data:`False` otherwise.
"""
# TODO: Since the sign up and admin create user page all restrict the
# characters to A-Za-z0-9_, just test whether '@' exists is enough.
return '@' in login
[docs]def group_histogram(data, getter):
"""Get the group histogram from given objects.
The frequency of each group will be counted and the histogram will be
based on the groups.
:param data: Iterable objects to be analyzed.
:param getter: A :func:`callable` object to get the group name from
an object.
:return: A :class:`dict` {group: frequency}.
"""
ret = {}
for d in data:
g = getter(d)
if g in ret:
ret[g] += 1
else:
ret[g] = 1
return ret
[docs]def date_histogram(data, getter, ignore_year=False):
"""Get the date histogram from given objects.
:param data: Iterable objects to be analyzed.
:param getter: A :func:`callable` object to get a
:class:`~datetime.datetime` from an object.
:param ignore_year: Ignore the year in the date. Only month and day
will be used in histogram.
:return: A sorted :class:`list` of :class:`tuple`
((year, month, day), freq).
"""
ret = {}
if ignore_year:
get_key = lambda dt: (dt.month, dt.day)
else:
get_key = lambda dt: (dt.year, dt.month, dt.day)
for obj in data:
key = get_key(to_user_timezone(getter(obj)))
if key in ret:
ret[key] += 1
else:
ret[key] = 1
return sorted(ret.items())
[docs]def load_vote_signup(username=None):
"""Load voting signup data from directory."""
username = username or current_user.name
fpath = os.path.join(app.config['VOTE_SIGNUP_DATA_DIR'],
'%s.dat' % username)
if os.path.isfile(fpath):
try:
with open(fpath, 'rb') as f:
return pickle.load(f)
except Exception:
app.logger.exception('Cannot load signup data from "%s"' % fpath)
return {'project_id': -1, 'group_name': '', 'description': '',
'logo_file': ''}
[docs]def list_vote_signup():
"""List all signup data."""
if os.path.isdir(app.config['VOTE_SIGNUP_DATA_DIR']):
for f in os.listdir(app.config['VOTE_SIGNUP_DATA_DIR']):
if f.endswith('.dat'):
yield f[: -4]
[docs]def store_vote_signup(project_id, group_name, description, logo_file,
username=None):
"""Store voting signup data to directory."""
username = username or current_user.name
fpath = os.path.join(app.config['VOTE_SIGNUP_DATA_DIR'],
'%s.dat' % username)
try:
if not os.path.isdir(app.config['VOTE_SIGNUP_DATA_DIR']):
os.makedirs(app.config['VOTE_SIGNUP_DATA_DIR'])
with open(fpath, 'wb') as f:
pickle.dump({
'project_id': project_id,
'group_name': group_name,
'description': description,
'logo_file': logo_file,
}, f)
return True
except Exception:
app.logger.exception('Cannot write signup data to "%s"' % fpath)
return False