diff --git a/ckanext/odsh/fanstatic/odsh_form.js b/ckanext/odsh/fanstatic/odsh_form.js index c4bbb1641fb8c8006888ef9d564f11cb6d31d3c4..0562849c43075ed6efff88ae05605d625f6c8e5a 100644 --- a/ckanext/odsh/fanstatic/odsh_form.js +++ b/ckanext/odsh/fanstatic/odsh_form.js @@ -18,7 +18,6 @@ ckan.module('odsh_form', function ($) { var values = $('#field-groups option:selected') .map(function (a, item) { return item.value; }).get().join(',') - console.log(values) $('#field-groups-value').val(values); } }); diff --git a/ckanext/odsh/helpers.py b/ckanext/odsh/helpers.py index 5a92d0b02ba73d341dedf500b2c40b5fed34630b..d2d07cfb9252dc6e992bb7bdae9d85d98bf0f866 100644 --- a/ckanext/odsh/helpers.py +++ b/ckanext/odsh/helpers.py @@ -149,16 +149,21 @@ def odsh_create_checksum(in_string): return int(hashstring, base=16) -def odsh_extract_error(key, errors): - if not errors or not ('extras' in errors): +def odsh_extract_error(key, errors, field='extras'): + if not errors or not (field in errors): return None - ext = errors['extras'] + ext = errors[field] for item in ext: if 'key' in item: for error in item['key']: if error.startswith(key): return error.replace(key+':', '') +def odsh_extract_error_new(key, errors): + if not errors or not ('__extras' in errors): + return None + error = errors['__extras'][0].get(key,None) + return error def odsh_extract_value_from_extras(extras, key): if not extras: diff --git a/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.mo b/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.mo index 1c0637984f09888c0446060066344f8fa8344204..6c58f6b551b398f3a3e09aed54d9584bf7cb6417 100644 Binary files a/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.mo and b/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.mo differ diff --git a/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.po b/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.po index 191aacf1e34e0fb3f575b7ae82d620a0f100721c..950414e8c55a260ff08470e071caa4493becca38 100644 --- a/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.po +++ b/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.po @@ -343,4 +343,7 @@ msgid "3URI" msgstr "verwendet URIs" msgid "4LD" -msgstr "Linked Data" \ No newline at end of file +msgstr "Linked Data" + +msgid "at least one group needed" +msgstr "Bitte geben Sie mindestens eine Kategorie an" \ No newline at end of file diff --git a/ckanext/odsh/plugin.py b/ckanext/odsh/plugin.py index c944fcf37445c7076424a53d8c39f555226fc6a4..354c3622953b27eb8d65423300b3becb07a43914 100644 --- a/ckanext/odsh/plugin.py +++ b/ckanext/odsh/plugin.py @@ -4,26 +4,23 @@ import ckan.plugins as plugins import ckan.plugins.toolkit as toolkit from ckan.lib.plugins import DefaultTranslation from ckan.lib.plugins import DefaultDatasetForm -from ckan.lib.navl.dictization_functions import Missing from ckan.logic.validators import tag_string_convert +from ckan.logic.schema import default_extras_schema from ckan.common import OrderedDict -import ckan.model as model from ckanext.odsh.lib.uploader import ODSHResourceUpload import ckan.lib.helpers as helpers import helpers as odsh_helpers -from itertools import count from routes.mapper import SubMapper from pylons import config -import urllib2 -import csv -import re from dateutil.parser import parse import ckan.plugins as p import logging +import validation + log = logging.getLogger(__name__) _ = toolkit._ @@ -50,20 +47,6 @@ def odsh_main_groups(): return groups -def odsh_convert_groups_string(value, context): - if not value: - return [] - if type(value) is not list: - value = [value] - groups = helpers.groups_available() - ret = [] - for v in value: - for g in groups: - if g['id'] == v: - ret.append(g) - return ret - - def odsh_now(): return helpers.render_datetime(datetime.datetime.now(), "%Y-%m-%d") @@ -77,211 +60,6 @@ def odsh_group_id_selected(selected, group_id): return False - -def known_spatial_uri(key, data, errors, context): - value = _extract_value(data, 'spatial_uri') - - if not value: - raise toolkit.Invalid('spatial_uri:odsh_spatial_uri_error_label') - - mapping_file = config.get('ckanext.odsh.spatial.mapping') - try: - mapping_file = urllib2.urlopen(mapping_file) - except Exception: - raise Exception("Could not load spatial mapping file!") - - not_found = True - spatial_text = str() - spatial = str() - cr = csv.reader(mapping_file, delimiter="\t") - for row in cr: - if row[0].encode('UTF-8') == value: - not_found = False - spatial_text = row[1] - loaded = json.loads(row[2]) - spatial = json.dumps(loaded['geometry']) - break - if not_found: - raise toolkit.Invalid( - 'spatial_uri:odsh_spatial_uri_unknown_error_label') - - # Get the current extras index - current_indexes = [k[1] for k in data.keys() - if len(k) > 1 and k[0] == 'extras'] - - new_index = max(current_indexes) + 1 if current_indexes else 0 - - data[('extras', new_index, 'key')] = 'spatial_text' - data[('extras', new_index, 'value')] = spatial_text - data[('extras', new_index+1, 'key')] = 'spatial' - data[('extras', new_index+1, 'value')] = spatial - - -def _extract_value(data, field): - key = None - for k in data.keys(): - if data[k] == field: - key = k - break - if key is None: - return None - return data[(key[0], key[1], 'value')] - -def _set_value(data, field, value): - key = None - for k in data.keys(): - if data[k] == field: - key = k - break - if key is None: - return None - data[(key[0], key[1], 'value')] = value - -def odsh_validate_extra_date(key, field, data, errors, context): - value = _extract_value(data, field) - - if not value: - if field == 'temporal_end': - return # temporal_end is optional - # Statistikamt Nord does not always provide temporal_start/end, - # but their datasets have to be accepted as they are. - if not ('id',) in data or data[('id',)][:7] != 'StaNord': - raise toolkit.Invalid(field+':odsh_'+field+'_error_label') - else: - if re.match(r'\d\d\d\d-\d\d-\d\d', value): - try: - dt=parse(value) - _set_value(data, field, dt.isoformat()) - return - except ValueError: - pass - raise toolkit.Invalid(field+':odsh_'+field+'_not_date_error_label') - - -def odsh_validate_extra_date_factory(field): - return lambda key, data, errors, context: odsh_validate_extra_date(key, field, data, errors, context) - -def odsh_validate_licenseAttributionByText(key, data, errors, context): - register = model.Package.get_license_register() - isByLicense=False - for k in data: - if len(k) > 0 and k[0] == 'license_id' and data[k] and not isinstance(data[k], Missing) and \ - 'Namensnennung' in register[data[k]].title: - isByLicense = True - break - hasAttribution=False - for k in data: - if data[k] == 'licenseAttributionByText': - if isinstance(data[(k[0], k[1], 'value')], Missing): - del data[(k[0], k[1], 'value')] - del data[(k[0], k[1], 'key')] - break - else: - value = data[(k[0], k[1], 'value')] - hasAttribution = value != '' - break - if isByLicense and not hasAttribution: - raise toolkit.Invalid('licenseAttributionByText:odsh_licence_text_missing_error_label') - if not isByLicense and hasAttribution: - raise toolkit.Invalid('licenseAttributionByText:odsh_licence_text_not_allowed_error_label') - -def odsh_tag_name_validator(value, context): - tagname_match = re.compile('[\w \-.\:\(\)]*$', re.UNICODE) - if not tagname_match.match(value): - raise toolkit.Invalid(_('Tag "%s" must be alphanumeric ' - 'characters or symbols: -_.:()') % (value)) - return value - - -def odsh_tag_string_convert(key, data, errors, context): - '''Takes a list of tags that is a comma-separated string (in data[key]) - and parses tag names. These are added to the data dict, enumerated. They - are also validated.''' - if isinstance(data[key], basestring): - tags = [tag.strip() - for tag in data[key].split(',') - if tag.strip()] - else: - tags = data[key] - - - current_index = max([int(k[1]) for k in data.keys() - if len(k) == 3 and k[0] == 'tags'] + [-1]) - - - - for num, tag in zip(count(current_index+1), tags): - data[('tags', num, 'name')] = tag - - for tag in tags: - toolkit.get_validator('tag_length_validator')(tag, context) - odsh_tag_name_validator(tag, context) - -def odsh_group_convert(key, data, errors, context): - # print('GROUPS') - print(key) - print(data) - - -def odsh_validate_extra_groups(key, data, errors, context): - value = _extract_value(data, 'groups') - print('GROUPS') - print(value) - if not value: - return - groups = [g.strip() for g in value.split(',') if value.strip()] - # data[('groups', 0, 'id')]='soci' - # data[('groups', 1, 'id')]='ener' - print('STRIP') - print(groups) - for k in data.keys(): - print(k) - if len(k) == 3 and k[0] == 'groups': - print('del') - data[k]='' - # del data[k] - print(data) - - # for num, tag in zip(range(len(groups)), groups): - # data[('groups', num, 'id')] = tag - # # print(data[('groups', num, 'id')]) - -def odsh_group_string_convert(key, data, errors, context): - '''Takes a list of groups that is a comma-separated string (in data[key]) - and parses groups names. These are added to the data dict, enumerated. - They are also validated.''' - print('GROUPSTRING') - print(key) - - if isinstance(data[key], basestring): - tags = [tag.strip() - for tag in data[key].split(',') - if tag.strip()] - else: - tags = data[key] - - print(tags) - - current_index = max([int(k[1]) for k in data.keys() - if len(k) == 3 and k[0] == 'groups'] + [-1]) - - # for num, tag in zip(count(current_index+1), tags): - # data[('groups', num, 'id')] = tag - # print(data[('groups', num, 'id')]) - - - - # current_index = max([int(k[1]) for k in data.keys() - # if len(k) == 3 and k[0] == 'groups'] + [-1]) - - # for num, tag in zip(count(current_index+1), tags): - # data[('groups', num, 'id')] = tag - - # for tag in tags: - # toolkit.get_validator('tag_length_validator')(tag, context) - # odsh_tag_name_validator(tag, context) - - class OdshIcapPlugin(plugins.SingletonPlugin): plugins.implements(plugins.IUploader, inherit=True) @@ -323,6 +101,7 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm 'odsh_upload_known_formats': odsh_helpers.odsh_upload_known_formats, 'odsh_encodeurl': odsh_helpers.odsh_encodeurl, 'odsh_extract_error': odsh_helpers.odsh_extract_error, + 'odsh_extract_error_new': odsh_helpers.odsh_extract_error_new, 'odsh_extract_value_from_extras': odsh_helpers.odsh_extract_value_from_extras, 'odsh_create_checksum': odsh_helpers.odsh_create_checksum, 'presorted_license_options': odsh_helpers.presorted_license_options @@ -446,8 +225,11 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm for field in ['title', 'notes','license_id']: schema.update({field: [toolkit.get_converter('not_empty')]}) - # schema.update({'groups_string': [toolkit.get_converter('odsh_group_string_convert')]}) - # schema.update({'groupss': [toolkit.get_converter('odsh_group_convert')]}) + ##schema.update({'group_string': [toolkit.get_converter('odsh_group_string_convert')]}) + # for i, item in enumerate(schema['groups']): + #schema['id'].update({'id': schema['groups']['id']+[toolkit.get_converter('odsh_group_convert')]}) + ##schema['groups'].update({'id': schema['groups']['id']}) + ## schema.update({'groups': [toolkit.get_converter('empty')]}) for i, item in enumerate(schema['tags']['name']): if item == toolkit.get_validator('tag_name_validator'): @@ -455,7 +237,7 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm 'odsh_tag_name_validator') for i, item in enumerate(schema['tag_string']): if item == tag_string_convert: - schema['tag_string'][i] = odsh_tag_string_convert + schema['tag_string'][i] = validation.tag_string_convert schema['resources'].update({ 'url': [toolkit.get_converter('not_empty')], @@ -468,10 +250,13 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm toolkit.get_converter('odsh_validate_temporal_start'), toolkit.get_converter('odsh_validate_temporal_end'), toolkit.get_converter('known_spatial_uri'), - toolkit.get_converter('licenseAttributionByText'), - # toolkit.get_converter('odsh_validate_extra_groups') + toolkit.get_converter('licenseAttributionByText') ] }) + ##schema.update({'title': [toolkit.get_converter('odsh_validate_extras')]+ schema['title']}) + schema.update({'__extras': [toolkit.get_converter('odsh_validate_extras')] }) + # eschema = schema['extras'] + ##schema.update({'extras': None }) def create_package_schema(self): schema = super(OdshPlugin, self).create_package_schema() @@ -498,17 +283,7 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm return [] def get_validators(self): - return {'odsh_convert_groups_string': odsh_convert_groups_string, - 'licenseAttributionByText': odsh_validate_licenseAttributionByText, - 'known_spatial_uri': known_spatial_uri, - 'odsh_validate_issued': odsh_validate_extra_date_factory('issued'), - 'odsh_validate_temporal_start': odsh_validate_extra_date_factory('temporal_start'), - 'odsh_validate_temporal_end': odsh_validate_extra_date_factory('temporal_end'), - 'odsh_tag_name_validator': odsh_tag_name_validator, - 'odsh_group_string_convert':odsh_group_string_convert, - 'odsh_group_convert':odsh_group_convert, - 'odsh_validate_extra_groups':odsh_validate_extra_groups - } + return validation.get_validators() # Add the custom parameters to Solr's facet queries # use several daterange queries agains temporal_start and temporal_end field diff --git a/ckanext/odsh/templates/package/snippets/info.html b/ckanext/odsh/templates/package/snippets/info.html index 54d5419f196e175bc2841e83094182850ce2db5f..396f62caf4fb9f8797a78019358029dd90b421fc 100644 --- a/ckanext/odsh/templates/package/snippets/info.html +++ b/ckanext/odsh/templates/package/snippets/info.html @@ -21,12 +21,6 @@ Example: <div class="groups-detail info-detail"> <div>{{ _('Kategorie') }}:</div> {{ pkg.groups|map(attribute='display_name')|join('; ') }} - {% if h.check_access('package_update', {'id':pkg.id }) %} - <div> - {% link_for _('Edit Categories'), controller='package', action='groups', id=pkg.name, - class_='btn btn-edit-categories', icon='wrench' %} - </div> - {% endif %} </div> {% endblock %} diff --git a/ckanext/odsh/templates/package/snippets/package_basic_fields.html b/ckanext/odsh/templates/package/snippets/package_basic_fields.html index 683e0f7a6ea3ec7003ce60875b47334fd550a1fe..1d7e441549a414e4c9a3e3cbc6d675e18a778bae 100644 --- a/ckanext/odsh/templates/package/snippets/package_basic_fields.html +++ b/ckanext/odsh/templates/package/snippets/package_basic_fields.html @@ -266,39 +266,42 @@ is_required=true,placeholder=_('Enter title')) }} {% endif %} <!-- field groups --> - {# - <div class="control-group"> + {% set error_groups = h.odsh_extract_error_new('groups', errors) %} + <div class="control-group {{ " error" if error_groups }}"> {% set groups_label='Kategorien'%} {% set multiselect_nonSelectedText='keine' %} {% set multiselect_allSelectedText='alle' %} {% set multiselect_nSelectedText='gewählt' %} - <!-- {% set error = errors.groups %} --> <label for="field-groups" class="control-label">{{ groups_label }} <span title="{{ _("This field is required") }}" class="control-required">*</span> </label> <div class="controls"> - {% set existing_groups = data.get('groups') %} - {% if existing_groups %} - {% set existing_groups_string = existing_groups|map(attribute='id')|join(',') %} - {% else %} - {% set existing_groups_string = h.odsh_extract_value_from_extras(data.extras,'groups') %} - {% endif %} - {{existing_groups_string}} - {{existing_groups}} - {% if data.id %} - <input name='groups' value='[{"id":"ener"}]'></input> - {% else %} - <select id='field-groups' multiple="multiple" data-module="odsh_form" data-module-multiselect='true' - data-module-nonSelectedText="{{multiselect_nonSelectedText}}" data-module-allSelectedText="{{multiselect_allSelectedText}}" - data-module-nSelectedText="{{multiselect_nSelectedText}}"> - {% for option in h.groups_available()%} - <option value={{option.id}} {% if existing_groups_string!=None and option['id'] in existing_groups_string %}selected="selected" - {% endif %}> - {{ option['display_name'] }}</option> - {% endfor %} - </select> - {{ form.input_extra('groups', value=existing_groups_string, index=h.odsh_create_checksum('groups'), type='hidden')}} - {% endif %} + <div class="row-fluid"> + <div class="span6"> + {% set existing_groups = data.get('groups') %} + {% if existing_groups %} + {% set existing_groups_string = existing_groups|map(attribute='id')|join(',') %} + {% else %} + {% set existing_groups_string = h.odsh_extract_value_from_extras(data.extras,'groups') %} + {% endif %} + <select id='field-groups' multiple="multiple" data-module="odsh_form" data-module-multiselect='true' + data-module-nonSelectedText="{{multiselect_nonSelectedText}}" data-module-allSelectedText="{{multiselect_allSelectedText}}" + data-module-nSelectedText="{{multiselect_nSelectedText}}" data-module-update='{{data.id != None}}'> + {% for option in h.groups_available()%} + <option value={{option.id}} {% if existing_groups_string!=None and option['id'] in existing_groups_string %}selected="selected" + {% endif %}> + {{ option['display_name'] }}</option> + {% endfor %} + </select> + <div id='selected-groups'> + {{ form.input_extra('groups', value=existing_groups_string, index=h.odsh_create_checksum('groups'), type='hidden')}} + </div> + </div> + <div class="span6 inline-error"> + {% if error_groups %} + {{_(error_groups)}} + {% endif %} + </div> + </div> </div> - </div> - #} \ No newline at end of file + </div> \ No newline at end of file diff --git a/ckanext/odsh/templates/package/snippets/resource_form.html b/ckanext/odsh/templates/package/snippets/resource_form.html index 91eaae9a5354a38cf88c56962c6dca3a7d756fca..7652b0b67e4cc9ed4e885e2549f75f63416f075b 100644 --- a/ckanext/odsh/templates/package/snippets/resource_form.html +++ b/ckanext/odsh/templates/package/snippets/resource_form.html @@ -6,8 +6,6 @@ {% set active = data and data.state=='active' %} {% set action = form_action or h.url_for(controller='package', action='new_resource', id=pkg_name) %} -{{errors}} - <form id="resource-edit" class="dataset-form dataset-resource-form {%if(data)%}resource-edit-form{%endif%}" method="post" action="{{ action }}" data-module="basic-form resource-form" enctype="multipart/form-data" novalidate> {% block stages %} diff --git a/ckanext/odsh/templates/snippets/package_item.html b/ckanext/odsh/templates/snippets/package_item.html index 74f0e095bcf9dc59cf20dbd11eba93f16c753e4f..dc465a7b73a676196e9aedbb9edc5b1d431ffa00 100644 --- a/ckanext/odsh/templates/snippets/package_item.html +++ b/ckanext/odsh/templates/snippets/package_item.html @@ -32,7 +32,7 @@ Example: {% set timerange_label ='Zeitraum' %} {% set access_count_label ='Aufrufe' %} {% set issued_extra = h.odsh_extract_value_from_extras(package.extras,'issued') %} -{% set issued = h.odsh_render_datetime(value) if value else h.odsh_render_datetime(package.metadata_created)%} +{% set issued = h.odsh_render_datetime(value) if issued_extra else h.odsh_render_datetime(package.metadata_created)%} {% set categories = package.groups|map(attribute='display_name')|join(', ') if package.groups else '-' %} {% block package_item %} diff --git a/ckanext/odsh/validation.py b/ckanext/odsh/validation.py new file mode 100644 index 0000000000000000000000000000000000000000..3a6d6ef8d77cce82e51b8191c2590fb6028da5ed --- /dev/null +++ b/ckanext/odsh/validation.py @@ -0,0 +1,180 @@ +import csv +import re +import urllib2 +import json +from itertools import count +from dateutil.parser import parse + +import ckan.plugins.toolkit as toolkit +import ckan.model as model +from ckan.lib.navl.dictization_functions import Missing + +from pylons import config + +def _extract_value(data, field): + key = None + for k in data.keys(): + if data[k] == field: + key = k + break + if key is None: + return None + return data[(key[0], key[1], 'value')] + +def validate_extra_groups(data): + value = _extract_value(data, 'groups') + if not value: + raise toolkit.Invalid({'groups':'at least one group needed'}) + + groups = [g.strip() for g in value.split(',') if value.strip()] + for k in data.keys(): + if len(k) == 3 and k[0] == 'groups': + data[k]='' + # del data[k] + if len(groups)==0: + raise toolkit.Invalid({'groups':'at least one group needed'}) + + for num, tag in zip(range(len(groups)), groups): + data[('groups', num, 'id')] = tag + +def validate_extras(key, data, errors, context): + validate_extra_groups(data) + +def _set_value(data, field, value): + key = None + for k in data.keys(): + if data[k] == field: + key = k + break + if key is None: + return None + data[(key[0], key[1], 'value')] = value + +def validate_extra_date(key, field, data, errors, context): + value = _extract_value(data, field) + + if not value: + if field == 'temporal_end': + return # temporal_end is optional + # Statistikamt Nord does not always provide temporal_start/end, + # but their datasets have to be accepted as they are. + if not ('id',) in data or data[('id',)][:7] != 'StaNord': + raise toolkit.Invalid(field+':odsh_'+field+'_error_label') + else: + if re.match(r'\d\d\d\d-\d\d-\d\d', value): + try: + dt=parse(value) + _set_value(data, field, dt.isoformat()) + return + except ValueError: + pass + raise toolkit.Invalid(field+':odsh_'+field+'_not_date_error_label') + + +def validate_extra_date_factory(field): + return lambda key, data, errors, context: validate_extra_date(key, field, data, errors, context) + +def validate_licenseAttributionByText(key, data, errors, context): + register = model.Package.get_license_register() + isByLicense=False + for k in data: + if len(k) > 0 and k[0] == 'license_id' and data[k] and not isinstance(data[k], Missing) and \ + 'Namensnennung' in register[data[k]].title: + isByLicense = True + break + hasAttribution=False + for k in data: + if data[k] == 'licenseAttributionByText': + if isinstance(data[(k[0], k[1], 'value')], Missing): + del data[(k[0], k[1], 'value')] + del data[(k[0], k[1], 'key')] + break + else: + value = data[(k[0], k[1], 'value')] + hasAttribution = value != '' + break + if isByLicense and not hasAttribution: + raise toolkit.Invalid('licenseAttributionByText:odsh_licence_text_missing_error_label') + if not isByLicense and hasAttribution: + raise toolkit.Invalid('licenseAttributionByText:odsh_licence_text_not_allowed_error_label') + +def known_spatial_uri(key, data, errors, context): + value = _extract_value(data, 'spatial_uri') + + if not value: + raise toolkit.Invalid('spatial_uri:odsh_spatial_uri_error_label') + + mapping_file = config.get('ckanext.odsh.spatial.mapping') + try: + mapping_file = urllib2.urlopen(mapping_file) + except Exception: + raise Exception("Could not load spatial mapping file!") + + not_found = True + spatial_text = str() + spatial = str() + cr = csv.reader(mapping_file, delimiter="\t") + for row in cr: + if row[0].encode('UTF-8') == value: + not_found = False + spatial_text = row[1] + loaded = json.loads(row[2]) + spatial = json.dumps(loaded['geometry']) + break + if not_found: + raise toolkit.Invalid( + 'spatial_uri:odsh_spatial_uri_unknown_error_label') + + # Get the current extras index + current_indexes = [k[1] for k in data.keys() + if len(k) > 1 and k[0] == 'extras'] + + new_index = max(current_indexes) + 1 if current_indexes else 0 + + data[('extras', new_index, 'key')] = 'spatial_text' + data[('extras', new_index, 'value')] = spatial_text + data[('extras', new_index+1, 'key')] = 'spatial' + data[('extras', new_index+1, 'value')] = spatial + +def tag_name_validator(value, context): + tagname_match = re.compile('[\w \-.\:\(\)]*$', re.UNICODE) + if not tagname_match.match(value): + raise toolkit.Invalid(_('Tag "%s" must be alphanumeric ' + 'characters or symbols: -_.:()') % (value)) + return value + +def tag_string_convert(key, data, errors, context): + '''Takes a list of tags that is a comma-separated string (in data[key]) + and parses tag names. These are added to the data dict, enumerated. They + are also validated.''' + if isinstance(data[key], basestring): + tags = [tag.strip() + for tag in data[key].split(',') + if tag.strip()] + else: + tags = data[key] + + + current_index = max([int(k[1]) for k in data.keys() + if len(k) == 3 and k[0] == 'tags'] + [-1]) + + + + for num, tag in zip(count(current_index+1), tags): + data[('tags', num, 'name')] = tag + + for tag in tags: + toolkit.get_validator('tag_length_validator')(tag, context) + tag_name_validator(tag, context) + + +def get_validators(): + return { + 'licenseAttributionByText': validate_licenseAttributionByText, + 'known_spatial_uri': known_spatial_uri, + 'odsh_validate_issued': validate_extra_date_factory('issued'), + 'odsh_validate_temporal_start': validate_extra_date_factory('temporal_start'), + 'odsh_validate_temporal_end': validate_extra_date_factory('temporal_end'), + 'odsh_tag_name_validator': tag_name_validator, + 'odsh_validate_extras':validate_extras + } \ No newline at end of file