Skip to content

Commit

Permalink
[2878] Changes to model to allow permission to appear in more than on…
Browse files Browse the repository at this point in the history
…e place.

- Also added a test and the organization_role_create action.
  • Loading branch information
rossjones committed Aug 22, 2012
1 parent ee1de4a commit 462880a
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 16 deletions.
4 changes: 4 additions & 0 deletions ckan/lib/dictization/model_dictize.py
Expand Up @@ -112,6 +112,10 @@ def resource_dictize(res, context):
def related_dictize(rel, context):
return d.table_dictize(rel, context)

def organization_role_dictize(rel, context):
return d.table_dictize(rel, context)


def _execute_with_revision(q, rev_table, context):
'''
Takes an SqlAlchemy query (q) that is (at its base) a Select on an
Expand Down
6 changes: 6 additions & 0 deletions ckan/lib/dictization/model_save.py
Expand Up @@ -435,6 +435,12 @@ def user_dict_save(user_dict, context):
return user


def organization_role_dict_save(organization_role_dict, context):
model = context['model']
session = context['session']
return d.table_dict_save(organization_role_dict,model.OrganisationRole, context)


def related_dict_save(related_dict, context):
model = context['model']
session = context['session']
Expand Down
41 changes: 41 additions & 0 deletions ckan/logic/action/create.py
Expand Up @@ -251,6 +251,47 @@ def resource_create(context, data_dict):
return pkg_dict['resources'][-1]


def organization_role_create(context, data_dict):
'''Create a new organisation role that will be available system wide
:param name: the name of the role to create
:type name: string
:param permissions:
:type permissions: list of names
:returns: the newly created role
:rtype: dictionary
'''
model = context['model']
session = context['session']
user = context['user']
userobj = model.User.get(user)

# Temporarily here because the auth is being replaced, and so no point
# it being in there for now.
from ckan.authz import Authorizer
from ckan.logic import NotAuthorized
if not Authorizer().is_sysadmin(unicode(user)):
msg = _('No valid API key provided.')
log.debug(msg)
raise NotAuthorized(msg)

data, errors = _validate(
data_dict, ckan.logic.schema.default_organization_role_schema(),
context)
if errors:
model.Session.rollback()
raise ValidationError(errors)

related = model_save.organization_role_dict_save(data, context)
if not context.get('defer_commit'):
model.repo.commit_and_remove()

session.flush()

return model_dictize.organization_role_dictize(related, context)

def related_create(context, data_dict):
'''Add a new related item to a dataset.
Expand Down
21 changes: 21 additions & 0 deletions ckan/logic/schema.py
Expand Up @@ -10,6 +10,7 @@
from ckan.logic.validators import (package_id_not_changed,
package_id_exists,
package_id_or_name_exists,
permission_id_or_name_exists,
extras_unicode_convert,
name_validator,
package_name_validator,
Expand Down Expand Up @@ -278,6 +279,26 @@ def default_related_schema():
}
return schema

def default_organization_role_schema():
schema = {
'id': [ignore_missing, unicode],
'name': [not_empty, unicode],
'permissions': {
"id": [ignore_missing, unicode, permission_id_or_name_exists],
"name":[ignore_missing, unicode],
"description":[ignore_missing, unicode],
}
}
return schema

def default_permission_schema():
schema = {
"id": [not_empty, unicode, package_id_or_name_exists],
"name":[not_empty, unicode],
"description":[ignore_missing, unicode],
}
return schema


def default_extras_schema():

Expand Down
16 changes: 16 additions & 0 deletions ckan/logic/validators.py
Expand Up @@ -88,6 +88,22 @@ def package_id_or_name_exists(value, context):

return result.id

def permission_id_or_name_exists(value, context):

model = context['model']
session = context['session']

result = session.query(model.Permission).get(value)
if result:
return value

result = session.query(model.Permission).filter_by(name=value).first()
if not result:
raise Invalid('%s: %s' % (_('Not found'), _('permission')))

return result.id


