X-Git-Url: http://git.veekun.com/zzz-spline-users.git/blobdiff_plain/efc8b2bfc9e8a98fe563608a9467d541fb99c614..29c938f83a6f65a3f11cc64f39c827b6ab839cf3:/spline/plugins/users/model/__init__.py diff --git a/spline/plugins/users/model/__init__.py b/spline/plugins/users/model/__init__.py index f7a30d1..2fd444b 100644 --- a/spline/plugins/users/model/__init__.py +++ b/spline/plugins/users/model/__init__.py @@ -1,3 +1,8 @@ +# encoding: utf8 +import colorsys +from math import sin, pi +import random + from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import relation from sqlalchemy.types import Integer, Unicode @@ -8,10 +13,84 @@ class User(TableBase): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(Unicode(length=20), nullable=False) + unique_identifier = Column(Unicode(length=32), nullable=False) + + def __init__(self, *args, **kwargs): + # Generate a unique hash if one isn't provided (which it shouldn't be) + if 'unique_identifier' not in kwargs: + ident = u''.join(random.choice(u'0123456789abcdef') + for _ in range(32)) + kwargs['unique_identifier'] = ident + + super(User, self).__init__(*args, **kwargs) + + @property + def unique_colors(self): + """Returns a list of (width, '#rrggbb') tuples that semi-uniquely + identify this user. + """ + width_blob, colors_blob = self.unique_identifier[0:8], \ + self.unique_identifier[8:32] + + widths = [] + for i in range(4): + width_hex = width_blob[i*2:i*2+2] + widths.append(int(width_hex, 16)) + total_width = sum(widths) + + ret = [] + last_hue = None + for i in range(4): + raw_hue = int(colors_blob[i*6:i*6+2], 16) / 256.0 + if last_hue: + # Make adjacent hues relatively close together, to avoid green + # + purple sorts of clashes. + # Minimum distance is 0.1; maximum is 0.35. Leaves half the + # spectrum available for any given color. + # Change 0.0–0.1 to -0.35–-0.1, 0.1–0.35 + hue_offset = raw_hue * 0.5 - 0.25 + if raw_hue < 0: + raw_hue -= 0.1 + else: + raw_hue += 0.1 + + h = last_hue + raw_hue + else: + h = raw_hue + last_hue = h + + l = int(colors_blob[i*6+2:i*6+4], 16) / 256.0 + s = int(colors_blob[i*6+4:i*6+6], 16) / 256.0 + + # Secondary colors are extremely biased against when picking + # randomly from the hue spectrum. + # To alleviate this, try to bias hue towards secondary colors. + # This adjustment is based purely on experimentation; sin() works + # well because hue is periodic, * 6 means each period is 1/3 the + # hue spectrum, and the final / 24 is eyeballed + h += sin(h * pi * 6) / 24 + + # Cap lightness to 0.4 to 0.95, so it's not too close to white or + # black + l = l * 0.6 + 0.3 + + # Cap saturation to 0.5 to 1.0, so the color isn't too gray + s = s * 0.6 + 0.3 + + r, g, b = colorsys.hls_to_rgb(h, l, s) + color = "#{0:02x}{1:02x}{2:02x}".format( + int(r * 256), + int(g * 256), + int(b * 256), + ) + + ret.append((1.0 * widths[i] / total_width, color)) + + return ret + class OpenID(TableBase): __tablename__ = 'openid' openid = Column(Unicode(length=255), primary_key=True) user_id = Column(Integer, ForeignKey('users.id')) user = relation(User, lazy=False, backref='openids') -