Skip to content

Commit

Permalink
[#652] Automatically make resources private or public when the permis…
Browse files Browse the repository at this point in the history
…sions change
  • Loading branch information
domoritz committed Apr 23, 2013
1 parent 54d7a95 commit 87de3ab
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 11 deletions.
32 changes: 21 additions & 11 deletions ckanext/datastore/db.py
Expand Up @@ -958,7 +958,7 @@ def create(context, data_dict):
u'SET LOCAL statement_timeout TO {0}'.format(timeout))
result = context['connection'].execute(
u'SELECT * FROM pg_tables WHERE tablename = %s',
data_dict['resource_id']
data_dict['resource_id']
).fetchone()
if not result:
create_table(context, data_dict)
Expand All @@ -967,6 +967,8 @@ def create(context, data_dict):
insert_data(context, data_dict)
create_indexes(context, data_dict)
create_alias(context, data_dict)
if data_dict.get('private'):
_change_privilege(context, data_dict, 'REVOKE')
trans.commit()
return _unrename_json_field(data_dict)
except IntegrityError, e:
Expand Down Expand Up @@ -1045,7 +1047,7 @@ def delete(context, data_dict):
trans = context['connection'].begin()
result = context['connection'].execute(
u'SELECT 1 FROM pg_tables WHERE tablename = %s',
data_dict['resource_id']
data_dict['resource_id']
).fetchone()
if not result:
raise ValidationError({
Expand Down Expand Up @@ -1138,10 +1140,6 @@ def _get_read_only_user(data_dict):


def _change_privilege(context, data_dict, what):
log.info('Changing permissions of resource {0} with {1}'.format(
data_dict['resource_id'], what))
engine = _get_engine(context, data_dict)
context['connection'] = engine.connect()
read_only_user = _get_read_only_user(data_dict)
assert(what in ['REVOKE', 'GRANT'])
if what == 'REVOKE':
Expand All @@ -1160,17 +1158,29 @@ def _change_privilege(context, data_dict, what):
'privileges': [u'cannot make "{0}" private'.format(
data_dict['resource_id'])],
'info': {
'orig': [str(e.orig)],
'orig': str(e.orig),
'pgcode': e.orig.pgcode
}
})
finally:
context['connection'].close()


def make_private(context, data_dict):
_change_privilege(context, data_dict, 'REVOKE')
log.info('Making resource {0} privtae'.format(
data_dict['resource_id']))
engine = _get_engine(context, data_dict)
context['connection'] = engine.connect()
try:
_change_privilege(context, data_dict, 'REVOKE')
finally:
context['connection'].close()


def make_public(context, data_dict):
_change_privilege(context, data_dict, 'GRANT')
log.info('Making resource {0} public'.format(
data_dict['resource_id']))
engine = _get_engine(context, data_dict)
context['connection'] = engine.connect()
try:
_change_privilege(context, data_dict, 'GRANT')
finally:
context['connection'].close()
6 changes: 6 additions & 0 deletions ckanext/datastore/logic/action.py
Expand Up @@ -71,8 +71,14 @@ def datastore_create(context, data_dict):
'alias': ['{0} is not a valid alias name'.format(alias)]
})

# create a private datastore resource, if necessary
resource = model.Resource.get(res_id)
if resource.resource_group.package.private:
data_dict['private'] = True

result = db.create(context, data_dict)
result.pop('id', None)
result.pop('private', None)
result.pop('connection_url')
return result

Expand Down
21 changes: 21 additions & 0 deletions ckanext/datastore/plugin.py
Expand Up @@ -20,6 +20,7 @@ class DatastorePlugin(p.SingletonPlugin):
p.implements(p.IConfigurable, inherit=True)
p.implements(p.IActions)
p.implements(p.IAuthFunctions)
p.implements(p.IDomainObjectModification, inherit=True)

legacy_mode = False

Expand Down Expand Up @@ -100,6 +101,26 @@ def new_resource_show(context, data_dict):
new_resource_show._datastore_wrapped = True
logic._actions['resource_show'] = new_resource_show

def notify(self, entity, operation):
if not isinstance(entity, model.Package) or self.legacy_mode:
return
# if a resource is new, it cannot have a datastore resource, yet
if operation == model.domain_object.DomainObjectOperation.changed:
context = {'model': model, 'ignore_auth': True, 'validate': False}
if entity.private:
func = p.toolkit.get_action('datastore_make_private')
else:
func = p.toolkit.get_action('datastore_make_public')
for resource in entity.resources:
try:
func(context, {
'connection_url': self.write_url,
'resource_id': resource.id})
except p.toolkit.ObjectNotFound:
pass
elif operation == model.domain_object.DomainObjectOperation.deleted:
pass # TODO: delete datastore resource

def _log_or_raise(self, message):
if self.config.get('debug'):
log.critical(message)
Expand Down

0 comments on commit 87de3ab

Please sign in to comment.