307 lines
12 KiB
Python
307 lines
12 KiB
Python
import ckan.plugins as plugins
|
|
import ckan.plugins.toolkit as toolkit
|
|
import ckan.lib.dictization.model_save as model_save
|
|
import sqlalchemy as sa
|
|
from ckan.views.resource import Blueprint
|
|
from ckanext.d4science import helpers
|
|
from ckanext.d4science.logic import action, auth
|
|
from ckanext.d4science.logic import validators
|
|
from ckan.config.middleware.common_middleware import TrackingMiddleware
|
|
from ckan.model import Package
|
|
from logging import getLogger
|
|
from flask import g
|
|
|
|
log = getLogger(__name__)
|
|
|
|
def remove_check_replicated_custom_key(schema):
|
|
if schema is not None:
|
|
schema.pop('__before', None)
|
|
|
|
return schema
|
|
|
|
def _package_extras_save(extra_dicts, obj, context):
|
|
''' It can save repeated extras as key-value '''
|
|
#allow_partial_update = context.get("allow_partial_update", False) potrebbe non servire
|
|
if extra_dicts is None: #and allow_partial_update:
|
|
return
|
|
|
|
model = context["model"]
|
|
session = context["session"]
|
|
|
|
log.debug("extra_dicts: "+ str(extra_dicts))
|
|
#print "extra_dicts: "+str(extra_dicts)
|
|
|
|
extras_list = obj.extras_list
|
|
#extras = dict((extra.key, extra) for extra in extras_list)
|
|
old_extras = {}
|
|
extras = {}
|
|
for extra in extras_list or []:
|
|
old_extras.setdefault(extra.key, []).append(extra.value)
|
|
extras.setdefault(extra.key, []).append(extra)
|
|
|
|
#print "old_extras: "+str(old_extras)
|
|
|
|
new_extras = {}
|
|
for extra_dict in extra_dicts or []:
|
|
#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"]))
|
|
#print 'extra_dict deleted: '+extra_dict["key"]
|
|
continue
|
|
|
|
#if extra_dict['value'] is not None and not extra_dict["value"] == "":
|
|
if extra_dict['value'] is not None:
|
|
new_extras.setdefault(extra_dict["key"], []).append(extra_dict["value"])
|
|
|
|
log.debug("new_extras: "+ str(new_extras))
|
|
#print "new_extras: "+str(new_extras)
|
|
|
|
#aggiunta di nuove chiavi
|
|
for key in set(new_extras.keys()) - set(old_extras.keys()):
|
|
#state = 'active'
|
|
log.debug("adding key: " + str(key))
|
|
#print "adding key: "+str(key)
|
|
extra_lst = new_extras[key]
|
|
for extra in extra_lst:
|
|
extra = model.PackageExtra(state='active', key=key, value=extra)
|
|
session.add(extra)
|
|
extras_list.append(extra)
|
|
|
|
#gestione chiavi eliminate
|
|
for key in set(old_extras.keys()) - set(new_extras.keys()):
|
|
log.debug("deleting key: "+ str(key))
|
|
#print "deleting key: "+str(key)
|
|
extra_lst = extras[key]
|
|
for extra in extra_lst:
|
|
#state = 'deleted'
|
|
extra.state = 'deleted'
|
|
extras_list.remove(extra)
|
|
|
|
#gestione chiavi aggiornate
|
|
for key in set(new_extras.keys()) & set(old_extras.keys()):
|
|
#for each value of new list
|
|
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))
|
|
#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")
|
|
#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)
|
|
for extra in extra_values:
|
|
#state = 'active'
|
|
extra.state = 'active'
|
|
session.add(extra)
|
|
#print "extra updated: "+str(extra)
|
|
log.debug("extra updated: "+ str(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")
|
|
#state = 'active'
|
|
extra = model.PackageExtra(state='active', key=key, value=value)
|
|
#extra.state = state
|
|
#extra.state = 'active' non dovrebbe servire
|
|
session.add(extra)
|
|
extras_list.append(extra)
|
|
old_extras[key].append(value)
|
|
log.debug("old extra values updated: "+ str(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).encode('utf-8') + ", is not present into new list, removing "+ str(countDelete).encode('utf-8')+" occurrence/s from old list")
|
|
#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))
|
|
#print "pkg extra deleting: "+str(extra.value)
|
|
#state = 'deleted'
|
|
extra.state = 'deleted'
|
|
|
|
else:
|
|
#print "pkg extra reactivating: "+str(extra.value)
|
|
log.debug("pkg extra reactivating: "+ str(extra.value))
|
|
#state = 'active'
|
|
extra.state = 'active'
|
|
session.add(extra)
|
|
|
|
else:
|
|
#print "extra new value: "+str(value)
|
|
log.debug("extra new value: " + str(value))
|
|
#state = 'active'
|
|
extra = model.PackageExtra(state='active', key=key, value=value)
|
|
#extra.state = state
|
|
#extra.state = 'active'
|
|
session.add(extra)
|
|
extras_list.append(extra)
|
|
|
|
|
|
#chiavi vecchie non presenti
|
|
for value in old_extras[key]:
|
|
#if value is not present in new list
|
|
if value not in new_extras[key]:
|
|
extra_values = get_package_for_value(extras[key], value)
|
|
for extra in extra_values:
|
|
#print "not present extra deleting: "+str(extra)
|
|
log.debug("not present extra deleting: "+ str(extra))
|
|
#state = 'deleted'
|
|
extra.state = 'deleted'
|
|
|
|
def get_package_for_value(list_package, value):
|
|
''' Returns a list of packages containing the value passed in input'''
|
|
|
|
return [x for x in list_package if x.value == value]
|
|
#lst = []
|
|
#for x in list_package:
|
|
# if x.value == value:
|
|
# lst.append(x)
|
|
# else:
|
|
# return lst
|
|
#
|
|
#return lst
|
|
|
|
|
|
#OVERRIDING BASE SQL ALCHEMY ENGINE INSTANCE
|
|
#gestisce le connessioni al db relazionale utilizzato da ckan
|
|
def _init_TrackingMiddleware(self, app, config):
|
|
self.app = app
|
|
log.debug('TrackingMiddleware d4Science instance')
|
|
sqlalchemy_url = config.get('sqlalchemy.url')
|
|
log.debug('sqlalchemy_url read: '+str(sqlalchemy_url))
|
|
|
|
sqlalchemy_pool = config.get('sqlalchemy.pool_size')
|
|
if sqlalchemy_pool is None:
|
|
sqlalchemy_pool = 5
|
|
|
|
log.debug('sqlalchemy_pool read: '+str(sqlalchemy_pool))
|
|
sqlalchemy_overflow = config.get('sqlalchemy.max_overflow')
|
|
|
|
if sqlalchemy_overflow is None:
|
|
sqlalchemy_overflow = 10
|
|
|
|
log.debug('sqlalchemy_overflow read: '+str(sqlalchemy_overflow))
|
|
|
|
try:
|
|
self.engine = sa.create_engine(sqlalchemy_url, pool_size=int(sqlalchemy_pool), max_overflow=int(sqlalchemy_overflow))
|
|
except TypeError as e:
|
|
log.error('pool size does not work: ' +str(e.args))
|
|
self.engine = sa.create_engine(sqlalchemy_url)
|
|
|
|
|
|
# import ckanext.d4science.cli as cli
|
|
# import ckanext.d4science.helpers as helpers
|
|
import ckanext.d4science.views as views
|
|
# from ckanext.d4science.logic import (
|
|
# action, auth, validators
|
|
# )
|
|
|
|
|
|
class D4SciencePlugin(plugins.SingletonPlugin):
|
|
plugins.implements(plugins.IConfigurer)
|
|
|
|
plugins.implements(plugins.IAuthFunctions)
|
|
plugins.implements(plugins.IActions)
|
|
# plugins.implements(plugins.IClick)
|
|
plugins.implements(plugins.ITemplateHelpers)
|
|
plugins.implements(plugins.IValidators)
|
|
plugins.implements(plugins.IDatasetForm)
|
|
|
|
#ckan 2.10
|
|
plugins.implements(plugins.IBlueprint)
|
|
|
|
|
|
# IConfigurer
|
|
|
|
def update_config(self, config_):
|
|
toolkit.add_template_directory(config_, "templates")
|
|
toolkit.add_public_directory(config_, "public")
|
|
toolkit.add_resource("assets", "d4science")
|
|
|
|
|
|
# IAuthFunctions
|
|
|
|
def get_auth_functions(self):
|
|
return auth.get_auth_functions()
|
|
|
|
# IActions
|
|
|
|
def get_actions(self):
|
|
return action.get_actions()
|
|
|
|
#IDataSetForm for custom datatype and dataset
|
|
|
|
def package_types(self):
|
|
# Aggiunta del tipo di dato personalizzato deliverable
|
|
return []
|
|
|
|
def is_fallback(self):
|
|
# Indica che questo plugin può essere usato come fallback se un tipo specifico non è specificato
|
|
return False
|
|
|
|
#IDatasetForm
|
|
def package_types(self):
|
|
# This plugin doesn't handle any special package types, it just
|
|
# registers itself as the default (above).
|
|
return []
|
|
|
|
def create_package_schema(self):
|
|
schema = super(D4SciencePlugin, self).create_package_schema()
|
|
schema = remove_check_replicated_custom_key(schema)
|
|
#schema.update({
|
|
# 'deliverable_type': [ignore_missing, unicode],
|
|
#})
|
|
return schema
|
|
|
|
def update_package_schema(self):
|
|
schema = super(D4SciencePlugin, self).update_package_schema()
|
|
schema = remove_check_replicated_custom_key(schema)
|
|
#schema.update({
|
|
# 'deliverable_type': [ignore_missing, unicode],
|
|
#})
|
|
return schema
|
|
|
|
def show_package_schema(self):
|
|
schema = super(D4SciencePlugin, self).show_package_schema()
|
|
schema = remove_check_replicated_custom_key(schema)
|
|
#schema.update({
|
|
# 'deliverable_type': [ignore_missing, unicode],
|
|
#})
|
|
return schema
|
|
|
|
#override
|
|
model_save.package_extras_save = _package_extras_save
|
|
|
|
#OVERRIDING BASE SQL ALCHEMY ENGINE INSTANCE
|
|
TrackingMiddleware.__init__ = _init_TrackingMiddleware
|
|
|
|
# IBlueprint
|
|
|
|
def get_blueprint(self):
|
|
return views.get_blueprints()
|
|
|
|
# IClick
|
|
|
|
# def get_commands(self):
|
|
# return cli.get_commands()
|
|
|
|
# ITemplateHelpers
|
|
|
|
def get_helpers(self):
|
|
return helpers.get_helpers()
|
|
|
|
# IValidators
|
|
|
|
def get_validators(self):
|
|
return validators.get_validators()
|
|
|