# encoding: utf8
import colorsys
+import json
from math import sin, pi
import random
-from sqlalchemy import Column, ForeignKey
+from sqlalchemy import Column, ForeignKey, or_
+from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm import relation
-from sqlalchemy.types import Integer, Unicode
+from sqlalchemy.orm.session import Session
+from sqlalchemy.types import Integer, PickleType, Unicode
from spline.model.meta import TableBase
+class AnonymousUser(object):
+ """Fake user object, for when the user isn't actually logged in.
+
+ Tests as false and tries to respond to method calls the expected way.
+ """
+ stash = {}
+
+ def __nonzero__(self):
+ return False
+ def __bool__(self):
+ return False
+
+ def can(self, action):
+ """Anonymous users aren't ever allowed to do anything."""
+ return False
+
+
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)
+ stash = Column(PickleType(pickler=json), nullable=False, default=dict())
def __init__(self, *args, **kwargs):
# Generate a unique hash if one isn't provided (which it shouldn't be)
super(User, self).__init__(*args, **kwargs)
+ _root_user_id = None
+ _default_permissions = None
+ def can(self, action):
+ """Returns True iff this user has permission to do `action`.
+
+ If `_root_user_id` is this user's id, all permissions are allowed. The
+ property is usually set by the spline-users after_setup hook.
+ """
+
+ if self.id == self._root_user_id:
+ return True
+
+ if action in self.permissions:
+ return True
+
+ # Permissions assigned to NULL apply to all roles
+ if self._default_permissions is None:
+ session = Session.object_session(self)
+ self._default_permissions = [
+ row.permission
+ for row in session.query(RolePermission)
+ .filter_by(role_id=None)
+ ]
+
+ return (action in self._default_permissions)
+
@property
def unique_colors(self):
"""Returns a list of (width, '#rrggbb') tuples that semi-uniquely
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')
+ user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
+
+
+# Permissions stuff
+class Role(TableBase):
+ __tablename__ = 'roles'
+ id = Column(Integer, primary_key=True, nullable=False)
+ name = Column(Unicode(64), nullable=False)
+ icon = Column(Unicode(64), nullable=False)
+
+class UserRole(TableBase):
+ __tablename__ = 'user_roles'
+ user_id = Column(Integer, ForeignKey('users.id'), primary_key=True, nullable=False, autoincrement=False)
+ role_id = Column(Integer, ForeignKey('roles.id'), primary_key=True, nullable=False, autoincrement=False)
+
+class RolePermission(TableBase):
+ __tablename__ = 'role_permissions'
+ id = Column(Integer, nullable=False, primary_key=True)
+ role_id = Column(Integer, ForeignKey('roles.id'), nullable=True)
+ permission = Column(Unicode(64), nullable=False)
+
+
+### Relations
+OpenID.user = relation(User, lazy=False, backref='openids')
+
+Role.role_permissions = relation(RolePermission, backref='role')
+
+User.roles = relation(Role, secondary=UserRole.__table__, backref='users')
+User.role_permissions = relation(RolePermission,
+ primaryjoin=User.id==UserRole.user_id,
+ secondary=UserRole.__table__,
+ secondaryjoin=UserRole.role_id==RolePermission.role_id,
+ foreign_keys=[UserRole.user_id, RolePermission.role_id],
+)
+User.permissions = association_proxy('role_permissions', 'permission')
+
+UserRole.user = relation(User)
+UserRole.role = relation(Role)