Skip to content

Commit

Permalink
[#2750] Add ckanext/example_idatasetform
Browse files Browse the repository at this point in the history
  • Loading branch information
Sean Hammond committed Mar 11, 2013
1 parent c8d788f commit 9a56e8e
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 0 deletions.
Empty file.
163 changes: 163 additions & 0 deletions ckanext/example_idatasetform/plugin.py
@@ -0,0 +1,163 @@
import logging

import ckan.plugins as plugins
import ckan.plugins.toolkit as tk
import ckan.lib.plugins as lib_plugins


class ExampleIDatasetFormPlugin(plugins.SingletonPlugin,
lib_plugins.DefaultDatasetForm):
'''An example IDatasetForm CKAN plugin.
Uses a tag vocabulary to add a custom metadata field to datasets.
'''
plugins.implements(plugins.IConfigurer, inherit=False)
plugins.implements(plugins.IDatasetForm, inherit=False)

# These record how many times methods that this plugin's methods are
# called, for testing purposes.
num_times_new_template_called = 0
num_times_read_template_called = 0
num_times_edit_template_called = 0
num_times_comments_template_called = 0
num_times_search_template_called = 0
num_times_history_template_called = 0
num_times_package_form_called = 0
num_times_check_data_dict_called = 0

def create_country_codes(self):
'''Create country_codes vocab and tags, if they don't exist already.
Note that you could also create the vocab and tags using CKAN's API,
and once they are created you can edit them (e.g. to add and remove
possible dataset country code values) using the API.
'''
user = tk.get_action('get_site_user')({'ignore_auth': True}, {})
context = {'user': user['name']}
try:
data = {'id': 'country_codes'}
tk.get_action('vocabulary_show')(context, data)
logging.info("Example genre vocabulary already exists, skipping.")
except tk.ObjectNotFound:
logging.info("Creating vocab 'country_codes'")
data = {'name': 'country_codes'}
vocab = tk.get_action('vocabulary_create')(context, data)
for tag in (u'uk', u'ie', u'de', u'fr', u'es'):
logging.info(
"Adding tag {0} to vocab 'country_codes'".format(tag))
data = {'name': tag, 'vocabulary_id': vocab['id']}
tk.get_action('tag_create')(context, data)

def update_config(self, config):
# Add this plugin's templates dir to CKAN's extra_template_paths, so
# that CKAN will use this plugin's custom templates.
tk.add_template_directory(config, 'templates')

def is_fallback(self):
# Return True to register this plugin as the default handler for
# package types not handled by any other IDatasetForm plugin.
return True

def package_types(self):
# This plugin doesn't handle any special package types, it just
# registers itself as the default (above).
return []

def form_to_db_schema(self):
schema = super(ExampleIDatasetFormPlugin, self).form_to_db_schema()

# Add our custom country_code metadata field to the schema.
schema.update({
'country_code': [tk.get_validator('ignore_missing'),
tk.get_converter('convert_to_tags')('country_codes')]
})

# Add our custom_test metadata field to the schema, this one will use
# convert_to_extras instead of convert_to_tags.
schema.update({
'custom_text': [tk.get_validator('ignore_missing'),
tk.get_converter('convert_to_extras')]
})

return schema

def db_to_form_schema(self):
schema = super(ExampleIDatasetFormPlugin, self).db_to_form_schema()

# Don't show vocab tags mixed in with normal 'free' tags
# (e.g. on dataset pages, or on the search page)
schema['tags']['__extras'].append(tk.get_converter('free_tags_only'))

# Add our custom country_code metadata field to the schema.
schema.update({
'country_code': [
tk.get_converter('convert_from_tags')('country_codes'),
tk.get_validator('ignore_missing')]
})

# Add our custom_text field to the dataset schema.
schema.update({
'custom_text': [tk.get_converter('convert_from_extras'),
tk.get_validator('ignore_missing')]
})

return schema

def setup_template_variables(self, context, data_dict=None):
super(ExampleIDatasetFormPlugin, self).setup_template_variables(
context, data_dict)

# Create the country_codes vocab and tags, if they don't already exist.
self.create_country_codes()

# Add the list of available country codes, from the country_codes
# vocab, to the template context.
try:
tk.c.country_codes = tk.get_action('tag_list')(
context, {'vocabulary_id': 'country_codes'})
except tk.ObjectNotFound:
tk.c.country_codes = None

# These methods just record how many times they're called, for testing
# purposes.
# TODO: It might be better to test that custom templates returned by
# these methods are actually used, not just that the methods get
# called.

def new_template(self):
ExampleIDatasetFormPlugin.num_times_new_template_called += 1
return lib_plugins.DefaultDatasetForm.new_template(self)

def read_template(self):
ExampleIDatasetFormPlugin.num_times_read_template_called += 1
return lib_plugins.DefaultDatasetForm.read_template(self)

def edit_template(self):
ExampleIDatasetFormPlugin.num_times_edit_template_called += 1
return lib_plugins.DefaultDatasetForm.edit_template(self)

def comments_template(self):
ExampleIDatasetFormPlugin.num_times_comments_template_called += 1
return lib_plugins.DefaultDatasetForm.comments_template(self)

def search_template(self):
ExampleIDatasetFormPlugin.num_times_search_template_called += 1
return lib_plugins.DefaultDatasetForm.search_template(self)

def history_template(self):
ExampleIDatasetFormPlugin.num_times_history_template_called += 1
return lib_plugins.DefaultDatasetForm.history_template(self)

def package_form(self):
ExampleIDatasetFormPlugin.num_times_package_form_called += 1
return lib_plugins.DefaultDatasetForm.package_form(self)

def check_data_dict(self, data_dict, schema=None):
ExampleIDatasetFormPlugin.num_times_check_data_dict_called += 1
# Disable DefaultDatasetForm's check_data_dict(), because it breaks
# with the new three-stage dataset creation when using
# convert_to_extras.
#return lib_plugins.DefaultDatasetForm.check_data_dict(self, data_dict,
# schema)
@@ -0,0 +1,6 @@
{% ckan_extends %}

<!-- Pass c.country_codes to package_metadata_form.html.
FIXME: If ckan passed c to package_metadata_form.html anyway, we wouldn't need
to override this block here. -->
{% block form %}{{ h.snippet('package/snippets/package_metadata_form.html', data=data, errors=errors, include_metadata=false, pkg_name=pkg_name, country_codes=c.country_codes) }}{% endblock %}
13 changes: 13 additions & 0 deletions ckanext/example_idatasetform/templates/package/read.html
@@ -0,0 +1,13 @@
{% ckan_extends %}

{% block package_description %}
{{ super() }}

<!-- Add our custom country_code field to the dataset read page. -->
{% if pkg.get('country_code') %}
<section id="dataset-country_code" class="resources module-content">
<p><strong>Country Code</strong>: {{ pkg.country_code[0] }}</p>
</section>
{% endif %}

{% endblock %}
@@ -0,0 +1,8 @@
{% ckan_extends %}

<!-- Pass c.country_codes to package_metadata_fields.html.
FIXME: If ckan passed c to package_metadata_fields.html anyway, we wouldn't
need to override this block here. -->
{% block metadata_fields %}
{% snippet 'package/snippets/package_metadata_fields.html', data=data, errors=errors, country_codes=c.country_codes %}
{% endblock %}
@@ -0,0 +1,42 @@
{% import 'macros/form.html' as form %}

{% set groups_available = h.groups_available() %}
{% if groups_available %}
<div class="control-group">
{% set groups = h.dict_list_reduce(data.groups, 'id') %}
<label for="field-groups" class="control-label">{{ _('Add to Groups') }}</label>
<div class="controls">
<select id="field-groups" name="groups__{{ groups | count }}__id" data-module="autocomplete">
<option value="">{{ _('Select a group...') }}</option>
{% for group in groups_available %}
<option value="{{ group.id }}" {% if group.id in groups %}selected="selected"{% endif %}>{{ group.name }}</option>
{% endfor %}
</select>
</div>
</div>
{% endif %}

{{ form.input('author', label=_('Author'), id='field-author', placeholder=_('Joe Bloggs'), value=data.author, error=errors.author, classes=['control-medium']) }}

{{ form.input('author_email', label=_('Author Email'), id='field-author-email', placeholder=_('joe@example.com'), value=data.author_email, error=errors.author_email, classes=['control-medium']) }}

{{ form.input('maintainer', label=_('Maintainer'), id='field-maintainer', placeholder=_('Joe Bloggs'), value=data.maintainer, error=errors.maintainer, classes=['control-medium']) }}

{{ form.input('maintainer_email', label=_('Maintainer Email'), id='field-maintainer-email', placeholder=_('joe@example.com'), value=data.maintainer_email, error=errors.maintainer_email, classes=['control-medium']) }}

<label class="control-label" for="field-country_code">{{ _("Country Code") }}</label>
<div class="controls">
<select id="field-country_code" name="country_code" data-module="autocomplete">
{% for country_code in country_codes %}
<option value="{{ country_code }}" {% if country_code in data.get('country_code', []) %}selected="selected"{% endif %}>{{ country_code }}</option>
{% endfor %}
</select>
</div>

{{ form.input('custom_text', label=_('Custom Text'), id='field-custom_text', placeholder=_('custom text'), value=data.custom_text, error=errors.custom_text, classes=['control-medium']) }}

{#
{% block custom_fields %}
{% snippet 'snippets/custom_form_fields.html', extras=data.extras, errors=errors, limit=3 %}
{% endblock %}
#}
@@ -0,0 +1,21 @@
{% import "macros/form.html" as form %}

{% set data = data or {} %}
{% set errors = errors or {} %}

<form class="dataset-form dataset-resource-form form-horizontal" method="post" data-module="basic-form">
{{ h.snippet('package/snippets/stages.html', stages=['complete', 'complete', 'active'], pkg_name=pkg_name) }}
{{ form.errors(error_summary) }}

<!-- Pass country_codes to package_metadata_fields.html.
FIXME: If CKAN would pass c to package_metadata_fields.html anyway, we
wouldn't need to override this template here. -->
{% snippet 'package/snippets/package_metadata_fields.html', data=data, errors=errors, groups_available=groups_available, country_codes=country_codes %}

<div class="form-actions">
{# TODO: Go back to previous resource form #}
<button class="btn" name="save" value="go-resources" type="submit">{{ _('Previous') }}</button>
<button class="btn btn-primary" name="save" value="finish" type="submit">{{ _('Finish') }}</button>
</div>

</form>
1 change: 1 addition & 0 deletions setup.py
Expand Up @@ -125,6 +125,7 @@
pdf_preview=ckanext.pdfpreview.plugin:PdfPreview
recline_preview=ckanext.reclinepreview.plugin:ReclinePreview
example_itemplatehelpers=ckanext.example_itemplatehelpers.plugin:ExampleITemplateHelpersPlugin
example_idatasetform=ckanext.example_idatasetform.plugin:ExampleIDatasetFormPlugin
[ckan.system_plugins]
domain_object_mods = ckan.model.modification:DomainObjectModificationExtension
Expand Down

0 comments on commit 9a56e8e

Please sign in to comment.