Contribution Drupal : bluedrop.fr libère le module Drupal HAL - Connecteur aux Archives Ouvertes

Mercredi 22 Janvier 2020

À l'occasion de notre collaboration avec le SESSTIM (laboratoire de Sciences économiques et sociales de la santé & traitement de l'information médicale), nous avons mis à jour libéré un connecteur Drupal au service de stockage et de diffusions HAL. Voici un retour sur ce développement particulier qui doit pouvoir servir à de nombreux projets universitaires.

Module Drupal HAL - Photo de la bibliothèque Universitaire de la Timone

HAL publications c'est quoi ?

L'archive ouverte pluridisciplinaire HAL (Hyper Articles en Ligne) permet de déposer et de diffuser des articles scientifiques de recherches, publiés ou non, et des thèses émanants des établissements d'enseignement et de recherches français ou étrangers, ainsi que de laboratoires publics ou privés.

Cette plateforme en ligne a été développée en 2001 par le Centre pour la Communication Scientifique Direct (CCSD) du CNRS, et plus particulièrement, à l'initiative du physicien français Franck Laloë.

Cette plateforme expose la plus grande base de données de recherche émanant d'institutions et de chercheurs francophones à travers le monde. En 2019, elle contenait environ 1.900.000 références et 600.000 documents scientifiques.

Le rôle et son utilisation par la communauté scientifique

HAL Publication propose une offre Portail. Ce service est spécifiquement dédié aux institutions et établissements qui souhaitent valoriser les publications et données scientifiques de leurs chercheurs et enseignants. Il s'agit d'un réservoir destiné à stocker et diffuser les communications / publications scientifiques. Elles sont généralement déposées par leur auteur et diffusées au grand public sans contrainte. L'utilisation de protocoles communs, en particulier l'Open Archives Initiative Protocol for Metadata Harvesting (OAI-PMH), permet aux différentes archives ouvertes de rendre leur contenu interrogeable et rend possible leur agrégation par des moteurs de recherches spécialisés (par l'intérmédiaire de métadonnées).

HAL publication dispose également d'une API (Application Programming Interface). Elle regroupe un ensemble particulier de règles ("code") et de spécifications que les logiciels peuvent suivre pour communiquer entre eux. Il est ainsi envisageable de disposer des ressources et de les trier. 

Les Archives ouvertes HAL exposent en outre un identifiant unique, qui permet à un utilisateur authentifié, reconnu comme auteur dans HAL, de regrouper toutes ses publications, quelles que soient les différentes formes sous lesquelles son nom a pu être saisi. Il s'agit de l'idHAL. L'idHAL est associé au profil, et donc mis à jour en même temps que ce dernier. Il est également utilisé en tant que CV.

Le connecteur Drupal

Contexte avec le SESSTIM

L'agence bluedrop.fr a repris, courant 2019, la maintenance du site Drupal du Laboratoire SESSTIM de la Timone à Marseille. L’Unité Mixte de Recherche 1252 SESSTIM Sciences Economiques et Sociales de la Santé & Traitement de l'Information Médicale (Inserm/ IRD/ Aix Marseille Université) a été créée au 1er janvier 2012. Il s’efforce de produire une recherche d’excellence, pluridisciplinaire et interdisciplinaire, en sciences humaines et sociale et en santé publique pouvant conduire à des changements dans les différents champs de la médecine prédictive, personnalisée, préemptive et participative. 

Le SESSTIM souhaitait qu'il soit possible d'afficher les profils des chercheurs participants et leurs publications de trois manières différentes : 

  • Par chercheur dans un onglet de son profil ;
  • Par tous les chercheurs d'une équipe dans un onglet des pages ;
  • Tous les chercheurs du SESSTIM dans une même page.

La solution technique auparavant utilisée était imporfaite. Elle utilisait le module Drupal Biblio d'une part (pour les 2 premières fonctionnalités), mais sans être connecté aux Archives ouvertes HAL. c'est en place mais imparfait. Deux outils étaient utilisés pour mettre en place ces demandes : le module biblio de Drupal (pour les deux premiers critères), mais sans être connecté à HAL . Elle proposait d'autre part une iframe interrogeant les idHAL des chercheur·euse·s concerné·e·s. 

Il convenait par conséquent de rendre possible l'utilisation de idHAL programmatiquement pour rendre possible l'affichage des ressources par chercheur·euse et par équipes. 

Reprise du module et correction

Pour répondre à ce besoin, nous avons choisi d'améliorer le module Drupal développé par Mathieu Dandonneau à AMU (Aix-Marseille Université). 

Les corrections ont porté sur les fonctionnalités suivantes :

  • La possibilité d'utiliser un idHal "dynamique" dont la valeur serait récupérée sur un champ du profil utilisateur. Cela permet d'afficher dans un onglet distinct "Publication HAL", présent sur le profil de l'utilisateur, les publications déposées dans les archives ouvertes.
  • La possibilité d'utiliser une liste d'idHal récupérée dynamiquement sur tous les profils des utilisateurs, renseignant ainsi à quelle équipe de recherche ils appartiennent. Cela permet d'afficher les publications HAL des 3 équipes de recherche sur 3 pages ou blocs différents, sans avoir à renseigner "à la main" les idHAL des chercheurs des équipes concernées (les publications sont ainsi accessibles sans intervention en cas de mouvements dans l'équipe ou de mise à jour par un utilisateur isolé de son idHAL). 

