Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dataset completeness feature #418

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions ckanext/scheming/ckan_formpages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ dataset_type: formpages
about: The default CKAN dataset schema with form split across multiple pages
about_url: http://github.com/ckan/ckanext-scheming

draft_fields_required: false

dataset_fields:

Expand All @@ -24,6 +25,8 @@ dataset_fields:
label: Description
form_snippet: markdown.html
form_placeholder: eg. Some useful notes about the data
required: true
validators: scheming_required unicode_safe

- field_name: owner_org
label: Organization
Expand Down Expand Up @@ -54,6 +57,8 @@ dataset_fields:
label: Version
validators: ignore_missing unicode_safe package_version_validator
form_placeholder: '1.0'
required: true
validators: scheming_required unicode_safe package_version_validator

- start_form_page:
title: Contact Info
Expand All @@ -63,6 +68,8 @@ dataset_fields:
label: Author
form_placeholder: Joe Bloggs
display_property: dc:creator
required: true
validators: scheming_required unicode_safe

- field_name: author_email
label: Author Email
Expand Down Expand Up @@ -95,6 +102,8 @@ resource_fields:
- field_name: name
label: Name
form_placeholder: eg. January 2011 Gold Prices
required: true
validators: scheming_required unicode_safe

- field_name: description
label: Description
Expand Down
18 changes: 18 additions & 0 deletions ckanext/scheming/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,3 +445,21 @@ def scheming_flatten_subfield(subfield, data):
for k in record:
flat[prefix + k] = record[k]
return flat


@helper
def scheming_missing_required_fields(pages, data=None, package_id=None):
if package_id:
try:
data = LocalCKAN().action.package_show(id=package_id)
except (NotFound, NotAuthorized):
pass
if data is None:
data = {}
missing = []
for p in pages:
missing.append([
f['field_name'] for f in p['fields']
if f.get('required') and not data.get(f['field_name'])
])
return missing
6 changes: 6 additions & 0 deletions ckanext/scheming/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ def resource_form(self):
def package_types(self):
return list(self._schemas)

def resource_validation_dependencies(self, package_type):
# Compatibility with https://github.com/ckan/ckan/pull/8421
schema = self._schemas.get(package_type, {})
dfr = schema.get('draft_fields_required', True)
return [] if dfr else ['state']

def validate(self, context, data_dict, schema, action):
"""
Validate and convert for package_create, package_update and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
{%- set pages = h.scheming_get_dataset_form_pages(dataset_type) -%}
{%- if pages -%}
{%- set active_page = data.get('_form_page', 1) | int -%}
{%- set draft_missing_required = h.scheming_missing_required_fields(pages, data) -%}
<ol class="stages stage-1">
{%- for p in pages -%}
<li class="{{
Expand All @@ -20,6 +21,16 @@
page=loop.index)
}}">{{ h.scheming_language_text(p.title) }}</a>{%
else %}{{ h.scheming_language_text(p.title) }}{% endif %}
{%- set mreq = draft_missing_required[loop.index0] -%}
{% if mreq %}
<abbr title="{{
ungettext("Missing required field", "Missing required fields", mreq | length)
}}: {% for m in mreq %}{{
h.scheming_language_text(h.scheming_field_by_name(p.fields, m).label)
}}{% if not loop.last %}, {% endif %}{% endfor %}">
<i class="fa fa-exclamation-circle text-danger fs-3" aria-hidden="true"></i>
</abbr>
{% endif %}
</span>
</li>
{%- endfor -%}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

{% block stages %}
{%- set pages = h.scheming_get_dataset_form_pages(dataset_type) -%}
{%- set draft_missing_required = h.scheming_missing_required_fields(pages, package_id=pkg_name) -%}
{%- if pages and stage -%}
<ol class="stages stage-1">
{%- for p in pages -%}
Expand All @@ -14,6 +15,16 @@
id=pkg_name,
page=loop.index)
}}">{{ h.scheming_language_text(p.title) }}</a>
{%- set mreq = draft_missing_required[loop.index0] -%}
{% if mreq %}
<abbr title="{{
ungettext("Missing required field", "Missing required fields", mreq | length)
}}: {% for m in mreq %}{{
h.scheming_language_text(h.scheming_field_by_name(p.fields, m).label)
}}{% if not loop.last %}, {% endif %}{% endfor %}">
<i class="fa fa-exclamation-circle text-danger fs-3" aria-hidden="true"></i>
</abbr>
{% endif %}
</span>
</li>
{%- endfor -%}
Expand Down
29 changes: 21 additions & 8 deletions ckanext/scheming/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@
import ckanext.scheming.helpers as sh
from ckanext.scheming.errors import SchemingException

OneOf = get_validator('OneOf')
ignore_missing = get_validator('ignore_missing')
not_empty = get_validator('not_empty')

all_validators = {}


Expand Down Expand Up @@ -65,6 +61,7 @@ def scheming_choices(field, schema):
"""
Require that one of the field choices values is passed.
"""
OneOf = get_validator('OneOf')
if 'choices' in field:
return OneOf([c['value'] for c in field['choices']])

Expand All @@ -84,11 +81,27 @@ def validator(value):
@register_validator
def scheming_required(field, schema):
"""
not_empty if field['required'] else ignore_missing
return a validator based on field['required']
and schema['draft_fields_required'] setting
"""
if field.get('required'):
return not_empty
return ignore_missing
if not field.get('required'):
return get_validator('ignore_missing')
if not schema.get('draft_fields_required', True):
return get_validator('scheming_draft_fields_not_required')
return get_validator('not_empty')


@register_validator
def scheming_draft_fields_not_required(key, data, errors, context):
"""
call ignore_missing if state is draft, otherwise not_empty
"""
state = data.get(('state',), '')
if state.startswith('draft'):
v = get_validator('ignore_missing')
else:
v = get_validator('not_empty')
v(key, data, errors, context)


@scheming_validator
Expand Down
Loading