From 27a1258b09b8679e993674ea79a0ca1777b4ddaa Mon Sep 17 00:00:00 2001 From: anonymous <anonymous> Date: Wed, 20 Mar 2019 17:13:54 +0100 Subject: [PATCH] ODPSH-214: edit groups --- ckanext/odsh/fanstatic/odsh_form.js | 1 - ckanext/odsh/helpers.py | 11 +- .../odsh/i18n/de/LC_MESSAGES/ckanext-odsh.mo | Bin 6372 -> 6459 bytes .../odsh/i18n/de/LC_MESSAGES/ckanext-odsh.po | 5 +- ckanext/odsh/plugin.py | 257 ++---------------- .../odsh/templates/package/snippets/info.html | 6 - .../snippets/package_basic_fields.html | 57 ++-- .../package/snippets/resource_form.html | 2 - .../odsh/templates/snippets/package_item.html | 2 +- ckanext/odsh/validation.py | 180 ++++++++++++ 10 files changed, 239 insertions(+), 282 deletions(-) create mode 100644 ckanext/odsh/validation.py diff --git a/ckanext/odsh/fanstatic/odsh_form.js b/ckanext/odsh/fanstatic/odsh_form.js index c4bbb164..0562849c 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 5a92d0b0..d2d07cfb 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 GIT binary patch delta 1825 zcmaE2xZ9}yo)F7a1_lO(ECvP!83qQ19A*#?f%mX6Fo1;iLg|B0`Y0O%0}BHK!$~Or z92*0J5Ca3lB{l{IZUzR1r)&`OKC&?|ure?(@Ub&6urn|)h_FNCW!M=Q_!$`L88p}# z7`PZ17%bQs7z7y@7@XM|7!(*77(&?@7$g}O7|NjH6QJrAK@C{T4l#HqJH+Ds><kQS zAP2BBFmN(3Fx+HkV31&7V0a7_|HIC}Ai%)Dz{~-$M}&icL5!iEfkBM};xbzfh(laC zAO;6;Knx7yU|`^5U|@*lU|<jhg%Ae=gDL|9LlXxB11|#u!wL=t1{DSdhHV@S3?d8+ z47WKL7-Sh37(PJd`8XjSk>P}xW5x+F-xb8KXJBCP=7eaB;)J+7A4*qpLV~K96C6|w z{hSO8QVa|X^En|wzl)QBfro*CVL!+q1_p*RoD2-QAO~<l9LmWBu}Geafq{d8fkBlE z;vqdQh(k=d7#Qk75-wZ}4B`w748B|ti&D8DE-vMQSkw>IFa;{Vm<!_2%}|5)azR4w z7*yRwsJ;hWkdS=}RreN3e}jtu=VGV_#~C{}#HW1Rki;g%4T&Q;ZioX6xEUCP85kH$ zxgkFD<c2sno*R-@%DEv?GJ~6eL6d=jVIP$L0xHkP!@wZNz`&r-15xkC14*3uJoS*c z>*0aK*+w3S&(HHPFvv47Fua8FIe8(8Oc_d>@j^ntlb3;kiGhJ3m=~fijF*8ynt_3# zfR}+mkAZ=qhnIoDi-Cb*H!lN&1p@;E8y^G11V#o1dp=0oxlqp!3G#dVkT`h<rT_9n zLWD;EqEJErlA6^7AU?H+il+)d(m*kkZV-TkP_F<ebu%z5hVpj_FfgbwFfd#YfOzaX zRDZp=AVh<zAjARIf{-}#5`<)zAVEl?Nfv~}ah4z?Bub(D4nYP6Wd;U@$$|_FN(>AP z+XW#(eG97ZCzJ*i4xn;?T?k?xuMjxV*E5I+L4r(Eh=D<yfq}tQ2;z`JA&5Z@LXfzc zF9dP<9wA7`+!2CA*$W{^T4580qzMUOh=&ZId^cf;N8*GbA(<}>iMm>0P?Xg(FtiIp z63s%Wg44o~#C8*E&|6^!1|v|xAp&uLnFu6Xg^556iV=bMC=JTb6@et$auG<7*NA|9 z%CK03fkB6XfnkRTB!r)eFfa&$^8Z^AhztKi4G<887%U|Uaj}Xh#D_+rklf)S3dzqN zP<4S&IvPr+ibB#<z9_`pdQpgjCqT`aCJJ%z3Q-1zdQg$LUX+1BgMoqJfGDH@c`3@k zV9vn6AT9=p0)H_`YR(gbB)+*~kf1*-1__ymVi2E-h%+!~F)%P#i!(4NGB7Zti9^im z5QjwVHgN_9Lk0$hN8*qu5|LnV2balO5|Bh?EdlYFp9I9G;S!J%FIobU2FfHD7%V}F zO@e{JnSp`ftOO+L1SL1GV%yCunOLHblbTpuqL81Ls*qlkUs|A$mztWAnzA{CON&d} zDYK*`RUth!DK$?aI5SltH#09KwYVfTuUH{9GcQ%aJFz4+J-;Y3RUvV6k4OXy0JnUq AX#fBK delta 1739 zcmdmO^u)0Ko)F7a1_lO(Oa=x983qQ16lM?)f!DAxFo1;CLg|fAdMg_P0}BHK!%irF z9~%RM5Ca3lAvOjEZUzR1t85VS9<nhoure?({9|KaU}s=pU}1;I^RP28@G~&fGf1#A zFmN$2FlewdFbFa*Fc`BlFeorEFu1ZaFi0{mFr-1n8=&eYK@FJ84l#HoJH+Dk><kQS zAP2BBFmN(3Fq~v(V31&7V7Lqwf5XneAi%)D@EK|z3kL&(7(+b+gBS<IWx5;?hnR9e z40hmv80f~qz`)1Az~IZlz#z)Nz!1a1z@W;&z)-}&z`)DEz%YY@fkB0Vfnga31A_<y z1H)+!1_oIM28IVv`F|V`kMM9p%u(Znm~RT=*E29MSaU)&dT~Nr9uK86IUzw+%n1%E zhI&p01}O#xhJH>+(68cTVBle3U|0__h=GA&4<`eIF316#5QqMRTEx%Az`()4z#z&6 z@sJ!B#38C&3=H)k2@@^`25|-k23szOMWI{}3sRv9v!LRYTo4C#LJgeE1qrb^P<6|p z`nGXFLUcD&-C-zw1}c6P>X5r!4E5l|@`MYL$UbmE(!dv}L2TR%48jZy4BXrhAIWn= z9BRr9Nh7}8kf_MxW?;}{U|^U6<?n;aKjCIzkYiwAVC8|RSK)yqN>?68lqK=hL*lBP z2NFk1c^DYv85kJ$L;3f4Ac^ZIl;+`ugn&FR0|OHS1A`_nM4t{X1A{aJ1A`kc1A`s| z149xo1A`X>1H(jK1_lcT28KJl3=9((85l(QAZcb9KP05L)bm5);s}(!%nyn4NBj_l z@Ax69_zyqCr=kK7accoc+<QXlFabyiB@2L3H3LH>ls`d$fk6$FI0YacI}6qS7Ajx= zTL9t!K|x5IDF{NciH0B~u~-U1;@CkD5)$4}ew-i!gEFYx5M*FbVqjqC6@&!!2B^OC zQ2Lr6B(>j#@*fLA68kGbaER42{1;?k&}Lv@kQRbC#9attP?!)Tu1bX<E}tX>37Jho zkSN<H1W7A*gdl0+oe(4h*n}Z`8DWS=OoSmJ<|+({x?o{Ql*I~z(o8)ALpfBzLSaZ^ zTQ3YT=&&#YgAoG*!%bm`19(IrKG6|@7-S>@2_YLO-&q8bYkWl@K^`Om@oA+9BxL(U zAP$};0&&<1kUmiU-w9$cFfbezfw=T6RN-wANUnG*0?EH0q3V7?X%<n4L-<4?iAh2f zVz7oN#G#g=5DV=^Ar1|M%14MYFld0HPLzS69#mjV5@ld8XJBABAPNckAEJ;{EG`B~ zbZ%mhAkPtlgh-bd#D{yu7#Oq|7#N<2F)%1HFfj0oLkb{6aY&TLi!(47GB7Z7i$g+m zuQ<ekm&GAz>4`XlIk;r{E)MZ2g9N06W08Qwy}SeigCzq4gN+0OgEIpILzx69&KMYW VNo?N5wwrl#KbI!g=BFZIEC6s4m4N^N diff --git a/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.po b/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.po index 191aacf1..950414e8 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 c944fcf3..354c3622 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 54d5419f..396f62ca 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 683e0f7a..1d7e4415 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 91eaae9a..7652b0b6 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 74f0e095..dc465a7b 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 00000000..3a6d6ef8 --- /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 -- GitLab