Contribution Drupal 7 et Drupal 8

Le module est désormais disponible sur drupal.org. Pour utiliser le module, il convient d'y paramétrer quelques configurations :

  • Le champ "identifiant HAL" de l'utilisateur·rice ;
  • Le champ "nom" de l'utilisateur·rice ;
  • Le champ "prénom" de l'utilisateur·rice ;
  • La liste de sélection des équipes auxquelles l'utilisateur·rice appartient ;
  • La librairie Chosen JS est intégrée au module. Si la librairie est déjà installée sur votre site, il convient de le notifier dans le fichier template.

Fonctionnalités présentes sur cet mise à jour du module :

  • Choix entre plusieurs portails/dépôts de publications d'où collecter les publications ;
  • Choix d'ajout d'un onglet de publications dans la page de l'utilisateur·rice dans le site ;
  • Collecte des publications selon les utilisateur·rice·s du site ;
  • Collecte des publications des équipes sélectionnées ;
  • Filtrage des publications par mot-clés ;
  • Filtrage des publications par auteur·e·(s) ;
  • Filtrage des publications par année(s) ;
  • Affichage des publications selon le standard Vancouver ;
  • Export en format BibTex d'une ou plusieurs publications ;
  • Export en format RTF d'une ou plusieurs publications.

Pour ajouter un nouveau bloc HAL :

  • Chaque bloc HAL représentant une "instance", il s'agit d'ajouter une nouvelle instance pour chaque nouveau bloc HAL - Structure > Blocs > Instances > Add instance
  • Donner un titre à l'instance dans "instance title" et choisissez Publications HAL dans la liste déroulante "Bloc type".
  • Enregistrez.
  • Configurez votre bloc en allant dans - Structure – Blocs.
  • Choisir entre afficher les filtres (ou pas).
  • Choisir entre une liste de séléction simple ou multiple pour les auteurs.
  • Choisir entre une liste de séléction simple ou multiple pour les années.
  • Choisir les équipes dont les publications doivent être affichées (ne rien choisir pour afficher les publications de toutes les équipes).

Pour afficher les publications par auteur·e·(s) :

  • Cocher le checkbox "Afficher la tabulation publications pour les utilisateurs" dans le formulaire de configuration du module. /admin/hal.
  • Remplir le champ "Titre des publications dans la page utilisateur" comme titre pour l'onglet dans la page utilisateur.

Ressources : 

Exemple de code - Get result from API

// GET RESULTS FROM API.
      $data = _amu_hal_api_request($url);
      $theme = $config->display_mode;
      $block['subject'] = t('publications');
      $block['content'] = theme($theme, [
        'docs' => $data->response->docs,
        'filters' => $filters,
        'display' => 'teaser',
        'suffix' => $instanceSuffix,
        'config' => $config,
      // 'results' => $results,
      // uncomment these to have number of results in template.
      ]);
      break;
  }
  return $block;
}
 

Exemple de code - HAL Publications block instance

/**
 * Retrieve configuration for the HAL Publications block instance.
 *
 * @param string $instanceSuffix
 *   : HAL Publications block instance number.
 *
 * @return object
 *   : Block configuration.
 */
function _amu_hal_get_configuration($instanceSuffix) {
  $config = new stdClass();
  // Global module.
  $config->retrieval_method_select = variable_get('retrieval_method_select' . $instanceSuffix);
  $config->display_mode = variable_get('display_mode' . $instanceSuffix);
  $config->filtres = variable_get('filtres' . $instanceSuffix);
  $config->multiple_authors = variable_get('multiple_authors' . $instanceSuffix);
  $config->multiple_years = variable_get('multiple_years' . $instanceSuffix);
  $config->choices = variable_get('choices' . $instanceSuffix);
  return $config;
}

Exemple de code - Publications d'un auteur

/**
 * Gets a specific author publications.
 *
 * @param int $arg
 *   : UID.
 *
 * @return array|mixed
 *   : Render array.
 */
