feature: add validators and some privatedatasets helpers (before implementing templates 2.6)
This commit is contained in:
parent
905b144ed8
commit
a9dd3266cd
|
@ -57,7 +57,7 @@ class d4SHomeController():
|
|||
'sort': 'views_recent desc',
|
||||
'fq': 'capacity:"public"'
|
||||
}
|
||||
query = logic.get_action('package_search')(context, data_dict)
|
||||
query = logic.get_action('package_search')(context, data_dict or {})
|
||||
c.search_facets = query['search_facets']
|
||||
c.package_count = query['count']
|
||||
c.datasets = query['results']
|
||||
|
|
|
@ -71,7 +71,7 @@ class d4STypeController():
|
|||
'sort': 'views_recent desc',
|
||||
'fq': 'capacity:"public"'
|
||||
}
|
||||
query = logic.get_action('package_search')(context, data_dict)
|
||||
query = logic.get_action('package_search')(context, data_dict or {})
|
||||
c.search_facets = query['search_facets']
|
||||
c.package_count = query['count']
|
||||
c.datasets = query['results']
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2014 CoNWeT Lab., Universidad Politécnica de Madrid
|
||||
|
||||
# This file is part of CKAN Private Dataset Extension.
|
||||
|
||||
# CKAN Private Dataset Extension is free software: you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# CKAN Private Dataset Extension is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with CKAN Private Dataset Extension. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from logging import getLogger
|
||||
|
||||
import sqlalchemy as sa
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
AllowedUser = None
|
||||
|
||||
def init_db(model):
|
||||
log.debug("call initDB...")
|
||||
global AllowedUser
|
||||
if AllowedUser is None:
|
||||
|
||||
class _AllowedUser(model.DomainObject):
|
||||
|
||||
@classmethod
|
||||
def get(cls, **kw):
|
||||
'''Finds all the instances required.'''
|
||||
query = model.Session.query(cls).autoflush(False)
|
||||
results = query.filter_by(**kw).all()
|
||||
log.debug("results in get %s", results)
|
||||
if not isinstance(results, list):
|
||||
log.debug("Errore: il risultato di get() non è una lista. Risultato:", results)
|
||||
results = []
|
||||
return results
|
||||
|
||||
AllowedUser = _AllowedUser
|
||||
|
||||
log.debug("allowed user: %s", AllowedUser)
|
||||
|
||||
# FIXME: Maybe a default value should not be included...
|
||||
package_allowed_users_table = sa.Table(
|
||||
'package_allowed_users',
|
||||
model.meta.metadata,
|
||||
sa.Column('package_id', sa.types.UnicodeText, primary_key=True, default=u''),
|
||||
sa.Column('user_name', sa.types.UnicodeText, primary_key=True, default=u''),
|
||||
)
|
||||
|
||||
# Create the table only if it does not exist
|
||||
package_allowed_users_table.create(checkfirst=True)
|
||||
|
||||
model.meta.mapper(AllowedUser, package_allowed_users_table,)
|
|
@ -25,6 +25,8 @@ import collections
|
|||
import ckan.plugins.toolkit as tk
|
||||
import ckan.logic as logic
|
||||
|
||||
from ckanext.d4science_theme import db
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
systemtype_field = 'systemtypefield'
|
||||
|
@ -730,3 +732,77 @@ def get_site_statistics() -> dict[str, int]:
|
|||
'group_count': len(logic.get_action('group_list')({}, {})),
|
||||
'organization_count': len(logic.get_action('organization_list')({}, {}))
|
||||
}
|
||||
|
||||
#private dataset
|
||||
|
||||
def is_dataset_acquired(pkg_dict):
|
||||
|
||||
log.debug("is_dataset package value: %s", pkg_dict) #restituisce True
|
||||
|
||||
db.init_db(model)
|
||||
log.debug("post init %s", db)
|
||||
|
||||
#return False
|
||||
if tk.c.user:
|
||||
return len(db.AllowedUser.get(package_id=pkg_dict['id'], user_name=tk.c.user)) > 0
|
||||
else:
|
||||
return False
|
||||
|
||||
def is_owner(pkg_dict):
|
||||
return False
|
||||
#if tk.c.userobj is not None:
|
||||
# return tk.c.userobj.id == pkg_dict['creator_user_id']
|
||||
#else:
|
||||
# return False
|
||||
|
||||
|
||||
def get_allowed_users_str(users):
|
||||
if users:
|
||||
return ','.join([user for user in users])
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
def can_read(pkg_dict):
|
||||
try:
|
||||
context = {'user': tk.c.user, 'userobj': tk.c.userobj, 'model': model}
|
||||
return tk.check_access('package_show', context, pkg_dict)
|
||||
except tk.NotAuthorized:
|
||||
return False
|
||||
|
||||
|
||||
def get_config_bool_value(config_name, default_value=False):
|
||||
env_name = config_name.upper().replace('.', '_')
|
||||
value = os.environ.get(env_name, tk.config.get(config_name, default_value))
|
||||
return value if type(value) == bool else value.strip().lower() in ('true', '1', 'on')
|
||||
|
||||
|
||||
def show_acquire_url_on_create():
|
||||
return get_config_bool_value('ckan.privatedatasets.show_acquire_url_on_create')
|
||||
|
||||
|
||||
def show_acquire_url_on_edit():
|
||||
return get_config_bool_value('ckan.privatedatasets.show_acquire_url_on_edit')
|
||||
|
||||
|
||||
def acquire_button(package):
|
||||
'''
|
||||
Return a Get Access button for the given package id when the dataset has
|
||||
an acquisition URL.
|
||||
|
||||
:param package: the the package to request access when the get access
|
||||
button is clicked
|
||||
:type package: Package
|
||||
|
||||
:returns: a get access button as an HTML snippet
|
||||
:rtype: string
|
||||
|
||||
'''
|
||||
|
||||
if 'acquire_url' in package and request.path.startswith('/dataset')\
|
||||
and package['acquire_url'] != '':
|
||||
url_dest = package['acquire_url']
|
||||
data = {'url_dest': url_dest}
|
||||
return tk.render_snippet('snippets/acquire_button.html', data)
|
||||
else:
|
||||
return ''
|
|
@ -4,6 +4,7 @@ from logging import getLogger
|
|||
import ckan.plugins as plugins
|
||||
|
||||
from ckanext.d4science_theme import helpers
|
||||
from ckanext.d4science_theme import validators
|
||||
import ckan.plugins.toolkit as toolkit
|
||||
import ckan.model as model
|
||||
from ckanext.d4science_theme.controllers.home import d4SHomeController
|
||||
|
@ -47,7 +48,7 @@ def _package_extras_save(extra_dicts, obj, context):
|
|||
session = context["session"]
|
||||
|
||||
#ADDED BY FRANCESCO MANGIACRAPA
|
||||
log.debug("extra_dicts: "+ str(extra_dicts))
|
||||
log.debug("extra_dicts: %s", extra_dicts)
|
||||
#print "extra_dicts: "+str(extra_dicts)
|
||||
|
||||
extras_list = obj.extras_list
|
||||
|
@ -66,7 +67,7 @@ def _package_extras_save(extra_dicts, obj, context):
|
|||
#print 'extra_dict key: '+extra_dict["key"] + ', value: '+extra_dict["value"]
|
||||
#new_extras.setdefault(extra_dict["key"], []).append(extra_dict["value"])
|
||||
if extra_dict.get("deleted"):
|
||||
log.debug("extra_dict deleted: "+str(extra_dict["key"]))
|
||||
log.debug("extra_dict deleted: %s ", extra_dict["key"])
|
||||
#print 'extra_dict deleted: '+extra_dict["key"]
|
||||
continue
|
||||
|
||||
|
@ -75,13 +76,13 @@ def _package_extras_save(extra_dicts, obj, context):
|
|||
new_extras.setdefault(extra_dict["key"], []).append(extra_dict["value"])
|
||||
|
||||
#ADDED BY FRANCESCO MANGIACRAPA
|
||||
log.debug("new_extras: "+str(new_extras))
|
||||
log.debug("new_extras: %s", new_extras)
|
||||
#print "new_extras: "+str(new_extras)
|
||||
|
||||
#new
|
||||
for key in set(new_extras.keys()) - set(old_extras.keys()):
|
||||
state = 'active'
|
||||
log.debug("adding key: "+str(key))
|
||||
log.debug("adding key: %s", key)
|
||||
#print "adding key: "+str(key)
|
||||
extra_lst = new_extras[key]
|
||||
for extra in extra_lst:
|
||||
|
@ -105,13 +106,13 @@ def _package_extras_save(extra_dicts, obj, context):
|
|||
for value in new_extras[key]:
|
||||
old_occur = old_extras[key].count(value)
|
||||
new_occur = new_extras[key].count(value)
|
||||
log.debug("value: "+str(value) + ", new_occur: "+str(new_occur)+ ", old_occur: "+str(old_occur))
|
||||
log.debug("value: %s\n new_occur: %s\n old_occur: %s", value, new_occur, old_occur)
|
||||
#print "value: "+str(value) + ", new_occur: "+str(new_occur) + ", old_occur: "+str(old_occur)
|
||||
# it is an old value deleted or not
|
||||
if value in old_extras[key]:
|
||||
if old_occur == new_occur:
|
||||
#print "extra - occurrences of: "+str(value) +", are equal into both list"
|
||||
log.debug("extra - occurrences of: "+str(value) +", are equal into both list")
|
||||
log.debug("extra - occurrences of: %s are equal into both list", value)
|
||||
#there is a little bug, this code return always the first element, so I'm fixing with #FIX-STATUS
|
||||
extra_values = get_package_for_value(extras[key], value)
|
||||
#extras_list.append(extra)
|
||||
|
@ -120,44 +121,44 @@ def _package_extras_save(extra_dicts, obj, context):
|
|||
extra.state = state
|
||||
session.add(extra)
|
||||
#print "extra updated: "+str(extra)
|
||||
log.debug("extra updated: "+str(extra))
|
||||
log.debug("extra updated: %s", extra)
|
||||
|
||||
elif new_occur > old_occur:
|
||||
#print "extra - a new occurrence of: "+str(value) +", is present into new list, adding it to old list"
|
||||
log.debug("extra - a new occurrence of: "+str(value) +", is present into new list, adding it to old list")
|
||||
log.debug("extra - a new occurrence of: %s, is present into new list, adding it to old list", value)
|
||||
state = 'active'
|
||||
extra = model.PackageExtra(state=state, key=key, value=value)
|
||||
extra.state = state
|
||||
session.add(extra)
|
||||
extras_list.append(extra)
|
||||
old_extras[key].append(value)
|
||||
log.debug("old extra values updated: "+str(old_extras[key]))
|
||||
log.debug("old extra values updated: %s", old_extras[key])
|
||||
#print "old extra values updated: "+str(old_extras[key])
|
||||
|
||||
else:
|
||||
#remove all occurrences deleted - this code could be optimized, it is run several times but could be performed one shot
|
||||
countDelete = old_occur-new_occur
|
||||
log.debug("extra - occurrence of: "+str(value) +", is not present into new list, removing "+str(countDelete) + " occurrence/s from old list")
|
||||
log.debug("extra - occurrence of: %s, is not present into new list, removing: %s occurrence/s from old list", value, countDelete)
|
||||
#print "extra - occurrence of: "+str(value) +", is not present into new list, removing "+str(countDelete)+" occurrence/s from old list"
|
||||
extra_values = get_package_for_value(extras[key], value)
|
||||
for idx, extra in enumerate(extra_values):
|
||||
if idx < countDelete:
|
||||
#print "extra - occurrence of: "+str(value) +", is not present into new list, removing it from old list"
|
||||
log.debug("pkg extra deleting: "+str(extra.value))
|
||||
log.debug("pkg extra deleting: %s", extra.value)
|
||||
#print "pkg extra deleting: "+str(extra.value)
|
||||
state = 'deleted'
|
||||
extra.state = state
|
||||
|
||||
else:
|
||||
#print "pkg extra reactivating: "+str(extra.value)
|
||||
log.debug("pkg extra reactivating: "+str(extra.value))
|
||||
log.debug("pkg extra reactivating: %s", extra.value)
|
||||
state = 'active'
|
||||
extra.state = state
|
||||
session.add(extra)
|
||||
|
||||
else:
|
||||
#print "extra new value: "+str(value)
|
||||
log.debug("extra new value: "+str(value))
|
||||
log.debug("extra new value: %s", value)
|
||||
state = 'active'
|
||||
extra = model.PackageExtra(state=state, key=key, value=value)
|
||||
extra.state = state
|
||||
|
@ -193,13 +194,15 @@ def get_package_for_value(list_package, value):
|
|||
|
||||
class D4Science_ThemePlugin(plugins.SingletonPlugin, toolkit.DefaultDatasetForm):
|
||||
plugins.implements(plugins.IConfigurer)
|
||||
plugins.implements(plugins.IDatasetForm)
|
||||
plugins.implements(plugins.IDatasetForm, inherit=True)
|
||||
plugins.implements(plugins.ITemplateHelpers)
|
||||
plugins.implements(plugins.IFacets)
|
||||
#plugins.implements(IRoutes, inherit=True)
|
||||
|
||||
#ckan 2.10
|
||||
plugins.implements(plugins.IBlueprint)
|
||||
plugins.implements(plugins.IValidators)
|
||||
plugins.implements(plugins.IPackageController, inherit=True)
|
||||
|
||||
# IConfigurer
|
||||
def update_config(self, config_):
|
||||
|
@ -219,37 +222,157 @@ class D4Science_ThemePlugin(plugins.SingletonPlugin, toolkit.DefaultDatasetForm)
|
|||
toolkit.add_resource('assets', 'd4science_theme')
|
||||
# toolkit.add_resource('assets', 'd4science_scripts')
|
||||
|
||||
def _modify_package_schema(self):
|
||||
log.debug("*** modify package ***")
|
||||
|
||||
# Personalizza il campo 'extras' rimuovendo il validatore extra_key_not_in_root_schema
|
||||
|
||||
return {
|
||||
'private': [toolkit.get_validator('ignore_missing'),
|
||||
toolkit.get_validator('boolean_validator')],
|
||||
'extras': {
|
||||
'id': [toolkit.get_validator('ignore')], # Ignora 'id' come prima
|
||||
'key': [toolkit.get_validator('not_empty'), toolkit.get_validator('unicode_safe'), validators.ignore_duplicate_keys], # Aggiunto ignore duplicate
|
||||
'value': [toolkit.get_validator('not_missing')]
|
||||
}
|
||||
}
|
||||
|
||||
#IDatasetForm
|
||||
def create_package_schema(self):
|
||||
# let's grab the default schema in our plugin
|
||||
log.debug("creating package....")
|
||||
schema = super(D4Science_ThemePlugin, self).create_package_schema()
|
||||
schema = remove_check_replicated_custom_key(schema)
|
||||
log.debug("schema after create prima del validator %s", schema)
|
||||
#schema = remove_check_replicated_custom_key(schema)
|
||||
#schema.update(self._modify_package_schema(schema))
|
||||
schema.update(self._modify_package_schema())
|
||||
#d.package_dict_save = _package_dict_save
|
||||
log.debug("create_package1 %s", schema)
|
||||
return schema
|
||||
|
||||
#IDatasetForm
|
||||
def update_package_schema(self):
|
||||
log.debug("** update_package **")
|
||||
schema = super(D4Science_ThemePlugin, self).update_package_schema()
|
||||
schema = remove_check_replicated_custom_key(schema)
|
||||
#schema = remove_check_replicated_custom_key(schema)
|
||||
#schema.update(self._modify_package_schema(schema))
|
||||
schema.update(self._modify_package_schema())
|
||||
log.debug("update_package1 %s", schema)
|
||||
return schema
|
||||
|
||||
#IDatasetForm
|
||||
def show_package_schema(self):
|
||||
log.debug("** show package **")
|
||||
schema = super(D4Science_ThemePlugin, self).show_package_schema()
|
||||
schema = remove_check_replicated_custom_key(schema)
|
||||
log.debug("show_package1 %s", schema)
|
||||
#schema = remove_check_replicated_custom_key(schema)
|
||||
#schema.update(self._modify_package_schema(schema))
|
||||
schema.update({
|
||||
'extras': {
|
||||
'id': [toolkit.get_validator('ignore')], # Ignora 'id' come prima
|
||||
'key': [toolkit.get_validator('not_empty'), toolkit.get_validator('unicode_safe'), validators.ignore_duplicate_keys], # Aggiunto ignore duplicate
|
||||
'value': [toolkit.get_validator('not_missing')]
|
||||
}
|
||||
})
|
||||
log.debug("show_package2 %s", schema)
|
||||
return schema
|
||||
|
||||
#IDatasetForm
|
||||
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 False
|
||||
return True
|
||||
|
||||
#IDatasetForm
|
||||
def package_types(self):
|
||||
# This plugin doesn't handle any special package types, it just
|
||||
# registers itself as the default (above).
|
||||
return []
|
||||
|
||||
def get_validators(self):
|
||||
return {
|
||||
'ignore_duplicate_keys': validators.ignore_duplicate_keys
|
||||
}
|
||||
|
||||
#IPackageController
|
||||
#def before_dataset_search(self, search_params):
|
||||
# search_params = search_params or {}
|
||||
# return search_params
|
||||
#
|
||||
#def after_dataset_search(self, search_results, data_dict):
|
||||
# return search_results
|
||||
#
|
||||
#def before_search(self, search_params):
|
||||
# # Controlla se search_params è None e sostituiscilo con un dizionario vuoto
|
||||
# search_params = search_params or {}
|
||||
# return search_params
|
||||
#
|
||||
#def before_create(self, context, data_dict):
|
||||
# self.apply_custom_extras_validator(data_dict)
|
||||
#
|
||||
#def before_update(self, context, data_dict):
|
||||
# self.apply_custom_extras_validator(data_dict)
|
||||
#
|
||||
|
||||
## utile ##
|
||||
#def before_dataset_save(self, context, data_dict):
|
||||
# log.debug("sto chiamando before_dataset_save")
|
||||
# # Intercetta il salvataggio dei dataset prima che venga effettuato il controllo
|
||||
# extras_list = data_dict.get('extras', [])
|
||||
#
|
||||
# # Aggiungi una logica per evitare che venga applicato un controllo su chiavi duplicate
|
||||
# # Si elimina la logica di validazione delle chiavi duplicate
|
||||
# unique_extras = {}
|
||||
# for extra in extras_list:
|
||||
# key = extra.get('key')
|
||||
# if key in unique_extras:
|
||||
# # Consenti la duplicazione delle chiavi, quindi non lo filtriamo
|
||||
# unique_extras[key].append(extra)
|
||||
# else:
|
||||
# unique_extras[key] = [extra]
|
||||
#
|
||||
# # Restituisci un nuovo 'extras' senza rimuovere le chiavi duplicate
|
||||
# data_dict['extras'] = [e for extras in unique_extras.values() for e in extras]
|
||||
# return data_dict
|
||||
def convert_to_boolean(self, value):
|
||||
log.debug("value boolean %s", value)
|
||||
if isinstance(value, str):
|
||||
if value.lower() == 'true':
|
||||
return True
|
||||
elif value.lower() == 'false':
|
||||
return False
|
||||
return value
|
||||
|
||||
#IValidator
|
||||
def validate(self, context, data_dict, schema, action):
|
||||
# Modifica il comportamento del validatore per ignorare le chiavi duplicate
|
||||
# Assicurati che 'private' sia un valore booleano
|
||||
log.debug("calling, validate, questo è lo schema: %s", schema)
|
||||
data_dict['private'] = self.convert_to_boolean(data_dict.get('private', False))
|
||||
errors = []
|
||||
#todo change this function
|
||||
if 'extras' in data_dict:
|
||||
log.debug("extras presente")
|
||||
extras = data_dict['extras']
|
||||
new_extras = []
|
||||
log.debug("extras value before for: %s e lunghezza: %s", extras, len(extras))
|
||||
# Aggiungi ogni coppia chiave-valore alla nuova lista, mantenendo i duplicati
|
||||
for extra in extras:
|
||||
new_extras.append(extra)
|
||||
log.debug("Aggiunta extra con chiave duplicata: %s -> %s", extra['key'], extra['value'])
|
||||
|
||||
# Aggiorna il data_dict con la lista di extras che include i duplicati
|
||||
data_dict['extras'] = new_extras
|
||||
log.debug("new extras mantenendo i duplicati: %s", new_extras)
|
||||
log.debug("pre return validate %s", data_dict)
|
||||
return data_dict, errors
|
||||
|
||||
def apply_custom_extras_validator(self, data_dict):
|
||||
"""
|
||||
Funzione helper per applicare il validator agli extras
|
||||
"""
|
||||
extras = data_dict.get('extras', [])
|
||||
# Esegui il validator per assicurare il salvataggio dei duplicati
|
||||
validators.ignore_duplicate_keys('extras', data_dict, [], {})
|
||||
|
||||
#ITemplateHelpers
|
||||
def get_helpers(self):
|
||||
|
@ -290,6 +413,13 @@ class D4Science_ThemePlugin(plugins.SingletonPlugin, toolkit.DefaultDatasetForm)
|
|||
'd4science_get_location_to_bboxes' : helpers.get_location_to_bboxes,
|
||||
'd4science_get_content_moderator_system_placeholder': helpers.get_content_moderator_system_placeholder,
|
||||
'd4science_get_site_statistics': helpers.get_site_statistics,
|
||||
'is_dataset_acquired': helpers.is_dataset_acquired,
|
||||
'get_allowed_users_str': helpers.get_allowed_users_str,
|
||||
'is_owner': helpers.is_owner,
|
||||
'can_read': helpers.can_read,
|
||||
'show_acquire_url_on_create': helpers.show_acquire_url_on_create,
|
||||
'show_acquire_url_on_edit': helpers.show_acquire_url_on_edit,
|
||||
'acquire_button': helpers.acquire_button
|
||||
}
|
||||
|
||||
#Overriding package_extras_save method
|
||||
|
|
|
@ -1,70 +1,139 @@
|
|||
{#
|
||||
Displays a single of dataset.
|
||||
|
||||
package - A package to display.
|
||||
item_class - The class name to use on the list item.
|
||||
hide_resources - If true hides the resources (default: false).
|
||||
|
||||
Example:
|
||||
|
||||
{% snippet 'snippets/package_item.html', package=c.datasets[0] %}
|
||||
|
||||
#}
|
||||
{% set title = package.title or package.name %}
|
||||
{% set notes = h.markdown_extract(package.notes, extract_length=180) %}
|
||||
|
||||
{% block package_item %}
|
||||
Displays a single of dataset.
|
||||
|
||||
package - A package to display.
|
||||
item_class - The class name to use on the list item.
|
||||
hide_resources - If true hides the resources (default: false).
|
||||
banner - If true displays a popular banner (default: false).
|
||||
truncate - The length to trucate the description to (default: 180)
|
||||
truncate_title - The length to truncate the title to (default: 80).
|
||||
|
||||
Example:
|
||||
|
||||
{% snippet 'snippets/package_item.html', package=c.datasets[0] %}
|
||||
|
||||
#}
|
||||
|
||||
{% set truncate = truncate or 180 %}
|
||||
{% set truncate_title = truncate_title or 80 %}
|
||||
{% set title = package.title or package.name %}
|
||||
{% set notes = h.markdown_extract(package.notes, extract_length=truncate) %}
|
||||
<!-- TODO: remove this comments after implementing privateDatasets
|
||||
{% set acquired = h.is_dataset_acquired(package) %}
|
||||
{% set owner = h.is_owner(package) %} -->
|
||||
|
||||
{#
|
||||
{% resource 'd4science_theme/custom.css' %}
|
||||
CHANGED BY FRANCESCO.MANGIACRAPA
|
||||
#}
|
||||
|
||||
{% block package_item_content %}
|
||||
|
||||
{% if package.private and not h.can_read(package) %}
|
||||
<li class="{{ item_class or "dataset-item" }}">
|
||||
{% block content %}
|
||||
<div class="dataset-content">
|
||||
{% block heading %}
|
||||
<h2 class="dataset-heading">
|
||||
{% block heading_private %}
|
||||
{% if package.private %}
|
||||
<span class="dataset-private badge bg-secondary">
|
||||
<i class="fa fa-lock"></i>
|
||||
{{ _('Private') }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block heading_title %}
|
||||
<a href="{{ h.url_for('%s.read' % package.type, id=package.name) }}" title="{{ title }}">
|
||||
{{title|truncate(80)}}
|
||||
</a>
|
||||
{% endblock %}
|
||||
{% block heading_meta %}
|
||||
{% if package.get('state', '').startswith('draft') %}
|
||||
<span class="badge bg-info">{{ _('Draft') }}</span>
|
||||
{% elif package.get('state', '').startswith('deleted') %}
|
||||
<span class="badge bg-danger">{{ _('Deleted') }}</span>
|
||||
{% endif %}
|
||||
{{ h.popular('recent views', package.tracking_summary.recent, min=10) if package.tracking_summary }}
|
||||
{% endblock %}
|
||||
</h2>
|
||||
{% endblock %}
|
||||
{% block notes %}
|
||||
{% if notes %}
|
||||
<div>{{ notes|urlize }}</div>
|
||||
{% else %}
|
||||
<p class="empty">{{ h.humanize_entity_type('package', package.type, 'no description') or _("There is no description for this dataset") }}</p>
|
||||
<h3 class="dataset-heading">
|
||||
{% if package.private and not h.can_read(package) %}
|
||||
<span class="dataset-private label label-inverse">
|
||||
<i class="icon-lock"></i>
|
||||
{{ _('Private') }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% block resources %}
|
||||
{% if package.resources and not hide_resources %}
|
||||
{% block resources_outer %}
|
||||
<ul class="dataset-resources list-unstyled">
|
||||
{% block resources_inner %}
|
||||
{% for resource in h.dict_list_reduce(package.resources, 'format') %}
|
||||
<li>
|
||||
<a href="{{ h.url_for(package.type ~ '.read', id=package.name) }}" class="badge badge-default" data-format="{{ resource.lower() }}">{{ resource }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
<!-- TODO: remove this comments after implementing privateDatasets
|
||||
{% if acquired and not owner %}
|
||||
<span class="dataset-private label label-acquired">
|
||||
<i class="icon-shopping-cart"></i>
|
||||
{{ _('Acquired') }}
|
||||
</span>
|
||||
{% endif %} -->
|
||||
|
||||
<!-- Customizations Acquire Button -->
|
||||
{% if package.private and not h.can_read(package) %}
|
||||
{# {{ _(h.truncate(title, truncate_title)) }} #} <!-- THIS IS PACKAGE TITLE -->
|
||||
Dataset
|
||||
<div class="divider"/>
|
||||
{{ h.acquire_button(package) }}
|
||||
{% else %}
|
||||
{# {{ h.link_to(h.truncate(title, truncate_title), h.url_for(controller='package', action='read', id=package.name)) }} #}
|
||||
{{ h.link_to(h.truncate(title, truncate_title), url_for('dataset.read', id=package.name)) }}
|
||||
{% endif %}
|
||||
<!-- End of customizations Acquire Button -->
|
||||
|
||||
{% if package.get('state', '').startswith('draft') %}
|
||||
<span class="label label-info">{{ _('Draft') }}</span>
|
||||
{% elif package.get('state', '').startswith('deleted') %}
|
||||
<span class="label label-important">{{ _('Deleted') }}</span>
|
||||
{% endif %}
|
||||
{{ h.popular('recent views', package.tracking_summary.recent, min=10) if package.tracking_summary }}
|
||||
</h3>
|
||||
{% if banner %}
|
||||
<span class="banner">{{ _('Popular') }}</span>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
{% if notes %}
|
||||
<!-- <div>{{ notes|urlize }}</div>--><!-- THIS IS PACKAGE DESCRIPTION -->
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% endblock %}
|
||||
{% else %}
|
||||
<li class="{{ item_class or "dataset-item" }}">
|
||||
<div class="dataset-content">
|
||||
<h3 class="dataset-heading">
|
||||
{% if package.private and not h.can_read(package) %}
|
||||
<span class="dataset-private label label-inverse">
|
||||
<i class="icon-lock"></i>
|
||||
{{ _('Private') }}
|
||||
</span>
|
||||
{% endif %}
|
||||
<!-- TODO: remove this comments after implementing privateDatasets
|
||||
{% if acquired and not owner %}
|
||||
<span class="dataset-private label label-acquired">
|
||||
<i class="icon-shopping-cart"></i>
|
||||
{{ _('Acquired') }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if owner %}
|
||||
<span class="dataset-private label label-owner">
|
||||
<i class="icon-user"></i>
|
||||
{{ _('Owner') }}
|
||||
</span>
|
||||
{% endif %} -->
|
||||
|
||||
<!-- Customizations Acquire Button -->
|
||||
{% if package.private and not h.can_read(package) %}
|
||||
{{ _(h.truncate(title, truncate_title)) }}
|
||||
<div class="divider"/>
|
||||
{{ h.acquire_button(package) }}
|
||||
{% else %}
|
||||
{# {{ h.link_to(h.truncate(title, truncate_title), h.url_for(controller='package', action='read', id=package.name)) }} #}
|
||||
{{ h.link_to(h.truncate(title, truncate_title), url_for('dataset.read', id=package.name)) }}
|
||||
{% endif %}
|
||||
<!-- End of customizations Acquire Button -->
|
||||
|
||||
{% if package.get('state', '').startswith('draft') %}
|
||||
<span class="label label-info">{{ _('Draft') }}</span>
|
||||
{% elif package.get('state', '').startswith('deleted') %}
|
||||
<span class="label label-important">{{ _('Deleted') }}</span>
|
||||
{% endif %}
|
||||
{{ h.popular('recent views', package.tracking_summary.recent, min=10) if package.tracking_summary }}
|
||||
</h3>
|
||||
{% if banner %}
|
||||
<span class="banner">{{ _('Popular') }}</span>
|
||||
{% endif %}
|
||||
{% if notes %}
|
||||
<div>{{ notes|urlize }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if package.resources and not hide_resources %}
|
||||
<ul class="dataset-resources unstyled">
|
||||
{% for resource in h.dict_list_reduce(package.resources, 'format') %}
|
||||
<li>
|
||||
{# <a href="{{ h.url_for(controller='package', action='read', id=package.name) }}" class="label" data-format="{{ resource.lower() }}">{{ resource }}</a> #}
|
||||
<a href="{{ url_for('dataset.read', id=package.name) }}" class="label" data-format="{{ resource.lower() }}">{{ resource }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,24 @@
|
|||
import ckan.plugins.toolkit as toolkit
|
||||
from logging import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
def ignore_duplicate_keys(key, data, errors, context):
|
||||
"""
|
||||
Validator che consente chiavi duplicate negli extras.
|
||||
"""
|
||||
# Estrarre gli extras dalla richiesta
|
||||
log.debug("controllo extra (data) %s", data)
|
||||
extras = data.get(key, [])
|
||||
|
||||
# Log per il debugging
|
||||
log.debug(f"Contenuto di 'data' per la chiave '{key}': {extras} (tipo: {type(extras)})")
|
||||
|
||||
# Se ci sono duplicati, evita di sollevare un'eccezione
|
||||
if isinstance(extras, list): # Verifica che extras sia una lista
|
||||
log.debug(f"Ignorando chiave duplicata: {extra['key']}")
|
||||
else:
|
||||
log.debug(f"Errore: 'extras' non è una lista, ma è di tipo {type(extras)}")
|
||||
|
||||
## Mantieni la lista aggiornata, che consente chiavi duplicate
|
||||
data[key] = extras
|
|
@ -1,3 +1,4 @@
|
|||
webhelpers2
|
||||
xmltodict
|
||||
pyqrcode
|
||||
sqlalchemy
|
||||
|
|
|
@ -69,8 +69,7 @@ setup(
|
|||
# installed, specify them here. If using Python 2.6 or less, then these
|
||||
# have to be included in MANIFEST.in as well.
|
||||
include_package_data=True,
|
||||
package_data={
|
||||
},
|
||||
#package_data={},
|
||||
|
||||
# Although 'package_data' is the preferred approach, in some case you may
|
||||
# need to place data files outside of your packages.
|
||||
|
|
Loading…
Reference in New Issue