diff --git a/VERSIONS_HOTLINE/141990 b/VERSIONS_HOTLINE/141990 new file mode 100644 index 0000000000000000000000000000000000000000..d2082148003caebc74efa65c356107f51a596595 --- /dev/null +++ b/VERSIONS_HOTLINE/141990 @@ -0,0 +1 @@ + - ticket #141990 : DiMusic : Ajout du script scripts/dimusic_first_harvest.php permettant de lancer le premier moissonage de cette ressource. \ No newline at end of file diff --git a/library/Class/DigitalResource.php b/library/Class/DigitalResource.php index c4e26c3c7096c6109bf2849867aff6c8f334cdda..6832c9e2fc51e7ae0faf056f8677ccf613b221a1 100644 --- a/library/Class/DigitalResource.php +++ b/library/Class/DigitalResource.php @@ -148,6 +148,24 @@ class Class_DigitalResource extends Class_Entity { } + public function getImporters() { + return $this->pluginsByName(function($config) + { + if($importer = $config->getImporter()) + return $this->build($importer, $config); + }); + } + + + public function getHarvesters() { + return $this->pluginsByName(function($config) + { + if($harvester = $config->getHarvester()) + return $this->build($harvester, $config); + }); + } + + public function hasRightAccessPlugin($plugin, $user) { if (!$this->isPluginDocType($plugin)) return false; diff --git a/library/Class/DigitalResource/Config.php b/library/Class/DigitalResource/Config.php index e2f92262271a4ea29ea46c83ecedaf173ce86126..400946039522a5e2d34251c8b8aa4fae933bc3fa 100644 --- a/library/Class/DigitalResource/Config.php +++ b/library/Class/DigitalResource/Config.php @@ -110,6 +110,32 @@ class Class_DigitalResource_Config extends Class_Entity { } + public function isFirstHarvestAware() { + return $this->getHarvester() + && $this->getImporter(); + } + + + public function isFirstHarvestDone() { + return $this->getHarvesterInstance()->isDone(); + } + + + public function isFirstImportDone() { + return $this->getImporterInstance()->isDone(); + } + + + public function isFirstHarvestRunning() { + return $this->getHarvesterInstance()->isRunning(); + } + + + public function isFirstImportRunning() { + return $this->getImporterInstance()->isRunning(); + } + + public function getDashboardUrl() { return Class_Url::absolute(['module' => $this->getModuleName()], null, @@ -118,7 +144,33 @@ class Class_DigitalResource_Config extends Class_Entity { public function getBatchInstance() { - return $this->getDigitalResource()->getBatches()[$this->getBatch()]; + return $this->_getObjectInstance($this->getDigitalResource()->getBatches(), + $this->getBatch()); + } + + + public function getImporterInstance() { + return $this->_getObjectInstance($this->getDigitalResource()->getImporters()); + } + + + public function getHarvesterInstance() { + return $this->_getObjectInstance($this->getDigitalResource()->getHarvesters()); + } + + + protected function _getObjectInstance($instances, $key = '') { + if ( ! $instances ) + return null; + + $key = + ( $key + ? $key + : $this->getName() ); + + return isset($instances[$key]) + ? $instances[$key] + : null; } diff --git a/library/Class/DigitalResource/Harvester/OAI.php b/library/Class/DigitalResource/Harvester/OAI.php new file mode 100644 index 0000000000000000000000000000000000000000..37022f93ad30e2adda53df1ba37a86da65654303 --- /dev/null +++ b/library/Class/DigitalResource/Harvester/OAI.php @@ -0,0 +1,103 @@ +<?php +/** + * Copyright (c) 2012-2021, 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_DigitalResource_Harvester_OAI extends Class_DigitalResource_OAI_AbstractInitJob { + + public function __construct() { + parent::__construct(); + $this->_job = $this->_('moissonnage de l\'OAI'); + } + + + protected function _clean() { + return $this + ->_cleanHarvestLogs() + ->_cleanXML(); + } + + + protected function _cleanHarvestLogs() { + $this->_log($this->_('Suppression des précédents journaux de moissonnage de %s.', + $this->_name)); + + Class_WebService_HarvestLog::deleteBy([ 'type_doc' => $this->_doc_type ]); + $this->_cleanMemory(); + + return $this; + } + + + protected function _cleanXML() { + $this->_log($this->_('Suppression des fichiers XML existants dans %s', $this->_oai_xml_directory_path)); + + Class_FileManager::deleteFiles($this->_oai_xml_directory_path); + + return $this; + } + + + protected function _work() { + $this->_log($this->_('Début du moissonnage.')); + $this->_oai_ws->setLogger($this->getLogger()); + + Class_FileManager::create($this->_oai_xml_directory_name, + Class_FileManager::find(USERFILES)); + + $page = 0; + while($this->_oai_ws->hasRecordsToHarvest()) + $this->_writeXML($page ++); + + Class_WebService_HarvestLog::newInstance(['end_date' => $this->getCurrentDate(), + 'type_doc' => $this->_doc_type]) + ->save(); + + $this->_log($this->_('%s fichiers sauvegardés.', ((int) $page ) -1)); + return $this; + } + + + protected function _writeXML($page) { + if ( ! $xml = $this->_getXML($page)) + return; + + $this->_oai_ws->parseResumptionToken($xml); + Class_FileManager::createFile($this->_oai_xml_directory_path . '/' . $page . '.xml', $xml); + } + + + protected function _getXML($page) { + return $page == 1 + ? $this->_oai_ws->getXML() + : $this->_oai_ws->getNextXML(); + } + + + public function isDone() { + return Class_WebService_HarvestLog::findFirstBy(['type_doc' => $this->_doc_type]); + } + + + public function isRunning() { + return ( ! $this->isDone()) + && Class_FileManager::hasFilesIn($this->_oai_xml_directory_path); + } +} diff --git a/library/Class/DigitalResource/Importer/OAI.php b/library/Class/DigitalResource/Importer/OAI.php new file mode 100644 index 0000000000000000000000000000000000000000..547fa1c1ccdf825404fa2bf32d70ccd5f487eaea --- /dev/null +++ b/library/Class/DigitalResource/Importer/OAI.php @@ -0,0 +1,121 @@ +<?php +/** + * Copyright (c) 2012-2021, 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_DigitalResource_Importer_OAI extends Class_DigitalResource_OAI_AbstractInitJob { + + public function __construct() { + parent::__construct(); + $this->_job = $this->_('import des albums'); + } + + + protected function _clean() { + if (Class_FileManager::files($this->_oai_xml_done_directory_path)) + return $this; + + $this->_log($this->_('%s : suppression des albums existants', + $this->_name)); + + $count_all_dimusic_albums = Class_Album::countBy(['type_doc_id' => $this->_doc_type]); + + $deleted_albums = 0; + + while ( $albums = Class_Album::findAllBy(['type_doc_id' => $this->_doc_type, + 'limit' => 100])) { + $deleted_albums += $this->_deleteAlbums($albums); + $this->_log(sprintf('%s/%s', + $deleted_albums, + $count_all_dimusic_albums)); + + $this->_cleanMemory(); + } + + return $this; + } + + + protected function _deleteAlbums($albums) { + $deleted_albums = 0; + foreach($albums as $album) { + $album->delete(); + $deleted_albums ++; + } + + return $deleted_albums; + } + + + protected function _work() { + $this->_log($this->_('%s : création des albums.', + $this->_name)); + + Class_FileManager::create(static::DONE_DIRECTORY, + Class_FileManager::find($this->_oai_xml_directory_path)); + + $files = Class_FileManager::files($this->_oai_xml_directory_path); + $total = count($files); + $count = 1; + + foreach ( $files as $xml_file ) { + $this->_log($this->_('Traitement du fichier : %s. %s/%s', + $xml_file->getPath(), + $count, + $total)); + $this->_workWithFile($xml_file); + $count ++; + } + + return $this; + } + + + protected function _workWithFile($xml_file) { + $xml = $xml_file->getContent(); + if ($this->_service->importFrom($xml)) + Class_FileManager::moveItemInto($xml_file, + $this->_oai_xml_done_directory_path + . '/' + . $xml_file->getName()); + + return $this; + } + + + public function isDone() { + return (0 < $this->_config->countAlbums()) + && $this->_config->getHarvesterInstance()->isDone(); + } + + + public function isRunning() { + return ( ! $this->isDone()) + && Class_FileManager::hasFilesIn($this->_oai_xml_directory_path); + } + + + public function getUserfilesFolderToDelete() { + return (Class_FileManager::find($this->_oai_xml_done_directory_path) + && $this->isDone()) + ? $this->_oai_xml_directory_path + : ''; + } +} diff --git a/library/Class/DigitalResource/OAI/AbstractInitJob.php b/library/Class/DigitalResource/OAI/AbstractInitJob.php new file mode 100644 index 0000000000000000000000000000000000000000..5b9df3508153f60de2dff02ab67db2eb53c00eac --- /dev/null +++ b/library/Class/DigitalResource/OAI/AbstractInitJob.php @@ -0,0 +1,109 @@ +<?php +/** + * Copyright (c) 2012-2021, 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 Class_DigitalResource_OAI_AbstractInitJob { + use + Trait_TimeSource, + Trait_Translator, + Trait_MemoryCleaner, + Trait_Logger; + + const DONE_DIRECTORY = 'done'; + + + protected + $_job, + $_config, + $_service, + $_doc_type, + $_oai_xml_directory_name, + $_oai_xml_directory_path; + + + public function __construct() { + $this->_config = Class_DigitalResource_Config::getInstanceFor(static::class); + $this->_name = $this->_config->getName(); + $this->_doc_type = $this->_config->getDocType(); + $this->_service = $this->_config->getServiceInstance(); + $this->_oai_ws = $this->_config->newOAIClient(); + + $this->_oai_xml_directory_name = sprintf('%s_oai_xml_responses', + strtolower($this->_name)); + + $this->_oai_xml_directory_path = USERFILES . '/' . $this->_oai_xml_directory_name; + + $this->_oai_xml_done_directory_path = + $this->_oai_xml_directory_path + . '/' + . static::DONE_DIRECTORY; + + Class_FileManager::disableCache(); + Class_FileManager::beOpenBar(); + Class_FileManager_FileSystem::beUnlimited(); + } + + + protected function _log($message) { + return $this->getLogger()->log("\n" . $message); + } + + + public function run() { + if ( ! $this->_config->isEnabled() ) { + $this->_log($this->_('%s n\'est pas activé. Le script est arrété.', + $this->_name)); + return $this;; + } + + return $this + ->_intro() + ->_clean() + ->_work() + ->_stop(); + } + + protected function _intro() { + $this->_log($this->_('%s : Début premier %s à %s.', + $this->_name, + $this->_job, + $this->getCurrentDateTime())); + return $this; + } + + + protected function _stop() { + Class_FileManager::reset(); + $this->_oai_ws->reset(); + + $this->_log($this->_('%s : Fin du premier %s à %s.', + $this->_name, + $this->_job, + $this->getCurrentDateTime())); + return $this; + } + + + abstract protected function _clean(); + abstract protected function _work(); + abstract public function isDone(); + abstract public function isRunning(); +} \ No newline at end of file diff --git a/library/Class/FileManager.php b/library/Class/FileManager.php index b81ed12c86ea10f770538bbe66f65aac16a776c1..084c7b5643bd2b6cca2b3e68ca2a94d8c8ea29d6 100644 --- a/library/Class/FileManager.php +++ b/library/Class/FileManager.php @@ -67,6 +67,11 @@ class Class_FileManager extends Class_Entity { } + public static function disableCache() { + return static::getFileSystem()->disableCache(); + } + + public static function getDiskSpaceInfo() { return static::getFileSystem()->diskSpaceInfo(); } @@ -276,6 +281,17 @@ class Class_FileManager extends Class_Entity { } + public static function deleteFiles ($path) { + foreach (Class_FileManager::files($path) as $file) + Class_FileManager::delete($file); + } + + + public static function hasFilesIn($path) { + return 0 < static::getFileSystem()->countFilesIn($path); + } + + public static function search($term, $path) { if (!static::userHasRightOnPath($path)) return []; @@ -363,6 +379,11 @@ class Class_FileManager extends Class_Entity { public static function createImage($path, $content) { + return static::createFile($path, $content); + } + + + public static function createFile($path, $content) { return static::getFileSystem()->createImage($path, $content); } diff --git a/library/Class/FileManager/FileSystem.php b/library/Class/FileManager/FileSystem.php index d98f26518820aa6910ca3ccd0688ce5a1b12a2ee..ca500fc6280d89113a3fba181450c70d5e5cf866 100644 --- a/library/Class/FileManager/FileSystem.php +++ b/library/Class/FileManager/FileSystem.php @@ -26,7 +26,9 @@ class Class_FileManager_FileSystem { const LISTING_LIMIT = 200; - protected static $_limited = true; + protected static + $_limited = true, + $_cache_status = true; protected $_cached_paths = [], @@ -40,6 +42,7 @@ class Class_FileManager_FileSystem { public static function reset() { static::$_limited = true; + static::$_cache_status = true; } @@ -53,8 +56,13 @@ class Class_FileManager_FileSystem { } + public function countFilesIn($path) { + return count($this->_glob($path, false)); + } + + protected function _filterEntriesAt($path, $callback = null) { - $items = $this->_glob($path, true); + $items = $this->_glob($path, static::$_cache_status); if (static::$_limited && Class_FileManager_FileSystem::LISTING_LIMIT < count($items)) { $this->_oversized[] = $path; @@ -334,16 +342,17 @@ class Class_FileManager_FileSystem { protected function _glob($path, $cache = true) { $this->_cached_paths[] = $path; - $closure = function() use ($path) { - $paths = glob($path . '/{,.}[!.,!..]*', GLOB_BRACE); - $paths = array_filter($paths, - function($path) - { - return Class_FileManager::userHasRightOnPath($path); - }); - sort($paths, SORT_NATURAL); - return $paths; - }; + $closure = function() use ($path) + { + $paths = glob($path . '/{,.}[!.,!..]*', GLOB_BRACE); + $paths = (array_filter($paths, + function($path) + { + return Class_FileManager::userHasRightOnPath($path); + })); + sort($paths, SORT_NATURAL); + return $paths; + }; if($cache) return (new Storm_Cache()) @@ -398,4 +407,9 @@ class Class_FileManager_FileSystem { ob_end_clean(); return readfile($path); } + + + public function disableCache() { + static::$_cache_status = false; + } } \ No newline at end of file diff --git a/library/Class/WebService/BibNumerique/AbstractOAI.php b/library/Class/WebService/BibNumerique/AbstractOAI.php index 96723336ba7f8b9b858c3a40251b4de7c81bf74f..aa9c8c14bd9ea27c816cd9d40722f4a1d8d47e0e 100644 --- a/library/Class/WebService/BibNumerique/AbstractOAI.php +++ b/library/Class/WebService/BibNumerique/AbstractOAI.php @@ -38,6 +38,11 @@ abstract class Class_WebService_BibNumerique_AbstractOAI extends Class_WebServic } + public function importFrom($xml) { + return $this->_importRessources($this->getOaiWS()->parseXML($xml)); + } + + protected function _logRun() { Class_WebService_HarvestLog::newInstance(['end_date' => $this->getCurrentDate(), 'type_doc' => $this->getDocType()])->save(); @@ -97,7 +102,7 @@ abstract class Class_WebService_BibNumerique_AbstractOAI extends Class_WebServic protected function getOaiWS() { - return $this->_oaiws; + return $this->_oaiws->setLogger($this->getLogger()); } diff --git a/library/Class/WebService/BibNumerique/ArteVOD/Config.php b/library/Class/WebService/BibNumerique/ArteVOD/Config.php index 2cbbd9b390bc04fa195a8140f25b439249daf988..d3c359e42da839b3257120eb53a7c79586d3bf85 100644 --- a/library/Class/WebService/BibNumerique/ArteVOD/Config.php +++ b/library/Class/WebService/BibNumerique/ArteVOD/Config.php @@ -201,4 +201,9 @@ class Class_WebService_BibNumerique_ArteVOD_Config extends Class_Entity { public function renderTrySsoUrlOn($view, $params=[]) { return $view->url(array_merge($params, ['action' => 'artevod-try-sso'])); } + + + public function isFirstHarvestAware() { + return false; + } } diff --git a/library/Class/WebService/OAI.php b/library/Class/WebService/OAI.php index 6a7a8c37579eb81678cc621b429aab69d5c3d803..a299a152e529b58ba6e43d5894e61f8e4aea4387 100644 --- a/library/Class/WebService/OAI.php +++ b/library/Class/WebService/OAI.php @@ -31,6 +31,9 @@ */ class Class_WebService_OAI extends Class_WebService_Abstract { + use Trait_Translator; + + const Verb = 'verb', MetadataPrefix = 'metadataPrefix', @@ -52,6 +55,14 @@ class Class_WebService_OAI extends Class_WebService_Abstract { $_logger; + /** @override Trait_SimpleWebClient::getWebClient() */ + public static function getWebClient() { + return isset(static::$_web_client) + ? static::$_web_client + : new Class_WebService_WaitingSimpleWebClient(); + } + + public static function baseURL() { return Class_Url::absolute(['module' => 'opac', 'controller' => 'oai', @@ -154,8 +165,19 @@ class Class_WebService_OAI extends Class_WebService_Abstract { public function oaiAsks($verb, $parameters) { $url = $this->_askUrlFor($verb, $parameters); + $this->_log($this->_('Url : %s', $url)); + $response = $this->getContent($url); - $this->_log($url, $response); + 200 < strlen($response) + ? ($this + ->_log($this->_('Réponse :')) + ->_log(substr($response, 0, 200)) + ->_log('[…]') + ->_log(substr($response, -200))) + : $response; + + if ( ! $response ) + $this->setListRecordsResumptionToken(null); return $response; } @@ -173,10 +195,12 @@ class Class_WebService_OAI extends Class_WebService_Abstract { } - protected function _log($url, $response) { + protected function _log($message) { if (!$this->_logger) - return; - $this->_logger->log($url, $response); + return $this; + + $this->_logger->log($message); + return $this; } @@ -235,11 +259,9 @@ class Class_WebService_OAI extends Class_WebService_Abstract { if (!$this->isFirstPage()) return $this->getNextNumericResources(); - $params = array_filter(array_merge([static::MetadataPrefix => $this->_metadata_prefix, - static::Set => $this->_default_set], - $params)); $this->_first_page = false; - $xml_data = $this->oaiAsks(static::ListRecords, $params); + + $xml_data = $this->getXML($params); return $this->parseListRecordsRessourcesNumeriqueXML($xml_data); } @@ -258,7 +280,8 @@ class Class_WebService_OAI extends Class_WebService_Abstract { public function getRecords($params = []) { - $params = array_merge([static::MetadataPrefix => $this->_metadata_prefix], $params); + $params = array_merge([static::MetadataPrefix => $this->_metadata_prefix], + $params); $xml_data = $this->oaiAsks(static::ListRecords, $params); return $this->parseListRecordsXML($xml_data); @@ -304,14 +327,39 @@ class Class_WebService_OAI extends Class_WebService_Abstract { protected function _withNextPageDo($method) { - if (!$this->hasNextRecords()) - return []; + return ($xml_data = $this->getNextXML()) + ? $this->$method($xml_data) + : []; + } - $xml_data = $this - ->oaiAsks(static::ListRecords, - [static::ResumptionToken => $this->getListRecordsResumptionToken()->getToken()]); - return $this->$method($xml_data); + public function getXML($params = []) { + $params = array_filter(array_merge([static::MetadataPrefix => $this->_metadata_prefix, + static::Set => $this->_default_set], + $params)); + return $this->oaiAsks(static::ListRecords, $params); + } + + + public function getNextXML() { + return $this->hasNextRecords() + ? $this->getXML([static::MetadataPrefix => null, + static::Set => null, + static::ResumptionToken => + $this->getListRecordsResumptionToken()->getToken()]) + : ''; + } + + + public function parseResumptionToken($xml) { + $this->parser->parse($xml); + + return ($token = $this->parser->getResumptionToken()) + ? ($this + ->setListRecordsResumptionToken($token) + ->beNextPage()) + : ($this + ->setListRecordsResumptionToken(null)); } @@ -356,6 +404,19 @@ class Class_WebService_OAI extends Class_WebService_Abstract { } + public function beNextPage() { + $this->_first_page = false; + return $this; + } + + + public function parseXML($xml) { + $this->parser->acceptVisitor($this); + $this->parser->parse($xml); + return $this->parser->getRecordsRessourceNumeriques(); + } + + public function reset() { return $this->setListRecordsResumptionToken(null) ->beFirstPage(); diff --git a/library/ZendAfi/View/Helper/BaseHelper.php b/library/ZendAfi/View/Helper/BaseHelper.php index e6d92f6709cc906fa17fc73fbc1bf345cc5d471d..cf4db9a25b04f749c334e52268778df18d22fbde 100644 --- a/library/ZendAfi/View/Helper/BaseHelper.php +++ b/library/ZendAfi/View/Helper/BaseHelper.php @@ -71,6 +71,11 @@ class ZendAfi_View_Helper_BaseHelper extends Zend_View_Helper_HtmlElement { } + protected function _tagSuccess($message) { + return call_user_func_array([$this->view, 'tagSuccess'], func_get_args()); + } + + protected function _tagWarning($message) { return call_user_func_array([$this->view, 'tagWarning'], func_get_args()); } diff --git a/library/ZendAfi/View/Helper/DigitalResource/Dashboard/Harvest.php b/library/ZendAfi/View/Helper/DigitalResource/Dashboard/Harvest.php index bb3ed791f9e472cddca788d09e6e47fd21d136b5..39e5d08723acaca1d51958d9794dd26475eb9c0f 100644 --- a/library/ZendAfi/View/Helper/DigitalResource/Dashboard/Harvest.php +++ b/library/ZendAfi/View/Helper/DigitalResource/Dashboard/Harvest.php @@ -33,6 +33,9 @@ class ZendAfi_View_Helper_DigitalResource_Dashboard_Harvest extends ZendAfi_View protected function _render($config) { $html = [$this->_tag('h3', $this->_('Diagnostic moissonnage'))]; + if ($config->isFirstHarvestAware()) + $html = $this->_addFirstHarvestAware($html, $config); + if (!$config->getBatch()) { $html [] = $this->_tagNotice($this->_('Cette ressource ne prend pas en charge le moissonnage')) ; return implode($html); @@ -51,7 +54,7 @@ class ZendAfi_View_Helper_DigitalResource_Dashboard_Harvest extends ZendAfi_View protected function _getTypedocImage($config){ return $this->_tag('h4', - $this->_('Image du type de document: ') + $this->_('Image du type de document: ') . $config->getTypeDocImage($this->view)); } @@ -106,7 +109,7 @@ class ZendAfi_View_Helper_DigitalResource_Dashboard_Harvest extends ZendAfi_View 'condition' => function($model) { return Class_Users::isCurrentUserSuperAdmin() && $model->isActive(); - }, + }, 'anchorOptions' => ['data-popup' => 'true']], ['url' => '/admin/batch/run/id/%s', @@ -200,4 +203,52 @@ class ZendAfi_View_Helper_DigitalResource_Dashboard_Harvest extends ZendAfi_View $this->_('Nombre de notices présentes dans Bokeh : %d', $count)), $records_link]); } + + + protected function _addFirstHarvestAware($html, $config) { + if ( $harvest_done = $config->isFirstHarvestDone()) + $html [] = $this->_tagSuccess($this->_('Le premier moissonnage a été effectué.')); + + if ( $import_done = $config->isFirstImportDone()) + $html [] = $this->_tagSuccess($this->_('Le premier import d\'albums a été effectué.')); + + if ( $harvest_done && $import_done) + return $html = $this->_allowDeletionOfFiles($html, $config); + + $html [] = $this->_tagError($this->_('Cette ressource nécessite un premier moissonnage manuel et un premier import manuel.')); + + $html [] = $this->_tagError($this->_('Vous devez contacter votre hébergeur pour réaliser ces actions.')); + + if ( $harvest_running = $config->isFirstHarvestRunning() ) + $html [] = $this->_tagWarning($this->_('Le premier moissonnage d\'albums est en cours.')); + + if ( $import_running = $config->isFirstImportRunning() ) + $html [] = $this->_tagWarning($this->_('Le premier import d\'albums est en cours.')); + + $html [] = $this->_tagError($this->_('En attendant le batch %s ne doit ni être lancé ni être plannifié.', + $config->getBatchInstance()->getLabel())); + + return $html; + } + + + protected function _allowDeletionOfFiles($html, $config) { + $importer = $config->getImporterInstance(); + + if ($userfiles_folder = $importer->getUserfilesFolderToDelete()) { + $delete_folder_anchor = + $this->view->tagAnchor($this->_url(['module' => 'admin', + 'controller' => 'file-manager', + 'action' => 'delete', + 'item' => $userfiles_folder], + null, true), + $this->_('Supprimer')); + + $html [] = $this->_tagNotice($this->_('Vous pouvez supprimer le dossier %s dans l\'explorateur de fichier : %s', + $userfiles_folder, + $delete_folder_anchor)); + } + + return $html; + } } \ No newline at end of file diff --git a/library/digital_resources/DiMusic/Config.php b/library/digital_resources/DiMusic/Config.php index bf5750388727ee271f39c939dfd8811af4bafcfa..5e2e95fb00dd69b8cad7ebb8ad6eeb09aa006e43 100644 --- a/library/digital_resources/DiMusic/Config.php +++ b/library/digital_resources/DiMusic/Config.php @@ -38,6 +38,9 @@ class DiMusic_Config extends Class_DigitalResource_Config { 'Service' => $this->withNameSpace('Service'), 'Batch' => $this->withNameSpace('Batch'), + 'Importer' => $this->withNameSpace('Importer'), + 'Harvester' => $this->withNameSpace('Harvester'), + 'DocTypeLabel' => $this->_('Ressource diMusic'), 'PhoneLabel' => $this->_('Accéder à l\'album'), diff --git a/library/digital_resources/DiMusic/Harvester.php b/library/digital_resources/DiMusic/Harvester.php new file mode 100644 index 0000000000000000000000000000000000000000..a1e75f1141153e5939c1a548e846668f217b9eab --- /dev/null +++ b/library/digital_resources/DiMusic/Harvester.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright (c) 2012-2021, 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 DiMusic_Harvester extends Class_DigitalResource_Harvester_OAI {} \ No newline at end of file diff --git a/library/digital_resources/DiMusic/Importer.php b/library/digital_resources/DiMusic/Importer.php new file mode 100644 index 0000000000000000000000000000000000000000..f3d6fb666ec27b760cc115a1d1834628b605dd0e --- /dev/null +++ b/library/digital_resources/DiMusic/Importer.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright (c) 2012-2021, 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 DiMusic_Importer extends Class_DigitalResource_Importer_OAI{} diff --git a/library/digital_resources/DiMusic/tests/DiMusicTest.php b/library/digital_resources/DiMusic/tests/DiMusicTest.php index 9beb08b88a23e0109f6a910a9897158f1cce3768..e3501f96f24d0cebd5c01c29e532678684f79c1a 100644 --- a/library/digital_resources/DiMusic/tests/DiMusicTest.php +++ b/library/digital_resources/DiMusic/tests/DiMusicTest.php @@ -44,6 +44,11 @@ abstract class DiMusicActivatedTestCase extends AbstractControllerTestCase { ['id' => 1, 'code' => 'DiMusic']) ->permitTo($group, new Class_Entity()); + + $now = new TimeSourceForTest('2021-11-18 14:21:00'); + + DiMusic_Harvester::setTimeSource($now); + DiMusic_Importer::setTimeSource($now); } } @@ -108,7 +113,7 @@ class DiMusicDashboardUnactivatedTest extends Admin_AbstractControllerTestCase { public function setUp() { parent::setUp(); - $this->dispatch('/DiMusic_Plugin', true); + $this->dispatch('/DiMusic_Plugin'); } @@ -128,8 +133,6 @@ class DiMusicDashboardUnactivatedTest extends Admin_AbstractControllerTestCase { class DiMusicDashboardActivatedTest extends DiMusicActivatedTestCase { - protected $_storm_default_to_volatile = true; - public function setUp() { parent::setUp(); @@ -154,7 +157,7 @@ class DiMusicDashboardActivatedTest extends DiMusicActivatedTestCase { 'password' => 'admin', 'role_level' => ZendAfi_Acl_AdminControllerRoles::SUPER_ADMIN])); - $this->dispatch('/DiMusic_Plugin', true); + $this->dispatch('/DiMusic_Plugin'); } @@ -199,9 +202,22 @@ class DiMusicDashboardActivatedTest extends DiMusicActivatedTestCase { public function doctypeImageUrlShouldBePresent() { $this->assertXPath('//h4/img[contains(@src, "/digital-resource/typedoc-icon/id/DiMusic")]'); } -} + /** @test */ + public function firstHarvestErrorMessageShouldBeDisplay() { + $this->assertXPathContentContains('//p[@class="error"]', + 'Cette ressource nécessite un premier moissonnage manuel et un premier import manuel.'); + } + + + /** @test */ + public function contextShouldExpectation() { + $this->assertXPathContentContains('//p[@class="error"]', + 'Vous devez contacter votre hébergeur pour réaliser ces actions.'); + } +} + @@ -657,4 +673,444 @@ class DiMusicNoticeAjaxControllerTest extends AbstractControllerTestCase { public function onloadUtilShouldBeLoaded() { $this->assertXPath('//script[contains(@src, "onload_util")]'); } +} + + + + +abstract class DiMusicOAIFirstHarvestTestCase extends DiMusicActivatedTestCase { + protected + $_logger, + $_log = [], + $_web_client, + $_file_system, + $_userfiles, + $_page1, + $_page2, + $_page1_xml, + $_page2_xml; + + + public function setUp() { + parent::setUp(); + + Class_AdminVar::set('DiMusic_Harvest_Url','https://music.divercities.eu/oai'); + + $this->_page1_xml = file_get_contents(__DIR__ . '/oai_page1.xml'); + $this->_page2_xml = file_get_contents(__DIR__ . '/oai_page2.xml'); + + $this->_page1 = $this + ->mock() + ->whenCalled('getModels') + ->answers(1); + + $this->_page2 = $this + ->mock() + ->whenCalled('getModels') + ->answers(1); + + $this->_userfiles = $this + ->mock() + + ->whenCalled('isWritable')->answers(true) + + ->whenCalled('isDir')->answers(true) + + ->whenCalled('getId')->answers('userfiles') + + ->beStrict(); + + $this->_file_system = $this + ->mock() + + ->whenCalled('disableCache') + ->answers(true) + + ->beStrict(); + + $this->_web_client = $this + ->mock() + ->beStrict(); + + Class_FileManager::setFileSystem($this->_file_system); + Class_WebService_OAI::setWebClient($this->_web_client); + } +} + + + + +class DiMusicHarvesterTest extends DiMusicOAIFirstHarvestTestCase { + + public function setUp() { + parent::setUp(); + + $this->_file_system + ->whenCalled('filesAt')->with('userfiles/dimusic_oai_xml_responses') + ->answers([$this->_page1, $this->_page2]) + + ->whenCalled('directoryAt')->with('userfiles') + ->answers($this->_userfiles) + + ->whenCalled('create')->with('userfiles/dimusic_oai_xml_responses') + ->answers(true) + + ->whenCalled('createImage')->with('userfiles/dimusic_oai_xml_responses/1.xml', + $this->_page1_xml) + ->answers(true) + + ->whenCalled('createImage')->with('userfiles/dimusic_oai_xml_responses/2.xml', + $this->_page2_xml) + ->answers(true); + + $this->_web_client + ->whenCalled('open_url')->with('https://music.divercities.eu/oai?verb=ListRecords&metadataPrefix=oai1dtouch_dc') + ->answers($this->_page1_xml) + + ->whenCalled('open_url') + ->with('https://music.divercities.eu/oai?verb=ListRecords&resumptionToken=oai1dtouch_dc.f%282015-02-09T08%3A46%3A09Z%29.u%282015-02-09T08%3A47%3A27Z%29%3A133') + ->answers($this->_page2_xml); + + $this->_logger = new Class_Cata_LogVolatile; + $harvester = (new DiMusic_Harvester) + ->setLogger($this->_logger); + $harvester->run(); + $this->_log = $this->_logger->getLines(); + } + + + /** @test */ + public function diMusicHarvestShouldCollectOAI() { + $page1_start = substr($this->_page1_xml, 0, 200); + $page1_end = substr($this->_page1_xml, -200); + + $page2_start = substr($this->_page2_xml, 0, 200); + $page2_end = substr($this->_page2_xml, -200); + + $this->assertEquals(["\nDiMusic : Début premier moissonnage de l'OAI à 2021-11-18 14:21:00.", + "\nSuppression des précédents journaux de moissonnage de DiMusic.", + "\nSuppression des fichiers XML existants dans userfiles/dimusic_oai_xml_responses", + "\nDébut du moissonnage.", + "Url : https://music.divercities.eu/oai?verb=ListRecords&metadataPrefix=oai1dtouch_dc", + "Réponse :", + $page1_start, + "[…]", + $page1_end, + "Url : https://music.divercities.eu/oai?verb=ListRecords&resumptionToken=oai1dtouch_dc.f%282015-02-09T08%3A46%3A09Z%29.u%282015-02-09T08%3A47%3A27Z%29%3A133", + "Réponse :", + $page2_start, + "[…]", + $page2_end, + "\n2 fichiers sauvegardés.", + "\nDiMusic : Fin du premier moissonnage de l'OAI à 2021-11-18 14:21:00."], + $this->_log); + } + + + /** @test */ + public function harvestLogShouldHaveBeenCreated() { + $this->assertNotNull(Class_WebService_HarvestLog::find(1)); + } +} + + + + +class DiMusicImporterTest extends DiMusicOAIFirstHarvestTestCase { + + + public function setUp() { + parent::setUp(); + + + $this->fixture(Class_Album::class, + ['id' => 1, + 'titre' => 'old_album', + 'type_doc_id' => 'DiMusic']); + + $this->_page1 + ->whenCalled('getContent') + ->answers($this->_page1_xml) + + ->whenCalled('getPath') + ->answers('userfiles/dimusic_oai_xml_responses/1.xml') + + ->whenCalled('isWritable') + ->answers(true) + + ->whenCalled('isDir') + ->answers(false) + + ->whenCalled('getId') + ->answers('userfiles/dimusic_oai_xml_responses/1.xml') + + ->whenCalled('getName') + ->answers('1.xml'); + + $this->_page2 + ->whenCalled('getContent') + ->answers($this->_page2_xml) + + ->whenCalled('getPath') + ->answers('userfiles/dimusic_oai_xml_responses/2.xml') + + ->whenCalled('isWritable') + ->answers(true) + + ->whenCalled('isDir') + ->answers(false) + + ->whenCalled('getName') + ->answers('2.xml') + + ->whenCalled('getId') + ->answers('userfiles/dimusic_oai_xml_responses/2.xml'); + + $dimusic_oai_xml_responses = $this + ->mock() + ->whenCalled('isWritable') + ->answers(true) + + ->whenCalled('isDir') + ->answers(true) + + ->whenCalled('getId') + ->answers('dimusic_oai_xml_responses'); + + $this->_file_system + ->whenCalled('directoryAt')->with('userfiles/dimusic_oai_xml_responses') + ->answers($dimusic_oai_xml_responses) + + ->whenCalled('filesAt')->with('userfiles/dimusic_oai_xml_responses/done') + ->answers([]) + + ->whenCalled('create')->with('dimusic_oai_xml_responses/done') + ->answers(true) + + ->whenCalled('filesAt')->with('userfiles/dimusic_oai_xml_responses') + ->answers([$this->_page1, $this->_page2]) + + ->whenCalled('rename')->with('userfiles/dimusic_oai_xml_responses/1.xml', + 'userfiles/dimusic_oai_xml_responses/done/1.xml') + ->answers(true) + + ->whenCalled('rename')->with('userfiles/dimusic_oai_xml_responses/2.xml', + 'userfiles/dimusic_oai_xml_responses/done/2.xml') + ->answers(true); + + $this->_logger = new Class_Cata_LogVolatile; + (new DiMusic_Importer) + ->setLogger($this->_logger) + ->run(); + + $this->_log = $this->_logger->getLines(); + } + + + /** @test */ + public function diMusicImporterShouldCreateFourAlbums() { + $this->assertEquals(4, Class_Album::countBy(['type_doc_id' => DiMusic_Config::getInstance()->getDocType()])); + } + + + /** @test */ + public function diMusicImportLogShouldBeHasExpected() { + $this->assertEquals(["\nDiMusic : Début premier import des albums à 2021-11-18 14:21:00.", + "\nDiMusic : suppression des albums existants", + "\n1/1", + "\nDiMusic : création des albums.", + "\nTraitement du fichier : userfiles/dimusic_oai_xml_responses/1.xml. 1/2", + "\nTraitement du fichier : userfiles/dimusic_oai_xml_responses/2.xml. 2/2", + "\nDiMusic : Fin du premier import des albums à 2021-11-18 14:21:00."], + $this->_log); + } +} + + + + +class DiMusicOAIFirstHarvestLoadingTest extends DiMusicActivatedTestCase { + /** @test */ + public function diMusicHarvesterShouldExists() { + $this->assertEquals(['DiMusic' => (new DiMusic_Harvester)], Class_DigitalResource::getInstance()->getHarvesters()); + } + + + /** @test */ + public function diMusicImporterShouldExists() { + $this->assertEquals(['DiMusic' => (new DiMusic_Importer)], Class_DigitalResource::getInstance()->getImporters()); + } +} + + + + +class DiMusicDashboardActivatedAndFirstRunDoneTest extends DiMusicActivatedTestCase { + + public function setUp() { + parent::setUp(); + + $album = $this->fixture('Class_Album', + ['id' => 20, + 'titre' => '10 moutons', + 'type_doc_id' => 'DiMusic', + ]); + + $album->addPosterURI('https://assest.server.eu/cargo/1.jpg') + ->assertSave(); + + Class_WebService_BibNumerique_Vignette::setHttpClient($this->mock() + ->whenCalled('getResponse') + ->answers(new Class_Testing_HttpResponse(['Body' => true]))); + + ZendAfi_Auth::getInstance() + ->logUser($this->fixture('Class_Users', + ['id' => 2, + 'login' => 'admin', + 'password' => 'admin', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::SUPER_ADMIN])); + + $this->fixture(Class_WebService_HarvestLog::class, + ['id' => 1, + 'type_doc' => 'DiMusic']); + + $file_system = $this + ->mock() + + ->whenCalled('disableCache') + ->answers(true) + + ->whenCalled('directoryAt')->with('userfiles/dimusic_oai_xml_responses/done') + ->answers(true) + + ->beStrict(); + + Class_FileManager::setFileSystem($file_system); + + $this->dispatch('/DiMusic_Plugin'); + } + + + public function tearDown() { + Class_WebService_BibNumerique_Vignette::setHttpClient(null); + parent::tearDown(); + } + + + /** @test */ + public function shouldDisplayActivated() { + $this->assertXPathContentContains('//button', 'Activé'); + } + + + /** @test */ + public function firstImportSuccessMessageShouldBeDisplay() { + $this->assertXPathContentContains('//p[@class="success"]', + 'Le premier import d\'albums a été effectué.'); + } + + + /** @test */ + public function firstHarvestSuccessMessageShouldBeDisplay() { + $this->assertXPathContentContains('//p[@class="success"]', + 'Le premier moissonnage a été effectué.'); + } + + + /** @test */ + public function removeDiMusicFilesMessageShouldBeDisplay() { + $this->assertXPathContentContains('//p[@class="notice"]', + 'Vous pouvez supprimer le dossier userfiles/dimusic_oai_xml_responses dans l\'explorateur de fichier :'); + } + + + /** @test */ + public function removeDiMusicLinkShouldBeDisplay() { + $this->assertXPathContentContains('//p[@class="notice"]//a[@href = "/admin/file-manager/delete/item/userfiles%2Fdimusic_oai_xml_responses"]', + 'Supprimer'); + } +} + + + +class DiMusicDashboardActivatedAndFirstRunRunningTest extends DiMusicActivatedTestCase { + + public function setUp() { + parent::setUp(); + + $album = $this->fixture('Class_Album', + ['id' => 20, + 'titre' => '10 moutons', + 'type_doc_id' => 'DiMusic', + ]); + + $album->addPosterURI('https://assest.server.eu/cargo/1.jpg') + ->assertSave(); + + Class_WebService_BibNumerique_Vignette::setHttpClient($this->mock() + ->whenCalled('getResponse') + ->answers(new Class_Testing_HttpResponse(['Body' => true]))); + + ZendAfi_Auth::getInstance() + ->logUser($this->fixture('Class_Users', + ['id' => 2, + 'login' => 'admin', + 'password' => 'admin', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::SUPER_ADMIN])); + + $file_system = $this + ->mock() + + ->whenCalled('disableCache') + ->answers(true) + + ->whenCalled('directoryAt')->with('userfiles/dimusic_oai_xml_responses/done') + ->answers(true) + + ->whenCalled('directoryAt')->with('userfiles/dimusic_oai_xml_responses') + ->answers(true) + + ->whenCalled('countFilesIn')->with('userfiles/dimusic_oai_xml_responses') + ->answers(3) + + ->beStrict(); + + Class_FileManager::setFileSystem($file_system); + + $this->dispatch('/DiMusic_Plugin'); + } + + + public function tearDown() { + Class_WebService_BibNumerique_Vignette::setHttpClient(null); + Class_FileManager::reset(); + parent::tearDown(); + } + + + /** @test */ + public function shouldDisplayActivated() { + $this->assertXPathContentContains('//button', 'Activé'); + } + + + /** @test */ + public function firstImportSuccessMessageShouldBeDisplay() { + $this->assertXPathContentContains('//p[@class="warning"]', + 'Le premier import d\'albums est en cours.'); + } + + + /** @test */ + public function firstHarvestSuccessMessageShouldBeDisplay() { + $this->assertXPathContentContains('//p[@class="warning"]', + 'Le premier moissonnage d\'albums est en cours.'); + } + + + /** @test */ + public function removeDiMusicLinkShouldBeDisplay() { + $this->assertNotXPathContentContains('//p[@class="notice"]//a', + 'Supprimer'); + } } \ No newline at end of file diff --git a/library/digital_resources/DiMusic/tests/oai_page1.xml b/library/digital_resources/DiMusic/tests/oai_page1.xml index 5e92ceb4c116b36df9feaa36311ceb24948d6ad3..c4fb631a08080d1dc0e70840a0183d66867c2c82 100644 --- a/library/digital_resources/DiMusic/tests/oai_page1.xml +++ b/library/digital_resources/DiMusic/tests/oai_page1.xml @@ -7,639 +7,637 @@ <ListRecords> <record> <header status="deleted"> - <identifier>oai:oai1dtouch.com/album2</identifier> - <datestamp>2017-02-22T12:46:19Z</datestamp> - <setSpec>music</setSpec> + <identifier>oai:oai1dtouch.com/album2</identifier> + <datestamp>2017-02-22T12:46:19Z</datestamp> + <setSpec>music</setSpec> </header> </record> <record> <header> - <identifier>oai:oai1dtouch.com:124 - </identifier> - <datestamp>2015-02-09T08:47:27Z - </datestamp> + <identifier>oai:oai1dtouch.com:124 + </identifier> + <datestamp>2015-02-09T08:47:27Z + </datestamp> </header> <metadata> - <oai1dtouch_dc xmlns="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/ http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc.xsd"> - <id>124 - </id> - <icpn>3610159181474 - </icpn> - <title>WOLFEP0241</title> - <description>A Dance House music album</description> - <date>2014-11-03T00:00:00Z - </date> - <label>Wolf Music Recordings - </label> - <cover_url>https://commondatastorage.googleapis.com/music-staging/cargo/medium_3610159181474.jpg - </cover_url> - <url>http://music.1dtouch.com/albums/124 - </url> - <artists> - <artist>Ishmael - </artist> - </artists> - <styles> - <style>Dance - </style> - <style>House - </style> - <style>Deep - </style> - </styles> - <tracks> - <track> - <id>1789AEYU89 - </id> - <isrc>GB2SA1200088 - </isrc> - <position>1 - </position> - <title>Dejong - </title> - <length>PT0H7M20S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200088_320k.mp3 - </url> - <artists> - <artist>Ishmael - </artist> - </artists> - </track> - <track> - <isrc>GB2SA1200089 - </isrc> - <position>2 - </position> - <title>Takoma - </title> - <length>PT0H5M30S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200089_320k.mp3 - </url> - <artists> - <artist>Ishmael - </artist> - </artists> - </track> - <track> - <isrc>GB2SA1200090 - </isrc> - <position>3 - </position> - <title>Ashbury Roll - </title> - <length>PT0H5M26S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200090_320k.mp3 - </url> - <artists> - <artist>Ishmael - </artist> - </artists> - </track> - <track> - <isrc>GB2SA1200091 - </isrc> - <position>4 - </position> - <title>Takoma - </title> - <length>PT0H7M13S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200091_320k.mp3 - </url> - <artists> - <artist>Ishmael - </artist> - </artists> - </track> - </tracks> - </oai1dtouch_dc> + <oai1dtouch_dc xmlns="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/ http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc.xsd"> + <id>124 + </id> + <icpn>3610159181474 + </icpn> + <title>WOLFEP0241</title> + <description>A Dance House music album</description> + <date>2014-11-03T00:00:00Z + </date> + <label>Wolf Music Recordings + </label> + <cover_url>https://commondatastorage.googleapis.com/music-staging/cargo/medium_3610159181474.jpg + </cover_url> + <url>http://music.1dtouch.com/albums/124 + </url> + <artists> + <artist>Ishmael + </artist> + </artists> + <styles> + <style>Dance + </style> + <style>House + </style> + <style>Deep + </style> + </styles> + <tracks> + <track> + <id>1789AEYU89 + </id> + <isrc>GB2SA1200088 + </isrc> + <position>1 + </position> + <title>Dejong + </title> + <length>PT0H7M20S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200088_320k.mp3 + </url> + <artists> + <artist>Ishmael + </artist> + </artists> + </track> + <track> + <isrc>GB2SA1200089 + </isrc> + <position>2 + </position> + <title>Takoma + </title> + <length>PT0H5M30S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200089_320k.mp3 + </url> + <artists> + <artist>Ishmael + </artist> + </artists> + </track> + <track> + <isrc>GB2SA1200090 + </isrc> + <position>3 + </position> + <title>Ashbury Roll + </title> + <length>PT0H5M26S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200090_320k.mp3 + </url> + <artists> + <artist>Ishmael + </artist> + </artists> + </track> + <track> + <isrc>GB2SA1200091 + </isrc> + <position>4 + </position> + <title>Takoma + </title> + <length>PT0H7M13S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200091_320k.mp3 + </url> + <artists> + <artist>Ishmael + </artist> + </artists> + </track> + </tracks> + </oai1dtouch_dc> </metadata> </record> <record> <header> - <identifier>oai:oai1dtouch.com:125 - </identifier> - <datestamp>2015-02-09T08:47:27Z - </datestamp> + <identifier>oai:oai1dtouch.com:125 + </identifier> + <datestamp>2015-02-09T08:47:27Z + </datestamp> </header> <metadata> - <oai1dtouch_dc xmlns="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/ http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc.xsd"> - <id>125 - </id> - <icpn>3610159181993 - </icpn> - <title>Ataché - </title> - <date>2014-11-06T00:00:00Z - </date> - <label>Altino's Music / Couleurs Music Publishing - </label> - <cover_url>https://commondatastorage.googleapis.com/music-staging/cargo/medium_3610159181993.jpg - </cover_url> - <url>http://music.1dtouch.com/albums/125 - </url> - <artists> - <artist>T-Micky - </artist> - </artists> - <styles> - <style>World - </style> - </styles> - <tracks> - <track> - <isrc>GBGYQ1400032 - </isrc> - <position>1 - </position> - <title>Pa kite - </title> - <length>PT0H4M54S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400032_320k.mp3 - </url> - <artists> - <artist>T-Micky - </artist> - </artists> - </track> - <track> - <isrc>FR6V82527830 - </isrc> - <position>2 - </position> - <title>Nou pare - </title> - <length>PT0H3M50S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr6v82527830_320k.mp3 - </url> - <artists> - <artist>T-Micky - </artist> - </artists> - </track> - <track> - <isrc>GBGYQ1400033 - </isrc> - <position>3 - </position> - <title>Manvi kwazé L - </title> - <length>PT0H3M27S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400033_320k.mp3 - </url> - <artists> - <artist>T-Micky - </artist> - </artists> - </track> - <track> - <isrc>GBGYQ1400034 - </isrc> - <position>4 - </position> - <title>Kite L ale - </title> - <length>PT0H4M38S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400034_320k.mp3 - </url> - <artists> - <artist>T-Micky - </artist> - </artists> - </track> - <track> - <isrc>GBGYQ1400035 - </isrc> - <position>5 - </position> - <title>Pale yo - </title> - <length>PT0H3M39S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400035_320k.mp3 - </url> - <artists> - <artist>T-Micky - </artist> - </artists> - </track> - <track> - <isrc>GBGYQ1400036 - </isrc> - <position>6 - </position> - <title>Love Me - </title> - <length>PT0H4M14S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400036_320k.mp3 - </url> - <artists> - <artist>T-Micky - </artist> - </artists> - </track> - <track> - <isrc>GBGYQ1200019 - </isrc> - <position>7 - </position> - <title>N'oublies pas - </title> - <length>PT0H3M50S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1200019_320k.mp3 - </url> - <artists> - <artist>T-Micky - </artist> - </artists> - </track> - <track> - <isrc>GBGYQ1400037 - </isrc> - <position>8 - </position> - <title>Mèt bliye M - </title> - <length>PT0H3M43S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400037_320k.mp3 - </url> - <artists> - <artist>T-Micky - </artist> - </artists> - </track> - <track> - <isrc>GBGYQ1400038 - </isrc> - <position>9 - </position> - <title>Mesi manman - </title> - <length>PT0H4M35S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400038_320k.mp3 - </url> - <artists> - <artist>T-Micky - </artist> - </artists> - </track> - <track> - <isrc>GBGYQ1400039 - </isrc> - <position>10 - </position> - <title>San ou - </title> - <length>PT0H4M14S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400039_320k.mp3 - </url> - <artists> - <artist>T-Micky - </artist> - </artists> - </track> - <track> - <isrc>GBGYQ1400040 - </isrc> - <position>11 - </position> - <title>Sere mwen - </title> - <length>PT0H4M20S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400040_320k.mp3 - </url> - <artists> - <artist>T-Micky - </artist> - </artists> - </track> - <track> - <isrc>GBGYQ1400041 - </isrc> - <position>12 - </position> - <title>Nouvèl la gaye - </title> - <length>PT0H3M44S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400041_320k.mp3 - </url> - <artists> - <artist>T-Micky - </artist> - </artists> - </track> - <track> - <isrc>GBGYQ1400042 - </isrc> - <position>13 - </position> - <title>Yo met pale - </title> - <length>PT0H4M6S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400042_320k.mp3 - </url> - <artists> - <artist>T-Micky - </artist> - </artists> - </track> - </tracks> - </oai1dtouch_dc> + <oai1dtouch_dc xmlns="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/ http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc.xsd"> + <id>125 + </id> + <icpn>3610159181993 + </icpn> + <title>Ataché + </title> + <date>2014-11-06T00:00:00Z + </date> + <label>Altino's Music / Couleurs Music Publishing + </label> + <cover_url>https://commondatastorage.googleapis.com/music-staging/cargo/medium_3610159181993.jpg + </cover_url> + <url>http://music.1dtouch.com/albums/125 + </url> + <artists> + <artist>T-Micky + </artist> + </artists> + <styles> + <style>World + </style> + </styles> + <tracks> + <track> + <isrc>GBGYQ1400032 + </isrc> + <position>1 + </position> + <title>Pa kite + </title> + <length>PT0H4M54S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400032_320k.mp3 + </url> + <artists> + <artist>T-Micky + </artist> + </artists> + </track> + <track> + <isrc>FR6V82527830 + </isrc> + <position>2 + </position> + <title>Nou pare + </title> + <length>PT0H3M50S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr6v82527830_320k.mp3 + </url> + <artists> + <artist>T-Micky + </artist> + </artists> + </track> + <track> + <isrc>GBGYQ1400033 + </isrc> + <position>3 + </position> + <title>Manvi kwazé L + </title> + <length>PT0H3M27S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400033_320k.mp3 + </url> + <artists> + <artist>T-Micky + </artist> + </artists> + </track> + <track> + <isrc>GBGYQ1400034 + </isrc> + <position>4 + </position> + <title>Kite L ale + </title> + <length>PT0H4M38S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400034_320k.mp3 + </url> + <artists> + <artist>T-Micky + </artist> + </artists> + </track> + <track> + <isrc>GBGYQ1400035 + </isrc> + <position>5 + </position> + <title>Pale yo + </title> + <length>PT0H3M39S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400035_320k.mp3 + </url> + <artists> + <artist>T-Micky + </artist> + </artists> + </track> + <track> + <isrc>GBGYQ1400036 + </isrc> + <position>6 + </position> + <title>Love Me + </title> + <length>PT0H4M14S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400036_320k.mp3 + </url> + <artists> + <artist>T-Micky + </artist> + </artists> + </track> + <track> + <isrc>GBGYQ1200019 + </isrc> + <position>7 + </position> + <title>N'oublies pas + </title> + <length>PT0H3M50S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1200019_320k.mp3 + </url> + <artists> + <artist>T-Micky + </artist> + </artists> + </track> + <track> + <isrc>GBGYQ1400037 + </isrc> + <position>8 + </position> + <title>Mèt bliye M + </title> + <length>PT0H3M43S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400037_320k.mp3 + </url> + <artists> + <artist>T-Micky + </artist> + </artists> + </track> + <track> + <isrc>GBGYQ1400038 + </isrc> + <position>9 + </position> + <title>Mesi manman + </title> + <length>PT0H4M35S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400038_320k.mp3 + </url> + <artists> + <artist>T-Micky + </artist> + </artists> + </track> + <track> + <isrc>GBGYQ1400039 + </isrc> + <position>10 + </position> + <title>San ou + </title> + <length>PT0H4M14S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400039_320k.mp3 + </url> + <artists> + <artist>T-Micky + </artist> + </artists> + </track> + <track> + <isrc>GBGYQ1400040 + </isrc> + <position>11 + </position> + <title>Sere mwen + </title> + <length>PT0H4M20S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400040_320k.mp3 + </url> + <artists> + <artist>T-Micky + </artist> + </artists> + </track> + <track> + <isrc>GBGYQ1400041 + </isrc> + <position>12 + </position> + <title>Nouvèl la gaye + </title> + <length>PT0H3M44S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400041_320k.mp3 + </url> + <artists> + <artist>T-Micky + </artist> + </artists> + </track> + <track> + <isrc>GBGYQ1400042 + </isrc> + <position>13 + </position> + <title>Yo met pale + </title> + <length>PT0H4M6S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gbgyq1400042_320k.mp3 + </url> + <artists> + <artist>T-Micky + </artist> + </artists> + </track> + </tracks> + </oai1dtouch_dc> </metadata> </record> <record> <header> - <identifier>oai:oai1dtouch.com:126 - </identifier> - <datestamp>2015-02-09T08:47:27Z - </datestamp> + <identifier>oai:oai1dtouch.com:126 + </identifier> + <datestamp>2015-02-09T08:47:27Z + </datestamp> </header> <metadata> - <oai1dtouch_dc xmlns="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/ http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc.xsd"> - <id>126 - </id> - <icpn>3610159198724 - </icpn> - <title>Impact - </title> - <date>2015-01-12T00:00:00Z - </date> - <label>Karlito - </label> - <cover_url>https://commondatastorage.googleapis.com/music-staging/cargo/medium_3610159198724.jpg - </cover_url> - <url>http://music.1dtouch.com/albums/126 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - <styles> - <style>Hip Hop - </style> - <style>French Hip Hop - </style> - </styles> - <tracks> - <track> - <isrc>FR10S1493172 - </isrc> - <position>1 - </position> - <title>Undercover - </title> - <length>PT0H3M22S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493172_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - <track> - <isrc>FR10S1493173 - </isrc> - <position>2 - </position> - <title>Le zoo - </title> - <length>PT0H3M10S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493173_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - <track> - <isrc>FR10S1493174 - </isrc> - <position>3 - </position> - <title>Continue - </title> - <length>PT0H4M17S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493174_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - <track> - <isrc>FR10S1493175 - </isrc> - <position>4 - </position> - <title>A la kiss - </title> - <length>PT0H3M6S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493175_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - <track> - <isrc>FR10S1493176 - </isrc> - <position>5 - </position> - <title>Banga - </title> - <length>PT0H1M41S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493176_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - <track> - <isrc>FR10S1493177 - </isrc> - <position>6 - </position> - <title>Ego - </title> - <length>PT0H3M37S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493177_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - <track> - <isrc>FR10S1493178 - </isrc> - <position>7 - </position> - <title>O.Dog Psycho - </title> - <length>PT0H3M17S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493178_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - <track> - <isrc>FR10S1493179 - </isrc> - <position>8 - </position> - <title>Affranchis - </title> - <length>PT0H3M12S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493179_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - <track> - <isrc>FR10S1493180 - </isrc> - <position>9 - </position> - <title>Biz Biz - </title> - <length>PT0H1M22S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493180_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - <track> - <isrc>FR10S1493181 - </isrc> - <position>10 - </position> - <title>Ghetto Youth - </title> - <length>PT0H3M42S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493181_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - <track> - <isrc>FR10S1493182 - </isrc> - <position>11 - </position> - <title>Défoncer - </title> - <length>PT0H3M5S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493182_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - <track> - <isrc>FR10S1493183 - </isrc> - <position>12 - </position> - <title>Illimité - </title> - <length>PT0H4M22S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493183_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - <track> - <isrc>FR10S1493184 - </isrc> - <position>13 - </position> - <title>No Drama - </title> - <length>PT0H3M35S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493184_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - <track> - <isrc>FR10S1493185 - </isrc> - <position>14 - </position> - <title>La folie - </title> - <length>PT0H3M48S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493185_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - <track> - <isrc>FR10S1493186 - </isrc> - <position>15 - </position> - <title>Victoria - </title> - <length>PT0H4M46S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493186_320k.mp3 - </url> - <artists> - <artist>Karlito - </artist> - </artists> - </track> - </tracks> - </oai1dtouch_dc> + <oai1dtouch_dc xmlns="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/ http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc.xsd"> + <id>126 + </id> + <icpn>3610159198724 + </icpn> + <title>Impact + </title> + <date>2015-01-12T00:00:00Z + </date> + <label>Karlito + </label> + <cover_url>https://commondatastorage.googleapis.com/music-staging/cargo/medium_3610159198724.jpg + </cover_url> + <url>http://music.1dtouch.com/albums/126 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + <styles> + <style>Hip Hop + </style> + <style>French Hip Hop + </style> + </styles> + <tracks> + <track> + <isrc>FR10S1493172 + </isrc> + <position>1 + </position> + <title>Undercover + </title> + <length>PT0H3M22S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493172_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + <track> + <isrc>FR10S1493173 + </isrc> + <position>2 + </position> + <title>Le zoo + </title> + <length>PT0H3M10S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493173_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + <track> + <isrc>FR10S1493174 + </isrc> + <position>3 + </position> + <title>Continue + </title> + <length>PT0H4M17S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493174_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + <track> + <isrc>FR10S1493175 + </isrc> + <position>4 + </position> + <title>A la kiss + </title> + <length>PT0H3M6S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493175_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + <track> + <isrc>FR10S1493176 + </isrc> + <position>5 + </position> + <title>Banga + </title> + <length>PT0H1M41S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493176_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + <track> + <isrc>FR10S1493177 + </isrc> + <position>6 + </position> + <title>Ego + </title> + <length>PT0H3M37S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493177_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + <track> + <isrc>FR10S1493178 + </isrc> + <position>7 + </position> + <title>O.Dog Psycho + </title> + <length>PT0H3M17S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493178_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + <track> + <isrc>FR10S1493179 + </isrc> + <position>8 + </position> + <title>Affranchis + </title> + <length>PT0H3M12S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493179_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + <track> + <isrc>FR10S1493180 + </isrc> + <position>9 + </position> + <title>Biz Biz + </title> + <length>PT0H1M22S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493180_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + <track> + <isrc>FR10S1493181 + </isrc> + <position>10 + </position> + <title>Ghetto Youth + </title> + <length>PT0H3M42S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493181_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + <track> + <isrc>FR10S1493182 + </isrc> + <position>11 + </position> + <title>Défoncer + </title> + <length>PT0H3M5S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493182_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + <track> + <isrc>FR10S1493183 + </isrc> + <position>12 + </position> + <title>Illimité + </title> + <length>PT0H4M22S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493183_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + <track> + <isrc>FR10S1493184 + </isrc> + <position>13 + </position> + <title>No Drama + </title> + <length>PT0H3M35S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493184_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + <track> + <isrc>FR10S1493185 + </isrc> + <position>14 + </position> + <title>La folie + </title> + <length>PT0H3M48S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493185_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + <track> + <isrc>FR10S1493186 + </isrc> + <position>15 + </position> + <title>Victoria + </title> + <length>PT0H4M46S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/fr10s1493186_320k.mp3 + </url> + <artists> + <artist>Karlito + </artist> + </artists> + </track> + </tracks> + </oai1dtouch_dc> </metadata> </record> - - -<resumptionToken>oai1dtouch_dc.f(2015-02-09T08:46:09Z).u(2015-02-09T08:47:27Z):133</resumptionToken></ListRecords></OAI-PMH> + <resumptionToken>oai1dtouch_dc.f(2015-02-09T08:46:09Z).u(2015-02-09T08:47:27Z):133</resumptionToken></ListRecords></OAI-PMH> diff --git a/library/digital_resources/DiMusic/tests/oai_page2.xml b/library/digital_resources/DiMusic/tests/oai_page2.xml index bfa106a4d517a166463d0273dcf2a9036177630d..ffd514a10980087d4dd4bedb193b34fad3c0527a 100644 --- a/library/digital_resources/DiMusic/tests/oai_page2.xml +++ b/library/digital_resources/DiMusic/tests/oai_page2.xml @@ -7,107 +7,107 @@ <ListRecords> <record> <header> - <identifier>oai:oai1dtouch.com:128 - </identifier> - <datestamp>2015-02-09T08:47:27Z - </datestamp> + <identifier>oai:oai1dtouch.com:128 + </identifier> + <datestamp>2015-02-09T08:47:27Z + </datestamp> </header> <metadata> - <oai1dtouch_dc xmlns="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/ http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc.xsd"> - <id>128 - </id> - <icpn>3610159181474 - </icpn> - <title>WOLFEP026 - </title> - <date>2014-11-03T00:00:00Z - </date> - <label>Wolf Music Recordings - </label> - <cover_url>https://commondatastorage.googleapis.com/music-staging/cargo/medium_3610159181474.jpg - </cover_url> - <url>http://music.1dtouch.com/albums/124 - </url> - <artists> - <artist>Ishmael - </artist> - </artists> - <styles> - <style>Dance - </style> - <style>House - </style> - <style>Deep - </style> - </styles> - <tracks> - <track> - <isrc>GB2SA1200088 - </isrc> - <position>1 - </position> - <title>Dejong - </title> - <length>PT0H7M20S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200088_320k.mp3 - </url> - <artists> - <artist>Ishmael - </artist> - </artists> - </track> - <track> - <isrc>GB2SA1200089 - </isrc> - <position>2 - </position> - <title>Takoma - </title> - <length>PT0H5M30S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200089_320k.mp3 - </url> - <artists> - <artist>Ishmael - </artist> - </artists> - </track> - <track> - <isrc>GB2SA1200090 - </isrc> - <position>3 - </position> - <title>Ashbury Roll - </title> - <length>PT0H5M26S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200090_320k.mp3 - </url> - <artists> - <artist>Ishmael - </artist> - </artists> - </track> - <track> - <isrc>GB2SA1200091 - </isrc> - <position>4 - </position> - <title>Takoma - </title> - <length>PT0H7M13S - </length> - <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200091_320k.mp3 - </url> - <artists> - <artist>Ishmael - </artist> - </artists> - </track> - </tracks> - </oai1dtouch_dc> + <oai1dtouch_dc xmlns="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc/ http://dev.1dtouch.com/OAI/2.0/oai1dtouch_dc.xsd"> + <id>128 + </id> + <icpn>3610159181474 + </icpn> + <title>WOLFEP026 + </title> + <date>2014-11-03T00:00:00Z + </date> + <label>Wolf Music Recordings + </label> + <cover_url>https://commondatastorage.googleapis.com/music-staging/cargo/medium_3610159181474.jpg + </cover_url> + <url>http://music.1dtouch.com/albums/124 + </url> + <artists> + <artist>Ishmael + </artist> + </artists> + <styles> + <style>Dance + </style> + <style>House + </style> + <style>Deep + </style> + </styles> + <tracks> + <track> + <isrc>GB2SA1200088 + </isrc> + <position>1 + </position> + <title>Dejong + </title> + <length>PT0H7M20S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200088_320k.mp3 + </url> + <artists> + <artist>Ishmael + </artist> + </artists> + </track> + <track> + <isrc>GB2SA1200089 + </isrc> + <position>2 + </position> + <title>Takoma + </title> + <length>PT0H5M30S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200089_320k.mp3 + </url> + <artists> + <artist>Ishmael + </artist> + </artists> + </track> + <track> + <isrc>GB2SA1200090 + </isrc> + <position>3 + </position> + <title>Ashbury Roll + </title> + <length>PT0H5M26S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200090_320k.mp3 + </url> + <artists> + <artist>Ishmael + </artist> + </artists> + </track> + <track> + <isrc>GB2SA1200091 + </isrc> + <position>4 + </position> + <title>Takoma + </title> + <length>PT0H7M13S + </length> + <url>https://commondatastorage.googleapis.com/music-staging/cargo/gb2sa1200091_320k.mp3 + </url> + <artists> + <artist>Ishmael + </artist> + </artists> + </track> + </tracks> + </oai1dtouch_dc> </metadata> </record> -<resumptionToken></resumptionToken> + <resumptionToken></resumptionToken> </ListRecords></OAI-PMH> diff --git a/scripts/dimusic_first_harvest.php b/scripts/dimusic_first_harvest.php new file mode 100644 index 0000000000000000000000000000000000000000..d613ec5506b259236f7c08644da8463f7dbe8e17 --- /dev/null +++ b/scripts/dimusic_first_harvest.php @@ -0,0 +1,25 @@ +<?php +require('console.php'); + +class Write_Log_In_Temp { + protected $_path = './temp/dimusic_harvest_log.txt'; + + public function __construct() { + file_put_contents($this->_path, + ''); + } + + + public function log($message) { + file_put_contents($this->_path, + $message . "\n", + FILE_APPEND); + } +} + +Class_DigitalResource::getInstance()->getHarvesters(); + +(new Dimusic_Harvester) + ->setLogger(new Write_Log_In_Temp) + ->run(); +?> \ No newline at end of file diff --git a/scripts/dimusic_first_import.php b/scripts/dimusic_first_import.php new file mode 100644 index 0000000000000000000000000000000000000000..1bbcf67d5615290196a3e93d29ed22b36914acb9 --- /dev/null +++ b/scripts/dimusic_first_import.php @@ -0,0 +1,25 @@ +<?php +require('console.php'); + +class Write_Log_In_Temp { + protected $_path = './temp/dimusic_import_log.txt'; + + public function __construct() { + file_put_contents($this->_path, + ''); + } + + + public function log($message) { + file_put_contents($this->_path, + $message . "\n", + FILE_APPEND); + } +} + +Class_DigitalResource::getInstance()->getImporters(); + +(new Dimusic_Importer) + ->setLogger(new Write_Log_In_Temp) + ->run(); +?> \ No newline at end of file diff --git a/tests/TearDown.php b/tests/TearDown.php new file mode 100644 index 0000000000000000000000000000000000000000..19532ce8e10cc964df0ae24c58638ac109e2511b --- /dev/null +++ b/tests/TearDown.php @@ -0,0 +1,110 @@ +<?php +/** + * Copyright (c) 2012-2021, 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 TearDown { + + public function __construct($volatile_status, $sql = null, $cfg = null) { + $this->_reset($volatile_status, + $sql, + $cfg); + } + + + protected function _reset($volatile_status, $sql, $cfg) { + if ($volatile_status) { + Storm_Model_Loader::defaultToDb(); + Class_Versions::defaultToFile(); + } + + if ($sql) + Zend_Registry::set('sql', $sql); + + if ($cfg) + Zend_Registry::set('cfg', $cfg); + + Bokeh_Engine::reset(); + + Class_Album::setFileSystem(null); + + Class_Codification::reset(); + Class_Codification::resetInstance(); + Class_CommSigb::setInstance(null); + Class_Cosmogramme_LandingDirectory::reset(); + Class_Cosmogramme_Generator_KindsTask::setDbAdapter(null); + Class_Crypt::setPhpCommand(null); + + Class_DigitalResource::resetInstance(); + + Class_I18n::reset(); + + Class_FederationReview::resetInstance(); + Class_FileManager::reset(); + + Class_Log::resetInstance(); + + Class_MoteurRecherche::resetInstance(); + Class_MoteurRecherche::setTimeSource(null); + Class_MoteurRecherche_FacetsByCount::reset(); + Class_MoteurRecherche_Facettes::reset(); + + Class_Notice_Thumbnail_ResizeImage::reset(); + Class_Notice_Xsl::reset(); + Class_Notice::setTimeSource(null); + Class_Notice_Facette::reset(); + + Class_Profil::getCurrentProfil()->clearInstanceCache(); + Class_Profil::clearCache(); + + Class_ScriptLoader::resetInstance(); + + Class_Systeme_Report_Portal::setIp(null); + Class_Systeme_ModulesMenu::reset(); + Class_Systeme_Widget_Abstract::reset(); + Class_Systeme_ModulesAccueil::reset(); + + Class_Template::reset(); + + Class_User_Settings::clearCache(); + + Class_Url::setBaseUrl(null); + Class_Url::setPhpMode(null); + + Class_WebService_Abstract::resetHttpClient(); + Class_WebService_Afi::setHttpClient(null); + Class_WebService_Afi::setKey(null); + Class_WebService_AllServices::setHttpClient(null); + Class_WebService_BibNumerique_Vignette::resetInstance(); + Class_WebService_BibNumerique_Vignette::resetHttpClient(); + Class_WebService_SIGB_Nanook::reset(); + Class_WebService_SIGB_Nanook_PatronPasswordNotSecure::resetInstance(); + Class_WebService_SIGB_AbstractService::setLogger(null); + Class_WebService_SIGB_AbstractRESTService::shouldThrowError(false); + + Intonation_Library_Record::reset(); + + Storm_Model_Abstract::unsetLoaders(); + + ZendAfi_Form_Element_Captcha::reset(); + ZendAfi_Acl_AdminControllerGroup::setAcl(null); + ZendAfi_Acl_AdminControllerRoles::reset(); + } +} diff --git a/tests/application/modules/AbstractControllerTestCase.php b/tests/application/modules/AbstractControllerTestCase.php index b1f1e9e17521eff60c089d52eb6a29ec8d829d47..48ae2d067ecd3906722a44bdc934fe4423be4966 100644 --- a/tests/application/modules/AbstractControllerTestCase.php +++ b/tests/application/modules/AbstractControllerTestCase.php @@ -164,58 +164,9 @@ abstract class AbstractControllerTestCase extends Zend_Test_PHPUnit_ControllerTe public function tearDown() { - if ($this->_storm_default_to_volatile) { - Storm_Model_Loader::defaultToDb(); - Class_Versions::defaultToFile(); - } - - Storm_Model_Abstract::unsetLoaders(); - Zend_Registry::set('sql', $this->_registry_sql); - Zend_Registry::set('cfg', $this->_registry_cfg); - Class_ScriptLoader::resetInstance(); - Class_Codification::resetInstance(); - Class_MoteurRecherche::resetInstance(); - Class_MoteurRecherche::setTimeSource(null); - Class_WebService_Abstract::resetHttpClient(); - Class_WebService_AllServices::setHttpClient(null); - Class_WebService_Afi::setHttpClient(null); - Class_WebService_Afi::setKey(null); - Class_I18n::reset(); - ZendAfi_Form_Element_Captcha::reset(); - Class_Url::setBaseUrl(null); - Class_Url::setPhpMode(null); - Class_Log::resetInstance(); - Class_WebService_BibNumerique_Vignette::resetInstance(); - Class_WebService_BibNumerique_Vignette::resetHttpClient(); - Class_Notice_Thumbnail_ResizeImage::reset(); - Class_FileManager::reset(); - Class_Notice_Xsl::reset(); - Class_Notice::setTimeSource(null); - Class_CommSigb::setInstance(null); - ZendAfi_Acl_AdminControllerGroup::setAcl(null); - Class_Systeme_ModulesAccueil::reset(); - Class_Album::setFileSystem(null); - Class_Crypt::setPhpCommand(null); - Class_User_Settings::clearCache(); - Class_Profil::getCurrentProfil()->clearInstanceCache(); - Class_Profil::clearCache(); - Class_DigitalResource::resetInstance(); - Class_Systeme_ModulesMenu::reset(); - Class_WebService_SIGB_Nanook::reset(); - Class_WebService_SIGB_Nanook_PatronPasswordNotSecure::resetInstance(); - Class_WebService_SIGB_AbstractService::setLogger(null); - Class_FederationReview::resetInstance(); - Class_Template::reset(); - Class_Systeme_Report_Portal::setIp(null); - Class_Systeme_ModulesMenu::reset(); - Class_MoteurRecherche_FacetsByCount::reset(); - Class_MoteurRecherche_Facettes::reset(); - Class_Notice_Facette::reset(); - Class_Systeme_Widget_Abstract::reset(); - Class_Codification::reset(); - ZendAfi_Acl_AdminControllerRoles::reset(); - Intonation_Library_Record::reset(); - Class_WebService_SIGB_AbstractRESTService::shouldThrowError(false); + new TearDown($this->_storm_default_to_volatile, + $this->_registry_sql, + $this->_registry_cfg); } diff --git a/tests/library/Class/ModelTestCase.php b/tests/library/Class/ModelTestCase.php index 25bb6a495bbfe5e157b6fa95ac539ca2033237d1..703002c6ce3ef4b2441840040eaa27357170b9b9 100644 --- a/tests/library/Class/ModelTestCase.php +++ b/tests/library/Class/ModelTestCase.php @@ -99,28 +99,9 @@ abstract class ModelTestCase extends Storm_Test_ModelTestCase { protected function tearDown() { - Bokeh_Engine::reset(); - Class_Url::setPhpMode(null); - Class_Notice_Thumbnail_ResizeImage::reset(); - Class_Album::setFileSystem(null); - Class_FileManager::reset(); - Class_MoteurRecherche::resetInstance(); - Class_Crypt::setPhpCommand(null); - Class_Cosmogramme_LandingDirectory::reset(); - Class_Cosmogramme_Generator_KindsTask::setDbAdapter(null); - - if($this->_storm_default_to_volatile) { - Storm_Model_Loader::defaultToDb(); - Class_Versions::defaultToFile(); - } - - Storm_Model_Abstract::unsetLoaders(); - Class_Systeme_ModulesAccueil::reset(); - if ($this->_registry_sql) - Zend_Registry::set('sql', $this->_registry_sql); - - Class_Systeme_Report_Portal::setIp(null); - parent::tearDown(); + new TearDown($this->_storm_default_to_volatile, + $this->_registry_sql); + return parent::tearDown(); } diff --git a/tests/scenarios/CiteDeLaMusique/CiteDeLaMusiqueTest.php b/tests/scenarios/CiteDeLaMusique/CiteDeLaMusiqueTest.php index bf1b5fa72ff9fce28d8931d0a047b256518ffa66..251e3321af706384c35899b282bb13a515da0b12 100644 --- a/tests/scenarios/CiteDeLaMusique/CiteDeLaMusiqueTest.php +++ b/tests/scenarios/CiteDeLaMusique/CiteDeLaMusiqueTest.php @@ -63,7 +63,6 @@ class CiteDeLaMusiqueFixtures { $user->beAbonneSIGB() ->assertSave(); - $test->fixture('Class_Profil', ['id' => 5, 'browser' => 'opac', @@ -133,6 +132,9 @@ class CiteDeLaMusiqueDisabledAdminTest extends Admin_AbstractControllerTestCase class CiteDeLaMusiqueModulesControllerTest extends AbstractControllerTestCase { + protected $_storm_default_to_volatile = true; + + public function setUp() { parent::setUp(); CiteDeLaMusiqueFixtures::prepare($this); @@ -172,6 +174,10 @@ class CiteDeLaMusiqueModulesControllerTest extends AbstractControllerTestCase { class CiteDeLaMusiqueRenderAlbumTest extends ViewHelperTestCase { + + protected $_storm_default_to_volatile = true; + + public function setUp() { parent::setUp(); CiteDeLaMusiqueFixtures::prepare($this); @@ -470,7 +476,14 @@ class CiteDeLaMusiqueOAIHarvestTest extends ModelTestCase { ->answers(CiteDeLaMusiqueFixtures::getFixtureContent('cite_de_la_musique_oai.xml')) ->whenCalled('open_url') - ->answers(''); + ->with('https://pad.philharmoniedeparis.fr/EXPLOITATION/oaiserver.ashx?verb=ListRecords&resumptionToken=%21%21videos-concerts-docu-entiers%21100%211061%21Ermes') + ->answers('') + + ->whenCalled('open_url') + ->with('https://pad.philharmoniedeparis.fr/EXPLOITATION/oaiserver.ashx?verb=ListRecords&metadataPrefix=ermes&set=audios-concerts-entiers&from=2017-10-11') + ->answers('') + + ->beStrict(); Class_WebService_BibNumerique_CiteDeLaMusique::setDefaultHttpClient($http_client);