2023-09-21 17:01:55 +02:00
# encoding: utf-8
from logging import getLogger
import ckan . plugins as plugins
from ckanext . d4science_theme import helpers
import ckan . plugins . toolkit as toolkit
import ckan . lib . dictization . model_save as model_save
import ckan . model as model
import ckan . lib . helpers as h
import sqlalchemy as sa
from ckan . controllers . home import HomeController
from ckanext . d4science_theme . controllers . organization import OrganizationVREController
from ckanext . d4science_theme . controllers . home import d4SHomeController
from ckan . config . middleware . common_middleware import TrackingMiddleware
from ckan . common import session
from ckan . plugins import IRoutes
from ckan . common import (
g
)
# Created by Francesco Mangiacrapa
# francesco.mangiacrapa@isti.cnr.it
# ISTI-CNR Pisa (ITALY)
log = getLogger ( __name__ )
d4s_ctg_namespaces_controller = None
def remove_check_replicated_custom_key ( schema ) :
if schema is not None :
schema . pop ( ' __before ' , None )
return schema
#CREATED BY FRANCESCO MANGIACRAPA FOR OVERRIDING THE package_extras_save FROM dictization.model_save.py
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 )
if extra_dicts is None and allow_partial_update :
return
model = context [ " model " ]
session = context [ " session " ]
#ADDED BY FRANCESCO MANGIACRAPA
log . debug ( " extra_dicts: " + unicode ( str ( extra_dicts ) ) . encode ( ' utf-8 ' ) )
#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 )
#ADDED BY FRANCESCO MANGIACRAPA
#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: " + unicode ( extra_dict [ " key " ] ) . encode ( ' utf-8 ' ) )
#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 " ] )
#ADDED BY FRANCESCO MANGIACRAPA
log . debug ( " new_extras: " + unicode ( str ( new_extras ) ) . encode ( ' utf-8 ' ) )
#print "new_extras: "+str(new_extras)
#new
for key in set ( new_extras . keys ( ) ) - set ( old_extras . keys ( ) ) :
state = ' active '
log . debug ( " adding key: " + unicode ( key ) . encode ( ' utf-8 ' ) )
#print "adding key: "+str(key)
extra_lst = new_extras [ key ]
for extra in extra_lst :
extra = model . PackageExtra ( state = state , key = key , value = extra )
session . add ( extra )
extras_list . append ( extra )
#deleted
for key in set ( old_extras . keys ( ) ) - set ( new_extras . keys ( ) ) :
log . debug ( " deleting key: " + unicode ( key ) . encode ( ' utf-8 ' ) )
#print "deleting key: "+str(key)
extra_lst = extras [ key ]
for extra in extra_lst :
state = ' deleted '
extra . state = state
extras_list . remove ( extra )
#changed
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: " + unicode ( value ) . encode ( ' utf-8 ' ) + " , new_occur: " + unicode ( new_occur ) . encode ( ' utf-8 ' ) + " , old_occur: " + unicode ( old_occur ) . encode ( ' utf-8 ' ) )
#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: " + unicode ( value ) . encode ( ' utf-8 ' ) + " , 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 = state
session . add ( extra )
#print "extra updated: "+str(extra)
log . debug ( " extra updated: " + unicode ( extra ) . encode ( ' utf-8 ' ) )
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: " + unicode ( value ) . encode ( ' utf-8 ' ) + " , is present into new list, adding it to old list " )
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: " + unicode ( old_extras [ key ] ) . encode ( ' utf-8 ' ) )
#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: " + unicode ( value ) . encode ( ' utf-8 ' ) + " , is not present into new list, removing " + unicode ( 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: " + unicode ( extra . value ) . encode ( ' utf-8 ' ) )
#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: " + unicode ( extra . value ) . encode ( ' utf-8 ' ) )
state = ' active '
extra . state = state
session . add ( extra )
else :
#print "extra new value: "+str(value)
log . debug ( " extra new value: " + unicode ( value ) . encode ( ' utf-8 ' ) )
state = ' active '
extra = model . PackageExtra ( state = state , key = key , value = value )
extra . state = state
session . add ( extra )
extras_list . append ( extra )
#for each value of old list
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: " + unicode ( extra ) . encode ( ' utf-8 ' ) )
state = ' deleted '
extra . state = state
#ADDED BY FRANCESCO MANGIACRAPA
def get_package_for_value ( list_package , value ) :
''' Returns a list of packages containing the value passed in input
'''
lst = [ ]
for x in list_package :
if x . value == value :
lst . append ( x )
else :
return lst
return lst
#OVERRIDING BASE SQL ALCHEMY ENGINE INSTANCE
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 )
class D4Science_ThemePlugin ( plugins . SingletonPlugin , toolkit . DefaultDatasetForm ) :
plugins . implements ( plugins . IConfigurer )
plugins . implements ( plugins . IDatasetForm )
plugins . implements ( plugins . ITemplateHelpers )
plugins . implements ( plugins . IFacets )
plugins . implements ( IRoutes , inherit = True )
# IConfigurer
def update_config ( self , config_ ) :
# Add this plugin's templates dir to CKAN's extra_template_paths, so
# that CKAN will use this plugin's custom templates.
toolkit . add_template_directory ( config_ , ' templates ' )
# Add this plugin's public dir to CKAN's extra_public_paths, so
# that CKAN will use this plugin's custom static files.
toolkit . add_public_directory ( config_ , ' public ' )
# Register this plugin's fanstatic directory with CKAN.
# Here, 'fanstatic' is the path to the fanstatic directory
# (relative to this plugin.py file), and 'example_theme' is the name
# that we'll use to refer to this fanstatic directory from CKAN
# templates.
toolkit . add_resource ( ' fanstatic ' , ' d4science_theme ' )
#IDatasetForm
def create_package_schema ( self ) :
# let's grab the default schema in our plugin
schema = super ( D4Science_ThemePlugin , self ) . create_package_schema ( )
schema = remove_check_replicated_custom_key ( schema )
#d.package_dict_save = _package_dict_save
return schema
#IDatasetForm
def update_package_schema ( self ) :
schema = super ( D4Science_ThemePlugin , self ) . update_package_schema ( )
schema = remove_check_replicated_custom_key ( schema )
return schema
#IDatasetForm
def show_package_schema ( self ) :
schema = super ( D4Science_ThemePlugin , self ) . show_package_schema ( )
schema = remove_check_replicated_custom_key ( 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
#IDatasetForm
def package_types ( self ) :
# This plugin doesn't handle any special package types, it just
# registers itself as the default (above).
return [ ]
#ITemplateHelpers
def get_helpers ( self ) :
log . info ( " get_helpers called... " )
''' Register functions as a template
helper function .
'''
# Template helper function names should begin with the name of the
# extension they belong to, to avoid clashing with functions from
# other extensions.
return {
' d4science_theme_get_user_role_for_group_or_org ' : helpers . get_user_role_for_group_or_org ,
' d4science_theme_get_parents_for_group ' : helpers . get_parents_for_group ,
' get_header_param ' : helpers . get_header_param ,
' get_request_param ' : helpers . get_request_param ,
' get_cookie_value ' : helpers . get_cookie_value ,
' d4science_theme_markdown_extract_html ' : helpers . markdown_extract_html ,
' d4science_theme_get_systemtype_value_from_extras ' : helpers . get_systemtype_value_from_extras ,
' d4science_theme_get_systemtype_field_dict_from_session ' : helpers . get_systemtype_field_dict_from_session ,
' d4science_theme_get_namespace_separator_from_session ' : helpers . get_namespace_separator_from_session ,
' d4science_theme_get_extras ' : helpers . get_extras ,
' d4science_theme_count_facet_items_dict ' : helpers . count_facet_items_dict ,
' d4science_theme_purge_namespace_to_facet ' : helpers . purge_namespace_to_fieldname ,
' d4science_get_color_for_type ' : helpers . get_color_for_type ,
' d4science_get_d4s_namespace_controller ' : helpers . get_d4s_namespace_controller ,
' d4science_get_extras_indexed_for_namespaces ' : helpers . get_extras_indexed_for_namespaces ,
' d4science_get_namespaces_dict ' : helpers . get_namespaces_dict ,
' d4science_get_extra_for_category ' : helpers . get_extra_for_category ,
' d4science_get_ordered_dictionary ' : helpers . ordered_dictionary ,
' d4science_get_qrcode_for_url ' : helpers . qrcode_for_url ,
' d4science_get_list_of_organizations ' : helpers . get_list_of_organizations ,
' d4science_get_image_display_for_group ' : helpers . get_image_display_for_group ,
' d4science_get_list_of_groups ' : helpers . get_list_of_groups ,
' d4science_get_browse_info_for_organisations_or_groups ' : helpers . get_browse_info_for_organisations_or_groups ,
' d4science_get_user_info ' : helpers . get_user_info ,
' d4science_get_url_to_icon_for_ckan_entity ' : helpers . get_url_to_icon_for_ckan_entity ,
' d4science_get_ckan_translate_for ' : helpers . get_ckan_translate_for ,
' d4science_get_location_to_bboxes ' : helpers . get_location_to_bboxes ,
' d4science_get_content_moderator_system_placeholder ' : helpers . get_content_moderator_system_placeholder ,
}
#Overriding package_extras_save method
model_save . package_extras_save = _package_extras_save
#Overriding index home controller
d4sHC = d4SHomeController ( )
HomeController . index = d4sHC . index
#OVERRIDING BASE SQL ALCHEMY ENGINE INSTANCE
TrackingMiddleware . __init__ = _init_TrackingMiddleware
global d4s_ctg_namespaces_controller
#if d4s_ctg_namespaces_controller is None:
# log.info("d4s_ctg_namespaces_controller instancing...")
# d4s_ctg_namespaces_controller = helpers.get_d4s_namespace_controller()
# log.info("d4s_ctg_namespaces_controller instancied %s" % d4s_ctg_namespaces_controller)
#IFacets
def dataset_facets ( self , facets_dict , package_type ) :
facets_dict = self . _update_facets ( facets_dict )
return facets_dict
def group_facets ( self , facets_dict , group_type , package_type ) :
facets_dict = self . _update_facets ( facets_dict )
return facets_dict
def organization_facets ( self , facets_dict , organization_type , package_type ) :
facets_dict = self . _update_facets ( facets_dict )
return facets_dict
def _update_facets ( self , facets_dict ) :
''' Add ' metadatatype ' to facets if not already present. '''
log . debug ( " facets_dict: " )
log . debug ( ' , ' . join ( facets_dict ) )
metadatatype = helpers . get_systemtype_field_dict_from_session ( )
''' Adding system:type '''
facet_title = helpers . purge_namespace_to_fieldname ( str ( metadatatype [ ' id ' ] ) )
facet_title = plugins . toolkit . _ ( facet_title . capitalize ( ) + ' s ' )
facets_dict = self . _add_or_update_facet ( metadatatype [ ' name ' ] , facet_title , facets_dict )
log . info ( " site_url is: " + g . site_url )
#ADD IT IN THE CUSTOMIZATION?
if g . site_url :
dev_sites = [ ' https://ckan-d-d4s.d4science.org ' ]
2024-07-01 10:55:57 +02:00
#GRSF Catalogues. 'Status of the Record' must be distributed everywhere, see #23398
grsf_sites = [ ' https://ckan-grsf-admin2.d4science.org ' , ' https://ckan-grsf.pre.d4science.org ' , ' https://ckan-grsf.d4science.org ' , ' https://ckan-grsf-pre.d4science.org ' ]
2023-09-21 17:01:55 +02:00
sbd_sites = [ ' https://ckan.sobigdata.d4science.net ' , ' https://ckan-sobigdata.d4science.org ' ,
' https://ckan-sobigdata2.d4science.org ' ]
if g . site_url in dev_sites :
''' Adding Status of the GRSF record '''
facets_dict = self . _add_or_update_facet ( " StatusoftheRecord " , " Status of the Record " , facets_dict ,
display_after_facet = ' groups ' )
2024-07-01 10:55:57 +02:00
facets_dict = self . _add_or_update_facet ( " Anno " , " Anno " , facets_dict ,
display_after_facet = ' groups ' )
2023-09-21 17:01:55 +02:00
elif g . site_url in grsf_sites :
''' Adding Status of the GRSF record '''
# facets_dict = self._add_or_update_facet("StatusoftheGRSFrecord", "Status of the GRSF record", facets_dict, display_after_facet='groups')
# Fixing #23348
facets_dict = self . _add_or_update_facet ( " StatusoftheRecord " , " Status of the Record " , facets_dict ,
display_after_facet = ' groups ' )
elif g . site_url in sbd_sites :
''' Adding the field Availability '''
facets_dict = self . _add_or_update_facet ( " Availability " , " Availability " , facets_dict ,
display_after_facet = ' groups ' )
return facets_dict
def before_map ( self , map ) :
""" This IRoutes implementation overrides the standard
` ` / user / register ` ` behaviour with a custom controller . You
might instead use it to provide a completely new page , for
example .
Note that we have also provided a custom register form
template at ` ` theme / templates / user / register . html ` ` .
"""
# Hook in our custom user controller at the points of creation
# and edition.
#
#map.connect('/type', controller='ckanext.d4science_theme.controllers.type::d4STypeController', action='index')
map . connect ( ' /type ' , controller = ' ckanext.d4science_theme.controllers.systemtype:d4STypeController ' , action = ' index ' )
''' Added by Francesco Mangiacrapa, see: #8964 '''
organization_vre = OrganizationVREController ( )
map . connect ( ' /organization_vre ' , controller = ' ckanext.d4science_theme.controllers.organization:OrganizationVREController ' , action = ' index ' )
map . connect ( ' /organization_vre/ {id} ' , controller = ' ckanext.d4science_theme.controllers.organization:OrganizationVREController ' , action = ' read ' )
map . redirect ( ' /types ' , " /type " )
return map
def _add_or_update_facet ( self , facet_key , facet_value , facets_dict , display_after_facet = ' organization ' ) :
#Updating ordering of facets_dict OrderedDict
if str ( facet_key ) not in facets_dict :
new_orderded_facets_dict = facets_dict . __class__ ( )
for key , value in facets_dict . items ( ) :
new_orderded_facets_dict [ key ] = value
# #the field 'metadatatype' will be inserted after following key
if key == display_after_facet :
new_orderded_facets_dict [ facet_key ] = facet_value
facets_dict . clear ( )
facets_dict . update ( new_orderded_facets_dict )
log . debug ( " facets_dict ordered: " )
log . debug ( ' , ' . join ( facets_dict ) )
return facets_dict