From 4e411e726bcde03223fe3b8d1cc3fdb4e8ed8c71 Mon Sep 17 00:00:00 2001 From: Laurent Laffont <llaffont@afi-sa.fr> Date: Tue, 16 Jul 2019 10:30:42 +0200 Subject: [PATCH] Add authors widget --- FEATURES/95222 | 10 + VERSIONS_WIP/95222 | 1 + .../admin/controllers/AjaxController.php | 3 +- .../admin/controllers/WidgetController.php | 17 + cosmogramme/sql/patch/patch_376.php | 6 + library/Class/Auteur.php | 62 --- library/Class/CodifAuteur.php | 29 +- library/Class/CodifAuteur/Description.php | 63 +-- library/Class/CodifAuteurFonction.php | 25 +- library/Class/Notice.php | 23 +- library/Class/Notice/Facette.php | 18 + library/Class/Systeme/ModulesAccueil.php | 3 +- .../Class/Systeme/ModulesAccueil/Authors.php | 57 ++ .../Form/Configuration/Widget/Authors.php | 80 +++ .../ZendAfi/View/Helper/Accueil/Authors.php | 203 +++++++ library/ZendAfi/View/Helper/Accueil/Base.php | 5 + .../ZendAfi/View/Helper/Accueil/Kiosque.php | 22 +- .../View/Helper/Admin/TagListeSuggestion.php | 1 + .../View/Helper/RenderAuthorMetadata.php | 16 +- public/opac/css/global.css | 7 +- public/opac/js/widget_templates/authors.jpg | Bin 0 -> 32175 bytes .../js/widget_templates/widget_templates.json | 9 +- tests/db/UpgradeDBTest.php | 18 +- tests/scenarios/AuthorPage/AuthorPageTest.php | 13 +- .../scenarios/AuthorPage/AuthorWidgetTest.php | 501 ++++++++++++++++++ tests/scenarios/AuthorPage/notre_dame.marc | 1 + 26 files changed, 1053 insertions(+), 140 deletions(-) create mode 100644 FEATURES/95222 create mode 100644 VERSIONS_WIP/95222 create mode 100644 cosmogramme/sql/patch/patch_376.php delete mode 100644 library/Class/Auteur.php create mode 100644 library/Class/Systeme/ModulesAccueil/Authors.php create mode 100644 library/ZendAfi/Form/Configuration/Widget/Authors.php create mode 100644 library/ZendAfi/View/Helper/Accueil/Authors.php create mode 100644 public/opac/js/widget_templates/authors.jpg create mode 100644 tests/scenarios/AuthorPage/AuthorWidgetTest.php create mode 100644 tests/scenarios/AuthorPage/notre_dame.marc diff --git a/FEATURES/95222 b/FEATURES/95222 new file mode 100644 index 00000000000..fb0b6c9913f --- /dev/null +++ b/FEATURES/95222 @@ -0,0 +1,10 @@ + '95222' => + ['Label' => $this->_('Boite Auteurs'), + 'Desc' => $this->_('Permet d\'afficher dynamiquement des auteurs à partir d\'une sélection de notices (domaines, paniers)'), + 'Image' => '', + 'Video' => 'https://www.youtube.com/watch?v=aK4Dz3LVOIo', + 'Category' => 'Recherche', + 'Right' => function($feature_description, $user) {return true;}, + 'Wiki' => 'http://wiki.bokeh-library-portal.org/index.php?title=Boite_auteurs', + 'Test' => '', + 'Date' => '2019-07-18'], \ No newline at end of file diff --git a/VERSIONS_WIP/95222 b/VERSIONS_WIP/95222 new file mode 100644 index 00000000000..8cd4aaec3ba --- /dev/null +++ b/VERSIONS_WIP/95222 @@ -0,0 +1 @@ + - ticket #95222 : Ajout de la boite Auteurs \ No newline at end of file diff --git a/application/modules/admin/controllers/AjaxController.php b/application/modules/admin/controllers/AjaxController.php index 983c3ff7a9e..ce63c3a2215 100644 --- a/application/modules/admin/controllers/AjaxController.php +++ b/application/modules/admin/controllers/AjaxController.php @@ -53,7 +53,8 @@ class Admin_AjaxController extends ZendAfi_Controller_Action { protected function getAuthorityFor($code) { - $authorities = ['auteur' => new Class_Auteur(), + $authorities = ['auteur' => new Class_CodifAuteur(), + 'responsibility' => new Class_CodifAuteurFonction(), 'matiere' => new Class_Matiere(), 'interet' => new Class_CodifCentreInteret(), 'dewey' => new Class_CodifDewey(), diff --git a/application/modules/admin/controllers/WidgetController.php b/application/modules/admin/controllers/WidgetController.php index 5ca52152035..55058fe4d15 100644 --- a/application/modules/admin/controllers/WidgetController.php +++ b/application/modules/admin/controllers/WidgetController.php @@ -305,4 +305,21 @@ class Admin_WidgetController extends ZendAfi_Controller_Action { public function formProvider($widget) { return call_user_func_array([$widget->getForm(), 'newWith'], [$widget->forForm()]); } + + + public function widgetActionAction() { + $id_module = $this->_getParam('id_module'); + + if (Class_Profil::getCurrentProfil()->getId() !== (int)$this->_getParam('id_profil')) + throw new Zend_Controller_Action_Exception($this->view->_('Profil inexistant'), 404); + + if (!$config = Class_Profil::getCurrentProfil()->getLocalModuleAccueilConfig($id_module)) + throw new Zend_Controller_Action_Exception($this->view->_('Boite inexistante'), 404); + + $helper = ZendAfi_View_Helper_Accueil_Base::getModuleHelperFromParams($id_module, + $config, + $this->view); + $helper->performAction($this->_getParam('named')); + $this->_redirectToReferer(); + } } \ No newline at end of file diff --git a/cosmogramme/sql/patch/patch_376.php b/cosmogramme/sql/patch/patch_376.php new file mode 100644 index 00000000000..823c2cd028a --- /dev/null +++ b/cosmogramme/sql/patch/patch_376.php @@ -0,0 +1,6 @@ +<?php +$adapter = Zend_Db_Table_Abstract::getDefaultAdapter(); +try { + $adapter->query('alter table codif_auteur add column thumbnail_url varchar(255)'); + +} catch(Exception $e) {} diff --git a/library/Class/Auteur.php b/library/Class/Auteur.php deleted file mode 100644 index 4cc4bc90f94..00000000000 --- a/library/Class/Auteur.php +++ /dev/null @@ -1,62 +0,0 @@ -<?PHP -/** - * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved. - * - * BOKEH 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. - * - * There are special exceptions to the terms and conditions of the AGPL as it - * is applied to this software (see README file). - * - * BOKEH 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 BOKEH; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -//////////////////////////////////////////////////////////////////////////////////////// -// OPAC 3 :AUTEURS -/////////////////////////////////////////////////////////////////////////////////////// - -class Class_Auteur -{ - -// ---------------------------------------------------------------- -// Rend une liste pour un champ suggestion -// ---------------------------------------------------------------- - public function getListeSuggestion($recherche,$mode,$limite_resultat) - { - // Lancer la recherche - $ix=new Class_Indexation(); - $code_alpha=$ix->alphaMaj($recherche); - $code_alpha=str_replace(" ","x",$code_alpha); - if($mode=="1") $req="select id_auteur,libelle from codif_auteur where formes like'".$code_alpha."%' order by FORMES limit ".$limite_resultat; - - $resultat=fetchAll($req); - - // Mettre l'indice et le libelle - if(!$resultat) return false; - foreach($resultat as $enreg) - { - $liste[]=array($enreg["id_auteur"],$enreg["libelle"]); - } - - return $liste; - } - - -// ---------------------------------------------------------------- -// Rend prénom et nom -// ---------------------------------------------------------------- - static function getLibelle($id_auteur) - { - $libelle = fetchEnreg("select libelle from codif_auteur where id_auteur='$id_auteur'"); - return $libelle; - } -} - -?> \ No newline at end of file diff --git a/library/Class/CodifAuteur.php b/library/Class/CodifAuteur.php index cf45e5818da..1ae9b079875 100644 --- a/library/Class/CodifAuteur.php +++ b/library/Class/CodifAuteur.php @@ -122,9 +122,36 @@ class Class_CodifAuteur extends Storm_Model_Abstract { 'wikidata_id' => '', 'youtube_channel_id' => '', 'isni' => '', - 'ark' => '']; + 'ark' => '', + 'thumbnail_url' => '']; public function getCategorie() { return; } + + + public function getListeSuggestion($recherche, $mode, $limite_resultat) { + $code_alpha = str_replace(' ', + 'x', + Class_Indexation::getInstance()->alphaMaj($recherche)); + + $authors = Class_CodifAuteur::getLoader() + ->findAllBy(['where' => 'formes like "' . $code_alpha . '%"', + 'order' => 'FORMES', + 'limit' => $limite_resultat]); + + return array_map(function($author) + { + return [$author->getId(), $author->getLibelle()]; + }, + $authors); + } + + + public function isThumbnailValid() { + return + (!empty($this->getThumbnailUrl())) + && + (false == strpos($this->getThumbnailUrl(), 'Defaut.svg')); + } } \ No newline at end of file diff --git a/library/Class/CodifAuteur/Description.php b/library/Class/CodifAuteur/Description.php index 1b72d9dbc1e..a916cf8659b 100644 --- a/library/Class/CodifAuteur/Description.php +++ b/library/Class/CodifAuteur/Description.php @@ -106,19 +106,9 @@ class Class_CodifAuteur_Description { if (!count($this->getRecords())) return ''; - $data = $this->_fetchBiography($this->_author, - $this->getRecords(), - $this->getAssociatedAuthors()); - - $author_attribs = array_intersect_key($data, ['wikidata_id' => '', - 'youtube_channel_id' => '', - 'ark' => '', - 'isni' => '']); - $this->_author - ->updateAttributes($author_attribs) - ->save(); + $data = $this->fetchBiography(); - if ($biography = $data['biographie']) { + if ($biography = $data->getbiographie()) { $biography = $this->_enrichBiographyWithRecords($biography, $this->getRecords(), $view); @@ -129,17 +119,19 @@ class Class_CodifAuteur_Description { } $thumbnail = ''; - if ($data['vignette']) + if ($this->_author->getThumbnailUrl()) $thumbnail = $view->tag('img', null, - ['src' => $data['vignette'], + ['src' => $this->_author->getThumbnailUrl(), 'alt' => $this->getLabel() . '. ' . $this->_('Source: Wikipedia')]); $update_button = $view->biographie_UpdateButton($this->getRecords()[0], $this->getLabel()); - $licence = $view->biographie_Licence($this->getLabel(), $data['source'], $data['url_source']); + $licence = $view->biographie_Licence($this->getLabel(), + $data->getsource(), + $data->geturl_source()); return $update_button . $thumbnail . $biography . $licence; } @@ -222,9 +214,23 @@ class Class_CodifAuteur_Description { public function fetchBiography() { - return new Class_Entity($this->_fetchBiography($this->_author, - $this->getRecords(), - $this->getAssociatedAuthors())); + $bio = new Class_Entity($this->_fetchBiography($this->_author, + $this->getRecords(), + $this->getAssociatedAuthors())); + + $author_attribs = array_intersect_key($bio->toArray(), + ['wikidata_id' => '', + 'youtube_channel_id' => '', + 'ark' => '', + 'isni' => '']); + if ($bio->getvignette()) + $author_attribs['thumbnail_url'] = $bio->getvignette(); + + $this->_author + ->updateAttributes($author_attribs) + ->save(); + + return $bio; } @@ -309,30 +315,19 @@ class Class_CodifAuteur_Description { public function renderThumbnailOn($view) { - $data = new Class_Entity($this->_fetchBiography($this->_author, - $this->getRecords(), - $this->getAssociatedAuthors())); - return $data->getvignette() + $this->fetchBiography(); + + return $this->_author->getThumbnailUrl() ? $view->tag('img', null, - ['src' => $data->getvignette(), + ['src' => $this->_author->getThumbnailUrl(), 'alt' => $this->getLabel() . '. ' . $this->_('Source: Wikipedia')]) : ''; } public function renderWikipediaOn($view) { - $data = new Class_Entity($this->_fetchBiography($this->_author, - $this->getRecords(), - $this->getAssociatedAuthors())); - - $author_attribs = array_intersect_key($data->toArray(), ['wikidata_id' => '', - 'youtube_channel_id' => '', - 'ark' => '', - 'isni' => '']); - $this->_author - ->updateAttributes($author_attribs) - ->save(); + $data = $this->fetchBiography(); if (!$biography = $data->getbiographie()) return ''; diff --git a/library/Class/CodifAuteurFonction.php b/library/Class/CodifAuteurFonction.php index 4ae6196f045..465bdcda6a6 100644 --- a/library/Class/CodifAuteurFonction.php +++ b/library/Class/CodifAuteurFonction.php @@ -16,7 +16,7 @@ * * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE * along with BOKEH; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ class Class_CodifAuteurFonctionLoader extends Storm_Model_Loader { @@ -24,12 +24,29 @@ class Class_CodifAuteurFonctionLoader extends Storm_Model_Loader { return array_map(function ($model) {return $model->getLibelle();}, Class_CodifAuteurFonction::findAllBy(['order' => 'libelle'])); } + } + + class Class_CodifAuteurFonction extends Storm_Model_Abstract { - protected $_table_name = 'codif_auteurs_fonctions'; - protected $_table_primary = 'id_fonction'; - protected $_loader_class = 'Class_CodifAuteurFonctionLoader'; + protected + $_table_name = 'codif_auteurs_fonctions', + $_table_primary = 'id_fonction', + $_loader_class = 'Class_CodifAuteurFonctionLoader'; + + + public function getListeSuggestion($recherche, $mode, $limite_resultat) { + $responsibilities = Class_CodifAuteurFonction::getLoader() + ->findAllBy(['where' => 'libelle like "' . $recherche .'%"', + 'order' => 'libelle']); + + return array_map(function($responsibility) + { + return [$responsibility->getId(), $responsibility->getLibelle()]; + }, + $responsibilities); + } } ?> \ No newline at end of file diff --git a/library/Class/Notice.php b/library/Class/Notice.php index a4ed9fa41db..e2383cb9266 100644 --- a/library/Class/Notice.php +++ b/library/Class/Notice.php @@ -1029,12 +1029,14 @@ class Class_Notice extends Storm_Model_Abstract { return $this->_auteur_principal; } + public function getFirstAuthor() { if (!$auteurs = $this->getAuteursUnimarc(true)) return ''; return $auteurs[0]; } + public function setAuteurPrincipal($auteur) { $this->_auteur_principal = $auteur; return $this; @@ -1047,7 +1049,6 @@ class Class_Notice extends Storm_Model_Abstract { public function getAuteursUnimarc($auteurPrincipal = false, $getFonction = false) { - $indexation = Class_Indexation::getInstance(); $auteurs = []; $zones = ['700', '710', '720', '730', '701', '702', '711', '712', '721', '722']; @@ -1226,7 +1227,9 @@ class Class_Notice extends Storm_Model_Abstract { return []; $label = trim($prenom . ' ' . $nom) . (($fonction) ? ' (' . $fonction . ')': ''); - return (new Class_Notice_FieldAuthor($codif_auteur))->setLabel($label); + return (new Class_Notice_FieldAuthor($codif_auteur)) + ->setLabel($label) + ->setFonction($fonction); } @@ -1628,21 +1631,7 @@ class Class_Notice extends Storm_Model_Abstract { public function getAvailableLibrariesFromFacet() { - $existing = array_filter( - Class_Notice_Facette::parseFacettesFromNoticeField($this->getFacettes()), - function($facet) { - return $facet->isAvailability(); - }); - - $values = array_unique( - array_filter( - array_map(function($facet) - { - return $facet->getValue(); - }, - $existing))); - - if(!$values) + if (!$values = Class_Notice_Facette::facetsValuesFromRecordFilteredBy($this, 'isAvailability')) return []; return Class_Bib::findAllBy(['id_site' => $values]); diff --git a/library/Class/Notice/Facette.php b/library/Class/Notice/Facette.php index 7935c67195d..ab1a48e33d3 100644 --- a/library/Class/Notice/Facette.php +++ b/library/Class/Notice/Facette.php @@ -37,6 +37,24 @@ class Class_Notice_Facette { } + public static function facetsValuesFromRecordFilteredBy($record, $filter_name) { + $existing = array_filter( + Class_Notice_Facette::parseFacettesFromNoticeField($record->getFacettes()), + function($facet) use ($filter_name){ + return call_user_func([$facet, $filter_name]); + }); + + $values = array_unique( + array_filter( + array_map(function($facet) + { + return $facet->getValue(); + }, + $existing))); + return $values; + } + + public static function extractCodeRubrique($cle) { return (Class_CodifThesaurus::CODE_FACETTE == ($code = $cle[0])) ? Class_CodifThesaurus::getLoader()->getFacetGroup($cle) diff --git a/library/Class/Systeme/ModulesAccueil.php b/library/Class/Systeme/ModulesAccueil.php index f710a0d5baf..9f09d4e6630 100644 --- a/library/Class/Systeme/ModulesAccueil.php +++ b/library/Class/Systeme/ModulesAccueil.php @@ -136,7 +136,8 @@ class Class_Systeme_ModulesAccueil extends Class_Systeme_ModulesAbstract { 'Panier', 'DomainBrowser', 'PremierChapitre', - 'Library']; + 'Library', + 'Authors']; foreach($defaults as $default) { $name = 'Class_Systeme_ModulesAccueil_' . $default; diff --git a/library/Class/Systeme/ModulesAccueil/Authors.php b/library/Class/Systeme/ModulesAccueil/Authors.php new file mode 100644 index 00000000000..8d8742866b4 --- /dev/null +++ b/library/Class/Systeme/ModulesAccueil/Authors.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH 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. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH 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 BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +class Class_Systeme_ModulesAccueil_Authors extends Class_Systeme_ModulesAccueil_Null { + const + CODE = 'AUTHORS', + AUTHORS_SELECTION_MODE_ALL = 'all', + AUTHORS_SELECTION_MODE_RESPONSIBILITIES = 'responsibilities', + AUTHORS_SELECTION_MODE_MAIN = 'main'; + + + protected + $_group = Class_Systeme_ModulesAccueil::GROUP_RECH, + $_isPhone = true; + + + public function __construct() { + $this->_libelle = $this->_('Boite auteurs'); + $this->_form = 'ZendAfi_Form_Configuration_Widget_Authors'; + $this->_defaultValues = ['titre' => $this->_('Sélection d\'auteurs'), + 'op_largeur_img' => 260, + 'authors_count' => 10, + 'authors_selection_mode' => static::AUTHORS_SELECTION_MODE_ALL]; + } + + + public function getAuthorsSelectionModeOptions() { + return [ + static::AUTHORS_SELECTION_MODE_ALL => $this->_('Tous les auteurs'), + static::AUTHORS_SELECTION_MODE_MAIN => $this->_('Auteurs principaux'), + static::AUTHORS_SELECTION_MODE_RESPONSIBILITIES => $this->_('Par responsabilité') + ]; + } + + + public function getDefaultAuthorsSelectionMode() { + return $this->_defaultValues['authors_selection_mode']; + } +} \ No newline at end of file diff --git a/library/ZendAfi/Form/Configuration/Widget/Authors.php b/library/ZendAfi/Form/Configuration/Widget/Authors.php new file mode 100644 index 00000000000..f664f2ce4ef --- /dev/null +++ b/library/ZendAfi/Form/Configuration/Widget/Authors.php @@ -0,0 +1,80 @@ +<?php +/** + * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH 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. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH 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 BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +class ZendAfi_Form_Configuration_Widget_Authors extends ZendAfi_Form_Configuration_Widget_Base { + public function init() { + parent::init(); + + Class_ScriptLoader::getInstance() + ->addJQueryReady('radioToggleVisibilityForElement("input[name=\'authors_selection_mode\']", + $("#responsibilities").closest("tr"), + ["responsibilities"]);'); + + $authors_module = new Class_Systeme_ModulesAccueil_Authors(); + + $this + ->addElement('domainePanier', + 'data_source') + ->addElement('number', + 'authors_count', + ['label' => $this->_('Nombre maximum d\'auteurs'), + 'min' => 1, + 'max' => 200]) + ->addElement('slider', + 'op_largeur_img', + ['label' => $this->_('Largeur des colonnes'), + 'min' => 100, + 'max' => 2000, + 'step' => 1]) + ->addElement('radio', + 'authors_selection_mode', + ['label' => $this->_('Auteurs sélectionnés'), + 'multiOptions' => $authors_module->getAuthorsSelectionModeOptions(), + 'value' => $authors_module->getDefaultAuthorsSelectionMode()]) + ->addElement('listeSuggestion', + 'responsibilities', + ['label' => $this->_('Responsabilité auteur'), + 'rubrique' => 'responsibility']) + + ->addToSelectionGroup(['data_source']) + + ->addToDisplaySettingsGroup(['authors_selection_mode', + 'responsibilities', + 'authors_count']) + + ->addToStyleGroup(['op_largeur_img']); + } + + + public function populate(array $datas) { + $this->customPopulate($datas); + return parent::populate($datas); + } + + + public function customPopulate($datas) { + $this + ->getElement('data_source') + ->setOptions(['IdItems' => isset($datas['id_panier']) ? $datas['id_panier'] : '', + 'IdCategories' => isset($datas['id_catalogue']) ? $datas['id_catalogue'] : '']); + return $this; + } +} \ No newline at end of file diff --git a/library/ZendAfi/View/Helper/Accueil/Authors.php b/library/ZendAfi/View/Helper/Accueil/Authors.php new file mode 100644 index 00000000000..4a5fb2e0b6d --- /dev/null +++ b/library/ZendAfi/View/Helper/Accueil/Authors.php @@ -0,0 +1,203 @@ +<?php +/** + * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH 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. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH 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 BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +class ZendAfi_View_Helper_Accueil_Authors extends ZendAfi_View_Helper_Accueil_Base { + public function getHTML() { + $this->titre = $this->preferences['titre']; + $this->contenu = $this->_renderContent(); + + return $this->getHtmlArray(); + } + + + public function performAction($action) { + if ($action === 'refresh') + $this->refreshAuthorsWithoutThumbnail(); + } + + + public function refreshAuthorsWithoutThumbnail() { + $authors = array_filter($this->_findAuthorsFromPreferences(), + function($author) + { + return !$author->isThumbnailValid(); + }); + array_map(function($author) + { + (new Class_CodifAuteur_Description($author))->fetchBiography(); + }, + $authors); + return $this; + } + + + protected function _extendedActions() { + if (!Class_Users::isCurrentUserCanAccesBackend()) + return null; + + return [ + function() + { + return $this->view->tagAnchor($this->view->url(['module' => 'admin', + 'controller' => 'widget', + 'action' => 'widget-action', + 'named' => 'refresh', + 'id_module' => $this->id_module, + 'id_profil' => Class_Profil::getCurrentProfil()->getId()]), + Class_Admin_Skin::current() + ->renderActionIconOn('images', + $this->view), + [ + 'title' => $this->view->_('Recharger les vignettes de la boite: %s', + htmlspecialchars($this->preferences['titre'])) + ]); + } + ]; + } + + + protected function _findAuthorsFromPreferences() { + $records = Class_Notice::getNoticesFromPreferences($this->preferences); + return $this->_getAuthorsFromRecords($records); + } + + + protected function _renderContent() { + $authors = array_filter($this->_findAuthorsFromPreferences(), + function($author) + { + return $author->isThumbnailValid(); + }); + + return $this->_tag('div', + implode('', array_map([$this, '_renderAuthor'], + $authors)), + ['class' => 'authors_wall', + 'style' => 'column-width:' . $this->preferences['op_largeur_img'] . 'px']); + } + + + protected function _getAuthorsFromRecords($records) { + $authors_ids = $this->_getAuthorsIdsFromRecords($records); + + return $authors_ids + ? Class_CodifAuteur::findAllBy(['id_auteur' => array_slice($authors_ids, + 0, + $this->preferences['authors_count'])]) + : []; + } + + + protected function _getAuthorsIdsFromRecords($records) { + if ($this->preferences['authors_selection_mode'] === Class_Systeme_ModulesAccueil_Authors::AUTHORS_SELECTION_MODE_MAIN) + return $this->_getMainAuthorsFromRecords($records); + + if ($this->preferences['authors_selection_mode'] === Class_Systeme_ModulesAccueil_Authors::AUTHORS_SELECTION_MODE_RESPONSIBILITIES) { + return $this->_getAuthorsByResponsibilitiesFromRecords($records); + } + + return $this->_getAllAuthorsFromRecords($records); + } + + + protected function _getAuthorsByResponsibilitiesFromRecords($records) { + $responsibilities_labels = $this->_getResponsibilitiesPreferenceLabels(); + + $authors_ids = []; + foreach($records as $record) { + $authors_ids = array_merge($authors_ids, + $this->_getAuthorsByResponsibilities($record, + $responsibilities_labels)); + } + + return array_filter(array_unique($authors_ids)); + } + + + protected function _getResponsibilitiesPreferenceLabels() { + $responsibilities_ids = array_filter(explode(';', + $this->preferences['responsibilities'])); + return array_filter( + array_map(function($responsibility) + { + return $responsibility->getLibelle(); + }, + $responsibilities_ids + ? Class_CodifAuteurFonction::findAllBy(['id_fonction' => $responsibilities_ids]) + : [])); + } + + + protected function _getAuthorsByResponsibilities($record, $responsibilities_labels) { + $authors = array_filter($record->getAuteursUnimarc(false, true), + function($author) use ($responsibilities_labels) + { + + return in_array($author->getFonction(), $responsibilities_labels); + }); + + return array_map(function($author) + { + return $author->getId(); + }, + $authors); + } + + + protected function _getMainAuthorsFromRecords($records) { + $authors_ids = array_map(function($record) + { + return current(Class_Notice_Facette::facetsValuesFromRecordFilteredBy($record, 'isAuthor')); + }, + $records); + + return array_filter(array_unique($authors_ids)); + } + + + protected function _getAllAuthorsFromRecords($records) { + $authors_ids = []; + foreach($records as $record) { + $authors_ids = array_merge($authors_ids, + Class_Notice_Facette::facetsValuesFromRecordFilteredBy($record, 'isAuthor')); + } + + return array_filter(array_unique($authors_ids)); + } + + + protected function _renderAuthor($author) { + return $this->_tag('div', + $this->_tag('a', + $this->_tag('img', + null, + ['src' => $author->getThumbnailUrl(), + 'width' => $this->preferences['op_largeur_img'], + 'alt' => $author->getLibelle() . '. ' . $this->_('Source: Wikipedia')]), + ['href' => $this->view->url(['controller' => 'author', + 'action' => 'view', + 'id' => $author->getId()]), + 'title' => $this->_('En savoir plus sur %s', $author->getLibelle())]), + ['class' => 'author']); + } +} + +?> \ No newline at end of file diff --git a/library/ZendAfi/View/Helper/Accueil/Base.php b/library/ZendAfi/View/Helper/Accueil/Base.php index 26a27cf4dbe..8d8c9e30d96 100644 --- a/library/ZendAfi/View/Helper/Accueil/Base.php +++ b/library/ZendAfi/View/Helper/Accueil/Base.php @@ -74,6 +74,11 @@ class ZendAfi_View_Helper_Accueil_Base extends ZendAfi_View_Helper_ModuleAbstrac } + public function performAction($action) { + //@see Admin_WidgetController::widgetActionAction() + } + + public function setIdMenu($id_menu) { $this->_id_menu = $id_menu; return $this; diff --git a/library/ZendAfi/View/Helper/Accueil/Kiosque.php b/library/ZendAfi/View/Helper/Accueil/Kiosque.php index db4fe904268..802d8d8c5ff 100644 --- a/library/ZendAfi/View/Helper/Accueil/Kiosque.php +++ b/library/ZendAfi/View/Helper/Accueil/Kiosque.php @@ -89,13 +89,13 @@ class ZendAfi_View_Helper_Accueil_Kiosque extends ZendAfi_View_Helper_Accueil_Ba return ''; return $this->view->tagAnchor($this->view->url(['module' => 'admin', - 'controller' => 'catalogue', - 'action' => 'edit', - 'id_catalogue' => $this->preferences['id_catalogue']]), - Class_Admin_Skin::current() - ->renderActionIconOn('edit', $this->view, - ['title' => $this->view->_('Modifier le domaine : %s', htmlspecialchars($catalogue->getLibelle()))]), - ['data-popup' => 'true']); + 'controller' => 'catalogue', + 'action' => 'edit', + 'id_catalogue' => $this->preferences['id_catalogue']]), + Class_Admin_Skin::current() + ->renderActionIconOn('edit', $this->view, + ['title' => $this->view->_('Modifier le domaine : %s', htmlspecialchars($catalogue->getLibelle()))]), + ['data-popup' => 'true']); } @@ -108,10 +108,10 @@ class ZendAfi_View_Helper_Accueil_Kiosque extends ZendAfi_View_Helper_Accueil_Ba return null; return $this->view->tagAnchor($this->view->url(['module' => 'admin', - 'controller' => 'catalogue', - 'action' => 'add', - 'id_catalogue' => $domaine_parent->getId(), - 'id_module' => $this->id_module]), + 'controller' => 'catalogue', + 'action' => 'add', + 'id_catalogue' => $domaine_parent->getId(), + 'id_module' => $this->id_module]), Class_Admin_Skin::current() ->renderActionIconOn('add', $this->view, ['title' => $this->view->_('Afficher un nouveau domaine')]), ['data-popup' => 'true']); diff --git a/library/ZendAfi/View/Helper/Admin/TagListeSuggestion.php b/library/ZendAfi/View/Helper/Admin/TagListeSuggestion.php index 670babfa5c7..c506440f4c3 100644 --- a/library/ZendAfi/View/Helper/Admin/TagListeSuggestion.php +++ b/library/ZendAfi/View/Helper/Admin/TagListeSuggestion.php @@ -149,6 +149,7 @@ class ZendAfi_View_Helper_Admin_TagListeSuggestion $map = [ 'auteur' => ['Class_CodifAuteur', [1 => $this->_('commence par')]], + 'responsibility' => ['Class_CodifAuteurFonction', [1 => $this->_('commence par')]], 'matiere' => ['Class_CodifMatiere'], 'interet' => ['Class_CodifCentreInteret'], 'dewey' => ['Class_CodifDewey', $dewey_pcdm4_options], diff --git a/library/ZendAfi/View/Helper/RenderAuthorMetadata.php b/library/ZendAfi/View/Helper/RenderAuthorMetadata.php index 7dc65e4e8c9..70703e887dc 100644 --- a/library/ZendAfi/View/Helper/RenderAuthorMetadata.php +++ b/library/ZendAfi/View/Helper/RenderAuthorMetadata.php @@ -28,17 +28,27 @@ class ZendAfi_View_Helper_renderAuthorMetadata extends ZendAfi_View_Helper_BaseH if ($id = $attributes['ark']) $attributes['ark'] = $this->_tag('a', $id, - ['href' => 'https://data.bnf.fr/fr/atelier/' . $id]); + ['href' => 'https://data.bnf.fr/' . $id, + 'target' => '_blank']); if ($id = $attributes['wikidata_id']) $attributes['wikidata_id'] = $this->_tag('a', $id, - ['href' => 'https://www.wikidata.org/wiki/' . $id]); + ['href' => 'https://www.wikidata.org/wiki/' . $id, + 'target' => '_blank']); if ($id = $attributes['youtube_channel_id']) $attributes['youtube_channel_id'] = $this->_tag('a', $id, - ['href' => Class_WebService_Youtube::CHANNEL_URL . $id]); + ['href' => Class_WebService_Youtube::CHANNEL_URL . $id, + 'target' => '_blank']); + + + if ($thumbnail_url = $attributes['thumbnail_url']) + $attributes['thumbnail_url'] = $this->_tag('a', + $thumbnail_url, + ['href' => $thumbnail_url, + 'target' => '_blank']); return $this->_tag('h2', $this->_('Auteur : %s', diff --git a/public/opac/css/global.css b/public/opac/css/global.css index 0175dae05a3..190e01a0128 100644 --- a/public/opac/css/global.css +++ b/public/opac/css/global.css @@ -3718,18 +3718,21 @@ a[href*="bookmarked-searches/notify"] img { overflow: hidden; } + .simple_wall > a > img { width: 100%; } .simple_wall > a > img, -.simple_wall > div { +.simple_wall > div, +.authors_wall div { transition: opacity 0.3s; } .simple_wall:hover > a:not(:hover), -.simple_wall:hover > div:not(:hover) { +.simple_wall:hover > div:not(:hover), +.authors_wall:hover div:not(:hover){ opacity: 0.4; } diff --git a/public/opac/js/widget_templates/authors.jpg b/public/opac/js/widget_templates/authors.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c7dc96512b093e9d3b838f312da344c51712f4c5 GIT binary patch literal 32175 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 literal 0 HcmV?d00001 diff --git a/public/opac/js/widget_templates/widget_templates.json b/public/opac/js/widget_templates/widget_templates.json index a939603c921..b24428962ab 100755 --- a/public/opac/js/widget_templates/widget_templates.json +++ b/public/opac/js/widget_templates/widget_templates.json @@ -225,7 +225,14 @@ } }, - { + { + "title": "Auteurs", + "icon": "authors.jpg", + "type": "AUTHORS", + "configuration": {} + }, + + { "title": "Nuage de tags", "icon": "nuage_tags.jpg", "type": "TAGS", diff --git a/tests/db/UpgradeDBTest.php b/tests/db/UpgradeDBTest.php index fb412af4b8d..6fe50e6c25d 100644 --- a/tests/db/UpgradeDBTest.php +++ b/tests/db/UpgradeDBTest.php @@ -2739,4 +2739,20 @@ class UpgradeDB_375_Test extends UpgradeDBTestCase { $this->assertEquals('Hello<br><br>You have a new friend', $this->query('select valeur from bib_admin_var where clef="NOTIFICATION_TEMPLATE_NEW_USER"')->fetch()['valeur']); } -} \ No newline at end of file +} + + + + +class UpgradeDB_376_Test extends UpgradeDBTestCase { + public function prepare() { + $this + ->silentQuery('ALTER TABLE codif_auteur DROP COLUMN thumbnail_url'); + } + + + /** @test */ + public function tableCodifAuteurShouldHaveColumnThumbnailUrlVarChar255() { + $this->assertFieldType('codif_auteur', 'thumbnail_url', 'varchar(255)'); + } +} diff --git a/tests/scenarios/AuthorPage/AuthorPageTest.php b/tests/scenarios/AuthorPage/AuthorPageTest.php index 7c13953da0e..327a3fddd6f 100644 --- a/tests/scenarios/AuthorPage/AuthorPageTest.php +++ b/tests/scenarios/AuthorPage/AuthorPageTest.php @@ -56,6 +56,7 @@ abstract class AuthorPageTestCase extends AbstractControllerTestCase { 'facettes' => 'A2408 A3', 'url_vignette' => 'paris.jpg']); + $this->fixture('Class_CodifAuteur', ['id' => 2408, 'libelle' => 'Victor Hugo']); @@ -190,17 +191,25 @@ class AuthorPageViewByIdTest extends AuthorPageTestCase { $this->assertEquals('UC1l7wYrva1qCH-wgqcHaaRg', Class_CodifAuteur::find(2408)->getYoutubeChannelId()); } - /** @test */ + /** @test */ public function authorISNIShouldBe0000000078391751() { $this->assertEquals('0000 0000 7839 1751', Class_CodifAuteur::find(2408)->getIsni()); } - /** @test */ + + /** @test */ public function authorARKShouldBecb13971020f() { $this->assertEquals('ark:/12148/cb13971020f', Class_CodifAuteur::find(2408)->getArk()); } + /** @test */ + public function authorThumbnailUrlShouldBeHugoThumbDotJpg() { + $this->assertEquals('http://images.fr/hugo_thumb.jpg', + Class_CodifAuteur::find(2408)->getThumbnailUrl()); + } + + /** @test */ public function pageTitleShouldBeVictorHugo() { $this->assertXPath('//title[text()="Auteur - Victor Hugo"]', $this->_response->getBody()); diff --git a/tests/scenarios/AuthorPage/AuthorWidgetTest.php b/tests/scenarios/AuthorPage/AuthorWidgetTest.php new file mode 100644 index 00000000000..d271480cad6 --- /dev/null +++ b/tests/scenarios/AuthorPage/AuthorWidgetTest.php @@ -0,0 +1,501 @@ +<?php +/** + * Copyright (c) 2012-2019, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH 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. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH 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 BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +abstract class AuthorWidgetOnPageTestCase extends Admin_AbstractControllerTestCase { + protected + $_storm_default_to_volatile = true; + + public function setUp() { + parent::setUp(); + + Class_AdminVar::set('AUTHOR_PAGE', 1); + + $cfg_accueil = ['modules' => ['1' => ['division' => '2', + 'type_module' => 'AUTHORS', + 'preferences' => ['titre' => 'Mes auteurs', + 'id_panier' => 3]]]]; + + $this->fixture('Class_Profil', + ['id' => 2, + 'libelle' => 'auteurs', + 'cfg_accueil' => $cfg_accueil]) + ->beCurrentProfil(); + + + $this->fixture('Class_Notice', + ['id' => 8, + 'type_doc' => Class_TypeDoc::LIVRE, + 'clef_alpha'=>'GAVROCHE_HUGO', + 'titre_principal' => 'Gavroche', + 'facettes' => 'A2408 A3 A666 G4 M6', + 'url_vignette' => 'gavroche.jpg']); + + $this->fixture('Class_Notice', + ['id' => 9, + 'type_doc' => Class_TypeDoc::LIVRE, + 'clef_alpha'=>'MISERABLES_HUGO', + 'titre_principal' => 'Les Misérables', + 'facettes' => 'A2408 M6 A4', + 'unimarc' => file_get_contents(__DIR__ . '/les_miserables.marc'), + 'url_vignette' => 'miserables.jpg', + 'url_image' => 'miserables.jpg']); + + $this->fixture('Class_Notice', + ['id' => 10, + 'type_doc' => Class_TypeDoc::DVD, + 'clef_alpha'=>'DAMEPARIS_HUGO', + 'titre_principal' => 'Notre Dame de Paris', + 'unimarc' => file_get_contents(__DIR__ . '/notre_dame.marc'), + 'facettes' => 'A2408 A3', + 'url_vignette' => 'paris.jpg']); + + $this->fixture('Class_CodifAuteur', + ['id' => 2408, + 'libelle' => 'Victor Hugo', + 'thumbnail_url' => 'http://wp/hugo.jpg']); + + $this->fixture('Class_CodifAuteur', + ['id' => 3, + 'libelle' => 'Robert Hossein', + 'thumbnail_url' => 'http://wp/hossein.jpg']); + + $this->fixture('Class_CodifAuteur', + ['id' => 4, + 'libelle' => 'Marcus %s \Mill', + 'thumbnail_url' => 'http://wp&f=Defaut.svg']); + + $this->fixture('Class_CodifAuteur', + ['id' => 5, + 'libelle' => 'Delannoy Jean', + 'thumbnail_url' => 'http://wp/delannoy.jpg']); + + $this->fixture('Class_CodifAuteurFonction', + ['id' => 635, + 'libelle' => 'Programmeur informatique']); + + $this->fixture('Class_CodifAuteurFonction', + ['id' => '370', + 'libelle' => 'Réalisateur']); + } +} + + + + +class AuthorWidgetActionRefreshThumbnailsTest extends AuthorWidgetOnPageTestCase { + public function setUp() { + parent::setUp(); + + $mock_sql = $this->mock() + ->whenCalled('fetchAll') + ->answers([[9, 'A2408 M6 A4']]); + Zend_Registry::set('sql', $mock_sql); + Class_CosmoVar::newInstanceWithId('url_services')->setValeur('http://cache.org'); + Class_WebService_AllServices::setHttpClient($http_client = $this->mock()); + + $http_client + ->whenCalled('open_url') + ->answers(json_encode(['statut_recherche' => 2, + 'erreur' => '', + 'vignette' => 'http://wp/marcus.jpg'])); + + $this->onLoaderOfModel('Class_Notice') + ->whenCalled('getNoticesFromPreferences') + ->answers(Class_Notice::findAll()); + + $this->dispatch('/admin/widget/widget-action/named/refresh/id_module/1/id_profil/2'); + } + + + /** @test */ + public function withIdModuleOneIdProfilTwoShouldSetThumbnailForMarcusMiller() { + $this->assertEquals('http://wp/marcus.jpg', + Class_CodifAuteur::find(4)->getThumbnailUrl()); + } + + + /** @test */ + public function answerShouldRedirectToReferrer() { + $this->assertRedirect(); + } +} + + + + +class AuthorWidgetActionRefreshThumbnailsWithWrongParamsTest extends AuthorWidgetOnPageTestCase { + public function errors() { + return [ + ['id_module/1/id_profil/66655', + [404, 'Profil inexistant']], + + ['id_module/134245/id_profil/2', + [404, 'Boite inexistante']], + ]; + } + + + /** + * @dataProvider errors + * @test + */ + public function withWrongIdProfilShouldAnswer404($url, $expected) { + try { + $this->dispatch('/admin/widget/widget-action/named/refresh/' . $url); + } catch(Zend_Controller_Action_Exception $e) { + $this->assertEquals($expected, + [$e->getCode(), $e->getMessage()]); + return; + } + $this->fail('should raise error 404 not found'); + } +} + + + + +class AuthorWidgetOnPageTest extends AuthorWidgetOnPageTestCase { + public function setUp() { + parent::setUp(); + + + $this->onLoaderOfModel('Class_Notice') + ->whenCalled('getNoticesFromPreferences') + ->willDo(function($preferences) + { + $this->assertEquals(3, $preferences['id_panier']); + $this->assertEquals(10, $preferences['authors_count']); + $this->assertEquals(Class_Systeme_ModulesAccueil_Authors::AUTHORS_SELECTION_MODE_ALL, + $preferences['authors_selection_mode']); + return Class_Notice::findAll(); + }); + + $this->dispatch('/'); + } + + + /** @test */ + public function pageShouldContainsWidgetAuthorWithH1MesAuteurs() { + $this->assertXPathContentContains('//div[@class="boite authors"]//div[@class="titre"]//h1', + 'Mes auteurs'); + } + + + /** @test */ + public function authorsWidgetShouldContainsLinkWithImageHosseinDotJpg() { + $this->assertXPath('//div[@class="boite authors"]//div[@class="author"]//a[contains(@href, "author/view/id/3")][@title="En savoir plus sur Robert Hossein"]//img[@src="http://wp/hossein.jpg"]'); + } + + + /** @test */ + public function numberOfAuthorsShouldBeTwo() { + $this->assertXPathCount('//div[@class="boite authors"]//div[@class="author"]', + 2); + } + + + /** @test */ + public function widgetConfigurationShouldContainsButtonToRefreshThumbnails() { + $this->assertXPath('//div[@class="configuration_module"]//a[contains(@href, "/admin/widget/widget-action/named/refresh/id_module/1/id_profil/2")]'); + } + + + /** @test */ + public function pageShouldBeHTML5Valid() { + $this->assertHTML5(); + } + + + /** @test */ + public function pageShouldBeAccessible() { + $this->assertAccessible(); + } +} + + + + +class AuthorWidgetOnPageWithMainAuthorSelectionModeTest extends AuthorWidgetOnPageTestCase { + public function setUp() { + parent::setUp(); + + Class_Profil::find(2) + ->setCfgAccueil(['modules' => ['1' => ['division' => '2', + 'type_module' => 'AUTHORS', + 'preferences' => ['titre' => 'Une sélection', + 'op_largeur_img' => '50', + 'authors_selection_mode' => Class_Systeme_ModulesAccueil_Authors::AUTHORS_SELECTION_MODE_MAIN, + 'id_catalogue' => 5]]]]); + + + $this->onLoaderOfModel('Class_Notice') + ->whenCalled('getNoticesFromPreferences') + ->willDo(function($preferences) + { + $this->assertEquals(5, $preferences['id_catalogue']); + $this->assertEquals(Class_Systeme_ModulesAccueil_Authors::AUTHORS_SELECTION_MODE_MAIN, + $preferences['authors_selection_mode']); + return Class_Notice::findAll(); + }); + + $this->dispatch('/'); + } + + + /** @test */ + public function numberOfAuthorsShouldBeOne() { + $this->assertXPathCount('//div[@class="boite authors"]//div[@class="author"]', + 1); + } + + + /** @test */ + public function authorsWidgetShouldContainsLinkWithImageHugoDotJpg() { + $this->assertXPath('//div[@class="boite authors"]//div[@class="author"]//a[contains(@href, "author/view/id/2408")][@title="En savoir plus sur Victor Hugo"]//img[@src="http://wp/hugo.jpg"][@width="50"]'); + } + + + /** @test */ + public function divAuthorsWallShouldHaveStyleColumnWidth50px() { + $this->assertXPath('//div[@class="authors_wall"][@style="column-width:50px"]'); + } +} + + + + +class AuthorWidgetOnPageFilteredByResponsibilityTest extends AuthorWidgetOnPageTestCase { + public function setUp() { + parent::setUp(); + + Class_Profil::find(2) + ->setCfgAccueil(['modules' => ['1' => ['division' => '2', + 'type_module' => 'AUTHORS', + 'preferences' => ['titre' => 'Une sélection', + 'op_largeur_img' => '50', + 'authors_selection_mode' => Class_Systeme_ModulesAccueil_Authors::AUTHORS_SELECTION_MODE_RESPONSIBILITIES, + 'responsibilities' => '230;370;', + 'id_catalogue' => 5]]]]); + + + $this->onLoaderOfModel('Class_Notice') + ->whenCalled('getNoticesFromPreferences') + ->answers(Class_Notice::findAll()); + + $this->onLoaderOfModel('Class_CodifAuteur') + ->whenCalled('findByLastNameFirstName') + ->with('Delannoy', 'Jean') + ->answers(Class_CodifAuteur::find(5)); + + $this->dispatch('/'); + } + + + /** @test */ + public function numberOfAuthorsShouldBeOne() { + $this->assertXPathCount('//div[@class="boite authors"]//div[@class="author"]', + 1); + } + + + /** @test */ + public function authorsWidgetShouldContainsLinkWithImageDelannoyJpg() { + $this->assertXPath('//a[contains(@href, "author/view/id/5")][@title="En savoir plus sur Delannoy Jean"]//img[@src="http://wp/delannoy.jpg"]'); + } +} + + + + +class AuthorWidgetOnPageLimitOneTest extends AuthorWidgetOnPageTestCase { + public function setUp() { + parent::setUp(); + + Class_Profil::find(2) + ->setCfgAccueil(['modules' => ['1' => ['division' => '2', + 'type_module' => 'AUTHORS', + 'preferences' => ['titre' => 'Une sélection', + 'authors_count' => 1, + 'id_catalogue' => 5]]]]); + + + $this->onLoaderOfModel('Class_Notice') + ->whenCalled('getNoticesFromPreferences') + ->willDo(function($preferences) + { + $this->assertEquals(1, $preferences['authors_count']); + return Class_Notice::findAll(); + }); + + $this->dispatch('/'); + } + + + /** @test */ + public function numberOfAuthorsShouldBeOne() { + $this->assertXPathCount('//div[@class="boite authors"]//div[@class="author"]', + 1); + } + + + /** @test */ + public function authorsWidgetShouldContainsLinkWithImageHugoDotJpg() { + $this->assertXPath('//div[@class="boite authors"]//div[@class="author"]//a[contains(@href, "author/view/id/2408")][@title="En savoir plus sur Victor Hugo"]//img[@src="http://wp/hugo.jpg"]'); + } +} + + + + +class AuthorWidgetConfigurationTest extends AuthorWidgetOnPageTestCase { + public function setUp() { + parent::setUp(); + $this->dispatch('/admin/widget/edit-widget/id/1/id_profil/2'); + } + + + /** @test */ + public function formShouldContainsInputForTitre() { + $this->assertXPath('//input[@name="titre"][@value="Mes auteurs"]', + $this->_response->getBody()); + } + + + /** @test **/ + public function formShouldContainsHiddenInputWithIdCatalogue() { + $this->assertXPath('//input[@type="hidden"][@id="id_catalogue"]'); + } + + + /** @test **/ + public function formShouldContainsHiddenInputWithIdPanierValueThree() { + $this->assertXPath('//input[@type="hidden"][@id="id_panier"][@value="3"]'); + } + + + /** @test **/ + public function formShouldContainsInputAuthorsCountValueTen() { + $this->assertXPath('//input[@type="number"][@name="authors_count"][@value="10"][@min="1"][@max="200"]'); + } + + + /** @test **/ + public function formShouldContainsInputSliderForOpLargeurImg() { + $this->assertXPath('//input[@name="op_largeur_img"]'); + $this->assertXPathContentContains('//script', '$("#op_largeur_img-slider").slider'); + } + + + /** @test */ + public function formShouldContainsRadioButtonForAuthorsSelectionModeMain() { + $this->assertXPath('//input[@type="radio"][@name="authors_selection_mode"][@value="main"][not(@checked)]'); + } + + + /** @test */ + public function formShouldContainsCheckedRadioButtonForAuthorsSelectionModeAll() { + $this->assertXPath('//input[@type="radio"][@name="authors_selection_mode"][@value="all"][@checked]'); + } +} + + + + +class AuthorWidgetConfigurationWithDomainTest extends AuthorWidgetOnPageTestCase { + public function setUp() { + parent::setUp(); + Class_Profil::find(2) + ->setCfgAccueil(['modules' => ['1' => ['division' => '2', + 'type_module' => 'AUTHORS', + 'preferences' => ['titre' => 'Une sélection', + 'id_catalogue' => 5]]]]) + ->save(); + + $this->dispatch('/admin/widget/edit-widget/id/1/id_profil/2'); + } + + + /** @test */ + public function formShouldContainsInputForTitreWithVlueUneSelection() { + $this->assertXPath('//input[@name="titre"][@value="Une sélection"]'); + } + + + /** @test **/ + public function formShouldContainsHiddenInputWithIdCategorieValueFive() { + $this->assertXPath('//input[@type="hidden"][@id="id_catalogue"][@value="5"]'); + } +} + + + + +class AuthorWidgetConfigurationPostTest extends AuthorWidgetOnPageTestCase { + protected $_saved_settings; + + public function setUp() { + parent::setUp(); + $this->postDispatch('/admin/widget/edit-widget/id/1/id_profil/2', + ['id_panier' => '5', + 'titre' => 'Des gens']); + Class_Profil::clearCache(); + $this->_saved_settings = Class_Profil::find(2) + ->getCfgAccueilAsArray()['modules'][1]; + } + + + /** @test **/ + public function shouldRedirect() { + $this->assertRedirect(); + } + + + /** @test */ + public function titleShouldBeDesGens() { + $this->assertEquals('Des gens', $this->_saved_settings['preferences']['titre']); + } + + + /** @test */ + public function idPanierShouldBeFive() { + $this->assertEquals('5', $this->_saved_settings['preferences']['id_panier']); + } +} + + + + +class AuthorWidgetResponsibilitiesInputSuggestTest extends AuthorWidgetOnPageTestCase { + /** @test */ + public function onSearchTermProShouldRetunProgrammeurInformatique() { + $this->onLoaderOfModel('Class_CodifAuteurFonction') + ->whenCalled('findAllBy') + ->with(['where' => 'libelle like "Pro%"', + 'order' => 'libelle']) + ->answers([Class_CodifAuteurFonction::find(635)]); + + $this->dispatch('/admin/ajax/listesuggestion?type_autorite=responsibility&id_champ=responsibilities&mode=1&valeur=Pro'); + + $this->assertEquals('<div class="tag_liste" clef="635" onclick="selectSuggest(\'responsibilities\',this)">Programmeur informatique</div>', + $this->_response->getBody()); + } +} diff --git a/tests/scenarios/AuthorPage/notre_dame.marc b/tests/scenarios/AuthorPage/notre_dame.marc new file mode 100644 index 00000000000..aab37b06f3e --- /dev/null +++ b/tests/scenarios/AuthorPage/notre_dame.marc @@ -0,0 +1 @@ +01365nam0 2200253 450 001000700000100001300007200002400020210006200044215009600106300002600202330029900228700003800527702018000565702004000745702005500785702002900840702003300869702002900902702002600931702002600957702002900983702008201012801001701094256387 a201105051 aNotre-Dame de Paris a[Issy-les-Moulineaux]cStudioCanal vidéo éd.dcop. 2005 a1 DVD vidéo monoface double couche zone 2, 1h58 min.c. 2.35, 16/9 comp. 4/3, coul. (PAL), aPays : France (1956). aDans le Paris médiéval, la belle danseuse Esméralda déchaine les passions. Au milieu des mendiants et des truands de la cour des Miracles, le drame se noue peu à peu entre Phoebus, le capitaine des gardes dont elle est amoureuse, le monstrueux Quasimodo et l'inquiétant alchimiste Frollo. 1aDelannoybJean40006Réalisateur 1aHugobVictorf1802-188531190796640106Adaptateur8Hugo, Victor-Marie (1802-1885)8Hugo, Vittor (1802-1885)8Hugo, Vittorio (1802-1885)8Yu guo (1802-1885)8Yuguo (1802-1885) 1aAurenchebJean40006Dialogues avec 1aPrévertbJacques3OPS117832940006Dialogues avec 1aAuricbGeorges40006230 1aLollobrigidabGina48006005 1aQuinnbAnthony48006005 1aDanetbJean48006005 1aCunybAlain48006005 1aHirschbRobert48006005 1aClaybPhilippef1927-2007311935067480060058Mathevet, Philippe (1927-2007) 2aFrc20150404 \ No newline at end of file -- GitLab