4ad49aa4592ac7985c07332a97b66afd49096c89
3 from math
import sin
, pi
6 from sqlalchemy
import Column
, ForeignKey
, or_
7 from sqlalchemy
.ext
.associationproxy
import association_proxy
8 from sqlalchemy
.orm
import relation
9 from sqlalchemy
.orm
.session
import Session
10 from sqlalchemy
.types
import Integer
, Unicode
12 from spline
.model
.meta
import TableBase
14 class AnonymousUser(object):
15 """Fake user object, for when the user isn't actually logged in.
17 Tests as false and tries to respond to method calls the expected way.
20 def __nonzero__(self
):
25 def can(self
, action
):
26 """Anonymous users aren't ever allowed to do anything."""
30 class User(TableBase
):
31 __tablename__
= 'users'
32 id = Column(Integer
, primary_key
=True)
33 name
= Column(Unicode(length
=20), nullable
=False)
34 unique_identifier
= Column(Unicode(length
=32), nullable
=False)
36 def __init__(self
, *args
, **kwargs
):
37 # Generate a unique hash if one isn't provided (which it shouldn't be)
38 if 'unique_identifier' not in kwargs
:
39 ident
= u
''.join(random
.choice(u
'0123456789abcdef')
41 kwargs
['unique_identifier'] = ident
43 super(User
, self
).__init__(*args
, **kwargs
)
46 _default_permissions
= None
47 def can(self
, action
):
48 """Returns True iff this user has permission to do `action`.
50 If `_root_user_id` is this user's id, all permissions are allowed. The
51 property is usually set by the spline-users after_setup hook.
54 if self
.id == self
._root_user_id
:
57 if action
in self
.permissions
:
60 # Permissions assigned to NULL apply to all roles
61 if self
._default_permissions
is None:
62 session
= Session
.object_session(self
)
63 self
._default_permissions
= [
65 for row
in session
.query(RolePermission
)
66 .filter_by(role_id
=None)
69 return (action
in self
._default_permissions
)
72 def unique_colors(self
):
73 """Returns a list of (width, '#rrggbb') tuples that semi-uniquely
76 width_blob
, colors_blob
= self
.unique_identifier
[0:8], \
77 self
.unique_identifier
[8:32]
81 width_hex
= width_blob
[i
*2:i
*2+2]
82 widths
.append(int(width_hex
, 16))
83 total_width
= sum(widths
)
88 raw_hue
= int(colors_blob
[i
*6:i
*6+2], 16) / 256.0
90 # Make adjacent hues relatively close together, to avoid green
91 # + purple sorts of clashes.
92 # Minimum distance is 0.1; maximum is 0.35. Leaves half the
93 # spectrum available for any given color.
94 # Change 0.0–0.1 to -0.35–-0.1, 0.1–0.35
95 hue_offset
= raw_hue
* 0.5 - 0.25
101 h
= last_hue
+ raw_hue
106 l
= int(colors_blob
[i
*6+2:i
*6+4], 16) / 256.0
107 s
= int(colors_blob
[i
*6+4:i
*6+6], 16) / 256.0
109 # Secondary colors are extremely biased against when picking
110 # randomly from the hue spectrum.
111 # To alleviate this, try to bias hue towards secondary colors.
112 # This adjustment is based purely on experimentation; sin() works
113 # well because hue is periodic, * 6 means each period is 1/3 the
114 # hue spectrum, and the final / 24 is eyeballed
115 h
+= sin(h
* pi
* 6) / 24
117 # Cap lightness to 0.4 to 0.95, so it's not too close to white or
121 # Cap saturation to 0.5 to 1.0, so the color isn't too gray
124 r
, g
, b
= colorsys
.hls_to_rgb(h
, l
, s
)
125 color
= "#{0:02x}{1:02x}{2:02x}".format(
131 ret
.append((1.0 * widths
[i
] / total_width
, color
))
135 class OpenID(TableBase
):
136 __tablename__
= 'openid'
137 openid
= Column(Unicode(length
=255), primary_key
=True)
138 user_id
= Column(Integer
, ForeignKey('users.id'), nullable
=False)
142 class Role(TableBase
):
143 __tablename__
= 'roles'
144 id = Column(Integer
, primary_key
=True, nullable
=False)
145 name
= Column(Unicode(64), nullable
=False)
146 icon
= Column(Unicode(64), nullable
=False)
148 class UserRole(TableBase
):
149 __tablename__
= 'user_roles'
150 user_id
= Column(Integer
, ForeignKey('users.id'), primary_key
=True, nullable
=False, autoincrement
=False)
151 role_id
= Column(Integer
, ForeignKey('roles.id'), primary_key
=True, nullable
=False, autoincrement
=False)
153 class RolePermission(TableBase
):
154 __tablename__
= 'role_permissions'
155 id = Column(Integer
, nullable
=False, primary_key
=True)
156 role_id
= Column(Integer
, ForeignKey('roles.id'), nullable
=True)
157 permission
= Column(Unicode(64), nullable
=False)
161 OpenID
.user
= relation(User
, lazy
=False, backref
='openids')
163 Role
.role_permissions
= relation(RolePermission
, backref
='role')
165 User
.roles
= relation(Role
, secondary
=UserRole
.__table__
, backref
='users')
166 User
.role_permissions
= relation(RolePermission
,
167 primaryjoin
=User
.id==UserRole
.user_id
,
168 secondary
=UserRole
.__table__
,
169 secondaryjoin
=UserRole
.role_id
==RolePermission
.role_id
,
170 foreign_keys
=[UserRole
.user_id
, RolePermission
.role_id
],
172 User
.permissions
= association_proxy('role_permissions', 'permission')
174 UserRole
.user
= relation(User
)
175 UserRole
.role
= relation(Role
)