--- /dev/null
+from sqlalchemy import *
+from migrate import *
+import migrate.changeset # monkeypatches Column
+
+from sqlalchemy import orm
+from sqlalchemy.ext.declarative import declarative_base
+TableBase = declarative_base()
+
+
+class User(TableBase):
+ __tablename__ = 'users'
+ id = Column(Integer, primary_key=True)
+
+
+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)
+
+
+def upgrade(migrate_engine):
+ TableBase.metadata.bind = migrate_engine
+ Role.__table__.create()
+ UserRole.__table__.create()
+ RolePermission.__table__.create()
+
+def downgrade(migrate_engine):
+ TableBase.metadata.bind = migrate_engine
+ RolePermission.__table__.drop()
+ UserRole.__table__.drop()
+ Role.__table__.drop()
from pkg_resources import resource_filename
-from pylons import c, session
+from pylons import c, config, session
-from spline.lib.plugin import PluginBase
from spline.lib.plugin import PluginBase, PluginLink, Priority
import spline.model.meta as meta
import splinext.users.controllers.accounts
+import splinext.users.controllers.admin
import splinext.users.controllers.users
from splinext.users import model as users_model
map.connect('/users/{id}', controller='users', action='profile',
conditions=dict(function=id_is_numeric))
+ # Big-boy admin
+ map.connect('/admin/users/permissions', controller='admin_users', action='permissions')
+
+def monkeypatch_user_hook(*args, **kwargs):
+ """Hook to tell the `User` model who the root user is."""
+ try:
+ users_model.User._root_user_id \
+ = int(config['spline-users.root_user_id'])
+ except KeyError:
+ # No config set; oh well!
+ pass
+
def check_userid_hook(action, **params):
"""Hook to see if a user is logged in and, if so, stick a user object in
c.
def controllers(self):
return dict(
accounts = splinext.users.controllers.accounts.AccountsController,
+ admin_users = splinext.users.controllers.admin.AdminController,
users = splinext.users.controllers.users.UsersController,
)
def hooks(self):
return [
('routes_mapping', Priority.NORMAL, add_routes_hook),
+ ('after_setup', Priority.NORMAL, monkeypatch_user_hook),
('before_controller', Priority.VERY_FIRST, check_userid_hook),
]
--- /dev/null
+import logging
+
+from pylons import config, request, response, session, tmpl_context as c, url
+from pylons.controllers.util import abort, redirect_to
+
+from spline.model import meta
+from spline.lib.base import BaseController, render
+from splinext.users import model as users_model
+
+log = logging.getLogger(__name__)
+
+
+class AdminController(BaseController):
+
+ def permissions(self):
+ if not c.user.can('administrate'):
+ abort(403)
+
+ c.roles = meta.Session.query(users_model.Role) \
+ .order_by(users_model.Role.id.asc()).all()
+ return render('/users/admin/permissions.mako')
--- /dev/null
+## encoding: utf8
+#-- Users plugin
+# id of the root user, who can automatically do anything
+#spline-users.root_user_id = 0
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.orm.session import Session
from sqlalchemy.types import Integer, Unicode
from spline.model.meta import TableBase
return False
def can(self, action):
- # XXX if viewing is ever a permission, this should probably change.
+ """Anonymous users aren't ever allowed to do anything."""
return False
super(User, self).__init__(*args, **kwargs)
+ _root_user_id = None
+ _default_permissions = None
def can(self, action):
- # XXX this is probably not desired.
- return True
+ """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):
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)
--- /dev/null
+<%inherit file="/base.mako" />
+
+<%def name="title()">Permissions - User admin</%def>
+
+<%def name="title_in_page()">
+<ul id="breadcrumbs">
+ <li><a href="${url(controller='users', action='list')}">Users</a></li>
+ <li>Permissions admin</li>
+</ul>
+</%def>
+
+<h1>Roles</h1>
+
+<ul class="classic-list">
+ % for role in c.roles:
+ <li>
+ <img src="${h.static_uri('spline', "icons/{0}.png".format(role.icon))}" alt="">
+ ${role.name}
+
+ <ul class="classic-list">
+ % for role_permission in role.role_permissions:
+ <li>${role_permission.permission}</li>
+ % endfor
+ </ul>
+ </li>
+ % endfor
+</ul>