Skip to content

Commit

Permalink
Add validators
Browse files Browse the repository at this point in the history
  • Loading branch information
blagojabozinovski committed Feb 24, 2024
1 parent da83fb0 commit 35784b9
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 0 deletions.
Empty file added ckanext/iaea/logic/__init__.py
Empty file.
45 changes: 45 additions & 0 deletions ckanext/iaea/logic/action.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import logging
import ckan.lib.datapreview as datapreview
import ckan.logic as l
import ckan.plugins as p
from ckan.logic.schema import default_create_resource_view_schema, default_update_resource_view_schema

from ckanext.iaea.helpers import get_main_organization

log = logging.getLogger(__name__)

ignore_missing = p.toolkit.get_validator('ignore_missing')


@p.toolkit.chained_action
def resource_view_create(up_func, context, data_dict):
view_plugin = datapreview.get_view_plugin(data_dict['view_type'])
if not view_plugin:
raise l.ValidationError(
{"view_type": "No plugin found for view_type {view_type}".format(
view_type=data_dict['view_type']
)}
)
schema = default_create_resource_view_schema(view_plugin)
schema.update({
'suggested_filter_fields': [ignore_missing]
})
context['schema'] = schema
result = up_func(context, data_dict)
return result


@p.toolkit.chained_action
def resource_view_update(up_func, context, data_dict):
model = context['model']
resource_view = model.ResourceView.get(data_dict['id'])
if not resource_view:
raise l.NotFound
view_plugin = datapreview.get_view_plugin(resource_view.view_type)
schema = default_update_resource_view_schema(view_plugin)
schema.update({
'suggested_filter_fields': [ignore_missing]
})
context['schema'] = schema
result = up_func(context, data_dict)
return result
61 changes: 61 additions & 0 deletions ckanext/iaea/logic/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from sqlalchemy.sql import exists
from sqlalchemy import or_

import ckan.model as model
import ckan.plugins as p
from ckan.common import config, g, _


@p.toolkit.chained_auth_function
def package_create(next_auth, context, data_dict):
return _check_dataset_write_actions_restricted(next_auth, context, data_dict)


def _check_dataset_write_actions_restricted(next_auth, context, data_dict):
res = next_auth(context, data_dict)
if not res.get('success'):
return res

allowed_orgs = config.get('ckanext.iaea.allow_dataset_create_from_organization') or ''
allowed_orgs = [o.strip() for o in allowed_orgs.strip().split(',') if o.strip()]

if not allowed_orgs:
return res

user = context.get('auth_user_obj')
if user:
org_ids = get_organization_ids(allowed_orgs)
if not org_ids:
return res

if not user_has_sufficient_roles_in_org(user.id, org_ids, ['editor', 'admin']):
return {
'success': False,
'message': _('User {} cannot create datasets.').format(user.name),
}

return res

def get_allowed_organizations_ids():
allowed_orgs = config.get('ckanext.iaea.allow_dataset_create_from_organization') or ''
allowed_orgs = [o.strip() for o in allowed_orgs.strip().split(',') if o.strip()]

if not allowed_orgs:
return []
return get_organization_ids(allowed_orgs)

def user_has_sufficient_roles_in_org(user_id, org_ids, roles):
q = (model.Session.query(model.Member.group_id)
.filter(model.Member.state=='active')
.filter(model.Member.table_name=='user')
.filter(model.Member.group_id.in_(org_ids))
.filter(model.Member.table_id == user_id)
.filter(model.Member.capacity.in_(roles))).exists()
return model.Session.query(q).scalar()

def get_organization_ids(org_names_ids):
q = (model.Session.query(model.Group.id)
.filter(or_(model.Group.id.in_(org_names_ids), model.Group.name.in_(org_names_ids)))
.filter(model.Group.state == 'active')
.filter(model.Group.type == 'organization'))
return [org_id[0] for org_id in q]
55 changes: 55 additions & 0 deletions ckanext/iaea/logic/validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import ckan.plugins.toolkit as tk
import ckan.lib.helpers as h
import ckan.lib.navl.dictization_functions as df
from ckan.common import _

from ckanext.iaea.helpers import get_main_organization
from ckanext.iaea.logic.auth import get_allowed_organizations_ids


def package_organization_validator(value, context):
'''Validates the organization on create/update package.
The organization must be one of:
- Empty value i.e. no owner organization for the package.
- If set, then it must be set to the main organization of the portal.
- If the package already was owned by an organization, the value must either be that old
organization or the main portal organization (this is for compatibility with older packages).
'''
if not value:
return value

main_org = get_main_organization()
package = context.get('package')

if not package and not main_org:
raise df.Invalid(_('Only datasets without organization are allowed'))

if not package:
# Check that the current owner_org is the main owner_org
if value.lower() != main_org.get('name').lower() and value.lower() != main_org.get('id').lower():
# Check if we can allow from additional organizations for load testing, but only if specified
if value not in get_allowed_organizations_ids():
raise df.Invalid(_('The dataset owner organization must be {} or empty').format(main_org.get('name')))

if package and main_org:
new_org = _get_organization(value)
if not new_org:
raise df.Invalid(_('Package owner organization does not exist'))
if new_org.get('id') != package.owner_org:
# The owner organization was updated, so it must be set to the main organization or not at all.
if new_org.get('id') != main_org.get('id'):
# The new owner org is not the main org.
raise df.Invalid(_('You can only update the package owner organization to {} or leave the old one.').format(main_org.get('name')))

return value


def _get_organization(value):
try:
return tk.get_action('organization_show')({
'ignore_auth': True,
}, {
'id': value,
})
except tk.ObjectNotFound:
return None
7 changes: 7 additions & 0 deletions ckanext/iaea/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
import ckan.plugins.toolkit as toolkit
from ckan.lib.plugins import DefaultTranslation
from ckanext.iaea.helpers import get_helpers
from ckanext.iaea.logic import action, validators


class IaeaPlugin(plugins.SingletonPlugin, DefaultTranslation):
plugins.implements(plugins.IConfigurer)
plugins.implements(plugins.ITranslation)
plugins.implements(plugins.ITemplateHelpers, inherit=True)
plugins.implements(plugins.IValidators)

# IConfigurer

Expand All @@ -28,3 +30,8 @@ def get_helpers(self):
iaea_helpers.update(get_helpers())
return iaea_helpers

# IValidators
def get_validators(self):
return {
'iaea_owner_org_validator': validators.package_organization_validator,
}

0 comments on commit 35784b9

Please sign in to comment.