def user_id_exists(user_id, context):
"""Raises Invalid if the given user_id does not exist in the model given
in the context, otherwise returns the given user_id.
Expand Down
15 changes: 11 additions & 4 deletions ckan/migration/versions/060_add_organisation_auth.py
Expand Up @@ -12,11 +12,15 @@ def upgrade(migrate_engine):
name text
);
CREATE TABLE organisationrole_permission (
organisationrole_id text NOT NULL,
permission_id text NOT NULL
);
CREATE TABLE permission (
id text NOT NULL,
name text,
description text,
organisationrole_id text NOT NULL
description text
);
ALTER TABLE organisationrole
Expand All @@ -25,8 +29,11 @@ def upgrade(migrate_engine):
ALTER TABLE permission
ADD CONSTRAINT permission_pkey PRIMARY KEY (id);
ALTER TABLE permission
ADD CONSTRAINT permission_organisationrole_id_fkey FOREIGN KEY (organisationrole_id) REFERENCES organisationrole(id);
ALTER TABLE organisationrole_permission
ADD CONSTRAINT organisationrole_permission_id_fkey FOREIGN KEY (organisationrole_id) REFERENCES organisationrole(id);
ALTER TABLE organisationrole_permission
ADD CONSTRAINT permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permission(id);
COMMIT;
'''
Expand Down
27 changes: 15 additions & 12 deletions ckan/model/organization_auth.py
Expand Up @@ -19,14 +19,17 @@
Column('name', types.UnicodeText),
)

role_permission_table = Table('organisationrole_permission', meta.metadata,
Column('organisationrole_id', types.UnicodeText, ForeignKey('organisationrole.id')),
Column('permission_id', types.UnicodeText, ForeignKey('permission.id'))
)

permission_table = Table(
'permission', meta.metadata,
Column('id', types.UnicodeText, primary_key=True,
default=_types.make_uuid),
Column('name', types.UnicodeText),
Column('description', types.UnicodeText),
Column('organisationrole_id', types.UnicodeText,
ForeignKey('organisationrole.id'), nullable=False),
Column('description', types.UnicodeText)
)


Expand All @@ -41,16 +44,16 @@ def get(cls, name):
class Permission(domain_object.DomainObject):

@classmethod
def get(cls, name):
return meta.Session.query(Permission).filter(
Permission.name == name).first()
def get(cls, reference):
query = meta.Session.query(cls).filter(cls.id==reference)
pkg = query.first()
if pkg == None:
pkg = cls.by_name(reference)
return pkg


meta.mapper(Permission, permission_table, properties={
'role': orm.relation(OrganisationRole)
})
meta.mapper(Permission, permission_table)

meta.mapper(OrganisationRole, organisationrole_table,
properties={'permissions':
orm.relation(Permission,
backref=orm.backref('permission'))})
properties={'permissions': orm.relationship(Permission,
secondary=role_permission_table)})
35 changes: 35 additions & 0 deletions ckan/tests/functional/api/test_organisation_auth.py
@@ -0,0 +1,35 @@
from nose.tools import assert_equal
from pylons import config
import pylons.test
import paste

from ckan.lib.create_test_data import CreateTestData
import ckan.lib.helpers as h
import ckan.model as model

_json = h.json

class TestUserController(object):

@classmethod
def setup_class(cls):
CreateTestData.create()
cls.app = paste.fixture.TestApp(pylons.test.pylonsapp)
cls.sysadmin_user = model.User.get('testsysadmin')
cls.extra_environ = {'Authorization' : str(cls.sysadmin_user.apikey)}

p = model.Permission(name="package.view")
model.Session.add(p)
model.Session.commit()

@classmethod
def teardown_class(self):
model.repo.rebuild_db()

def test_role_create(self):
params = _json.dumps({'name':'test_role', 'permissions': [{"name":"package.view"}]})

response = self.app.post('/api/action/organization_role_create',
params=params, extra_environ=self.extra_environ).json
assert response['success'] is True
print response

0 comments on commit 462880a

Please sign in to comment.