function _amu_hal_author_pub($arg) {
  // Retrieveing the HAL ID field machine name from configuration.
  $hal_id_machine_name = variable_get('hal_id_machine_name');
  // Hal ID table name.
  $hal_id_table = "field_data_$hal_id_machine_name";
  // HAL ID column name.
  $hal_id_column = $hal_id_machine_name . "_value";
  // Query to retrieve a HAL ID from UID.
  $hal_id_query = db_query("SELECT $hal_id_column FROM $hal_id_table WHERE entity_id = $arg");
  $hal_id_results = $hal_id_query->fetchAll();
  if ($hal_id_results) {
    $hal_id = $hal_id_results[0]->$hal_id_column;
    $portal = variable_get('portal', '');
    if ($portal) {
      $portal = "$portal/";
    }
    $url = variable_get('amu_hal_url_ws') . 'search/' . $portal . '?fq=authIdHal_s:' . $hal_id . '&rows=2000&group.field=producedDateY_i&sort=producedDate_tdate%20desc&fl=authLastNameFirstName_s,title_s,journalTitle_s,producedDateY_i,volume_s,issue_s,page_s,publisherLink_s,halId_s,uri_s,files_s,journalSherpaCondition_s,label_xml';
    $data = _amu_hal_api_request($url);
    $docs = $data->response->docs;
  }
  // Change page title.
  drupal_set_title(t("Publications"));
  return theme('vancouver_no_et_al', [
    'docs' => $docs,
    'display' => 'teaser',
  ]);
}

Exemple de code - IDS

/**
 * Retrieve HAL IDS.
 *
 * @param array $team_ids
 *   : Team IDs.
 * @param bool $plusNames
 *   : True: returns authors HAL IDs and names.
 *
 * @return array
 *   : HAL IDs and names if $plusNames is TRUE.
 */
function _amu_hal_ids(array $team_ids = [], $plusNames = FALSE) {
  // Retrieveing the HAL ID field machine name from configuration.
  $hal_id_machine_name = variable_get('hal_id_machine_name');
  // Hal ID table name.
  $hal_id_table = "field_data_$hal_id_machine_name";
  // HAL ID column name.
  $hal_id_column = $hal_id_machine_name . "_value";
  // Array to save the HAL IDs.
  $filter_ids = array();
  // Retrieveing the teams field machine name from configuration.
  $team_machine_name = variable_get('team_machine_name');
  // Teams table name.
  $team_table = "field_data_$team_machine_name";
  // Retrieveing the user's first name field machine name from configuration.
  $firstname_machine_name = variable_get('field_prenom_machine_name');
  // Ther user's first name table name.
  $firstname_table = "field_data_$firstname_machine_name";
  // Ther user's first name column name.
  $firstname_column = $firstname_machine_name . "_value";
  // Retrieveing the user's last name field machine name from configuration.
  $lastname_machine_name = variable_get('field_nom_machine_name');
  // Ther user's last name table name.
  $lastname_table = "field_data_$lastname_machine_name";
  // Ther user's last name column name.
  $lastname_column = $lastname_machine_name . "_value";
  // Filtering HAL IDs by Team IDs if $team_ids is not empty.
  if (isset($team_ids) && $team_ids) {
    // Teams column name.
    $team_column = $team_machine_name . "_target_id";
    $team_ids_list = implode(',', $team_ids);
    $filtered_query = db_query("SELECT DISTINCT entity_id FROM $team_table WHERE $team_column IN ($team_ids_list)");
  }
  else {
    $filtered_query = db_query("SELECT DISTINCT entity_id FROM $team_table");
  }
  $filtered_records = $filtered_query->fetchAll();
  foreach ($filtered_records as $row) {
    $filter_ids[] = $row->entity_id;
  }
  if (isset($filter_ids) && $filter_ids) {
    $filter = implode(',', $filter_ids);
    $query = db_query("SELECT $hal_id_column, entity_id FROM $hal_id_table WHERE $hal_id_column <> '' AND entity_id IN ($filter) ");
  }
  else {
    $query = db_query("SELECT $hal_id_column, entity_id FROM $hal_id_table WHERE $hal_id_column <> '' ");
  }
  $records = $query->fetchAll();
  $all_ids = array();
  foreach ($records as $record) {
    if ($plusNames) {
      $namequery = db_query("SELECT $firstname_table.$firstname_column, $lastname_table.$lastname_column FROM $firstname_table, $lastname_table WHERE $firstname_table.entity_id = $lastname_table.entity_id AND $firstname_table.entity_id = $record->entity_id");
      $namequeryResult = $namequery->fetchAll()[0];
      $first_name = $namequeryResult->$firstname_column;
      $last_name = $namequeryResult->$lastname_column;
      $name = $last_name . " " . $first_name;
      $all_ids[str_replace(" ", "", $record->$hal_id_column)] = $name;
    }
    else {
      $all_ids[$record->entity_id] = str_replace(" ", "", $record->$hal_id_column);
    }
  }
  asort($all_ids);
  return $all_ids;
}