diff --git a/FEATURES/107087 b/FEATURES/107087 new file mode 100644 index 0000000000000000000000000000000000000000..2bd738944292f94393ec692f1636f11b964e7625 --- /dev/null +++ b/FEATURES/107087 @@ -0,0 +1,10 @@ + '107087' => + ['Label' => $this->_('Export des agendas au format OpenAgenda'), + 'Desc' => $this->_('Exportez vos agendas pour les intégrer dans un logiciel de calendrier ou un autre système d\'information.'), + 'Image' => '', + 'Video' => '', + 'Category' => $this->_('Agenda'), + 'Right' => function($feature_description, $user) {return true;}, + 'Wiki' => '', + 'Test' => '', + 'Date' => '2020-08-13'], \ No newline at end of file diff --git a/VERSIONS_WIP/107087 b/VERSIONS_WIP/107087 new file mode 100644 index 0000000000000000000000000000000000000000..8dc46bc814fb8f77b0133c64f4118a36b03b03c7 --- /dev/null +++ b/VERSIONS_WIP/107087 @@ -0,0 +1 @@ + - ticket #107087 : Export des agendas au format OpenAgenda \ No newline at end of file diff --git a/application/modules/opac/controllers/CmsController.php b/application/modules/opac/controllers/CmsController.php index e743955ef5bd61e7eda00a8f4b94d2b868312141..27b212577a13b24bc16c4c3fc371c59ec757e9cf 100644 --- a/application/modules/opac/controllers/CmsController.php +++ b/application/modules/opac/controllers/CmsController.php @@ -183,6 +183,13 @@ class CmsController extends ZendAfi_Controller_Action { } + public function openagendaAction() { + $profil = Class_Profil::find((int)$this->_getParam('id_profil', 1)); + $id_module = (int)$this->_getParam('id_module'); + $this->_helper->renderOpenagenda($profil, $id_module); + } + + /** * @see ZendAfi_View_Helper_Accueil_MenuVertical */ diff --git a/library/Class/Article/Openagenda.php b/library/Class/Article/Openagenda.php new file mode 100644 index 0000000000000000000000000000000000000000..c5bc39efb9a4726c148e99f5378d6bb66022bdf3 --- /dev/null +++ b/library/Class/Article/Openagenda.php @@ -0,0 +1,130 @@ +<?php +/** + * Copyright (c) 2012-2020, 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_Article_Openagenda { + protected + $_field_map = [ + 'id_article' => 'uid', + 'titre' => 'title', + 'description' => 'description', + 'contenu' => 'html', + 'tags' => 'keywords', + 'date_maj' => 'updatedAt' + ], + $_location_field_map = [ + 'id' => 'uid', + 'libelle' => 'name', + 'adresse' => 'address', + 'code_postal' => 'postalCode', + 'latitude' => 'latitude', + 'longitude' => 'longitude', + 'ville' => 'city', + 'pays' => 'country', + 'telephone' => 'phone', + 'url' => 'website', + 'mail' => 'access' + ], + $_datas, + $_article; + + + public function __construct($article) { + $this->_article = $article; + } + + + public function asOpenagenda() { + $attributes = $this->_article->getRawAttributes(); + $this->_datas = $this->_applyMapping($this->_field_map, $attributes, true); + $this->_datas['updatedAt'] = date('c', strtotime($this->_datas['updatedAt'])); + + $this + ->_applyLocation() + ->_applyTimings() + ->_applyCustomFields(); + + return $this->_datas; + } + + + protected function _applyMapping($map, $datas, $empty_accepted = false) { + $mapped_datas = []; + + $datas = array_intersect_key(array_change_key_case($datas, CASE_LOWER), + $map); + + foreach($datas as $key => $value) + $mapped_datas[$map[$key]] = $value; + + return $empty_accepted + ? $mapped_datas + : array_filter($mapped_datas); + } + + + protected function _applyCustomFields() { + if (!isset($this->_datas['keywords'])) + $this->_datas['keywords'] = ''; + + $values = array_map(function($custom_value) + { + return implode(';', $custom_value->getValueAsArray()); + }, + Class_CustomField_Value::findAllByInstance($this->_article)); + + $this->_datas['keywords'] .= implode (';', array_filter($values)); + + return $this; + } + + + protected function _applyLocation() { + if (!$lieu = $this->_article->getLieu()) + return $this; + + $this->_datas['location'] = $this->_applyMapping($this->_location_field_map, + $lieu->getRawAttributes()); + + return $this; + } + + + protected function _applyTimings() { + if (!($events_debut = $this->_article->getEventsDebut()) + || !($events_fin = $this->_article->getEventsFin())) + return $this; + + $debut = explode(' ', $events_debut); + $fin = explode(' ', $events_fin); + + $this->_datas['firstDate'] = $debut[0]; + $this->_datas['lastDate'] = $fin[0]; + + $this->_datas['firstTimeStart'] = substr($debut[1], 0, 5); + $this->_datas['lastTimeEnd'] = substr($fin[1], 0, 5); + + $this->_datas['timings'] = ['start' => date('c', strtotime($events_debut)), + 'end' => date('c', strtotime($events_fin))]; + + return $this; + } +} diff --git a/library/ZendAfi/Controller/Action/Helper/RenderOpenagenda.php b/library/ZendAfi/Controller/Action/Helper/RenderOpenagenda.php new file mode 100644 index 0000000000000000000000000000000000000000..85a1921261b457f6ddfb0385040b01074e7817e7 --- /dev/null +++ b/library/ZendAfi/Controller/Action/Helper/RenderOpenagenda.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright (c) 2012-2014, 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_Controller_Action_Helper_RenderOpenagenda + extends Zend_Controller_Action_Helper_Abstract { + + public function direct($profil, $module_id) { + $this->_actionController->getHelper('ViewRenderer')->setNoRender(); + $this->_actionController->getResponse()->setHeader('Content-Type', + 'application/json;charset=utf-8'); + + if (!$profil + || (!$preferences = $profil->getModuleAccueilPreferences($module_id, 'CALENDAR'))) + return $this->_actionController->getResponse()->setBody('[]'); + + $articles_json = []; + foreach (Class_Article::getArticlesByPreferences($preferences) as $article) + $articles_json []= (new Class_Article_Openagenda($article))->asOpenagenda(); + + $this->_actionController->getResponse() + ->setBody(json_encode($articles_json)); + } +} diff --git a/tests/application/modules/opac/controllers/CmsControllerCalendarActionTest.php b/tests/application/modules/opac/controllers/CmsControllerCalendarActionTest.php index 6ff1eae9a5d754501a70ddf62e45d662b2e620f7..36ea3eea15bb7b4224cf1aa660172b2a7bb88361 100644 --- a/tests/application/modules/opac/controllers/CmsControllerCalendarActionTest.php +++ b/tests/application/modules/opac/controllers/CmsControllerCalendarActionTest.php @@ -748,11 +748,10 @@ class CmsControllerCalendarActionAjaxLinkTest extends AbstractControllerTestCase -abstract class CmsControllerCalendarActionIcalExportTestCase +abstract class CmsControllerCalendarActionFixturesTestCase extends CmsControllerCalendarActionTestCase { protected - $_ical = '', $_articles_by_pref = []; public function setUp() { @@ -790,7 +789,6 @@ abstract class CmsControllerCalendarActionIcalExportTestCase ->answers($this->_articles_by_pref); $this->_dispatch(); - $this->_ical = $this->_response->getBody(); } @@ -800,7 +798,19 @@ abstract class CmsControllerCalendarActionIcalExportTestCase protected function _dispatch() { $this->dispatch('/cms/ical'); } +} + + +abstract class CmsControllerCalendarActionIcalExportTestCase + extends CmsControllerCalendarActionFixturesTestCase { + + protected + $_ical = ''; + public function setUp(){ + parent::setUp(); + $this->_ical = $this->_response->getBody(); + } /** @test */ public function contentTypeHeaderShouldBeTextCalendarUtf8() { @@ -954,6 +964,164 @@ class CmsControllerCalendarActionIcalExportSimpleTest + +abstract class AbstractCmsControllerCalendarActionOpenagendaExportTestCase + extends CmsControllerCalendarActionFixturesTestCase { + protected $_json_content = []; + + public function setUp() { + parent::setUp(); + $this->_json_content = json_decode($this->_response->getBody(), true); + } + + + protected function _dispatch(){ + $this->dispatch('cms/openagenda'); + } +} + + + + +class CmsControllerCalendarActionOpenagendaExportEmptyDataTest + extends AbstractCmsControllerCalendarActionOpenagendaExportTestCase { + + + /** @test */ + public function headerContentTypeShouldContainsApplicationJson() { + $this->assertHeaderContains('Content-type', 'application/json'); + } + + + /** @test */ + public function withEmptyPrefsJsonContentShouldBeEmpty() { + $this->assertEmpty($this->_json_content); + } + +} + + +class CmsControllerCalendarActionOpenagendaExportSimpleTest + extends AbstractCmsControllerCalendarActionOpenagendaExportTestCase { + + + protected function _prepareFixtures() { + $this->setupCustomFields(); + $this->_nanook2 + ->setCustomField('Theme', ['sigb']) + ->setCustomField('Options "classieuses"', ['wifi','restauration']) + ->saveWithCustomFields(); + + $this->_nanook2 + ->setLieu($this->annecy) + ->setTags('Jeunesse;Interface') + ->setDescription('Une super description') + ->setDateMaj('2018-06-12 12:47:36') + ->assertSave(); + + $this->_articles_by_pref = [$this->_nanook2]; + } + + + /** @test */ + public function headerContentTypeShouldContainsApplicationJson() { + $this->assertHeaderContains('Content-type', 'application/json'); + } + + + /** @test */ + public function uidShouldBe4() { + $this->assertEquals(4, $this->_json_content[0]['uid']); + } + + + /** @test */ + public function titleShouldContainsNanook2EnProd() { + $this->assertContains('Nanook 2 en prod', $this->_json_content[0]['title']); + } + + + /** @test */ + public function htmlShouldContainsYoupi() { + $this->assertContains('youpi !', $this->_json_content[0]['html']); + } + + + /** @test */ + public function descriptionShouldContainsSuperDescription() { + $this->assertContains('super description', $this->_json_content[0]['description']); + } + + + /** @test */ + public function updatedAtShouldBeFoo2018_06_12() { + $this->assertEquals('2018-06-12T12:47:36+02:00', + $this->_json_content[0]['updatedAt']); + } + + + /** @test */ + public function firstDateShouldContains20110217() { + $this->assertEquals('2011-02-17', $this->_json_content[0]['firstDate']); + } + + + /** @test */ + public function firstTimeStartShouldBeMidnight() { + $this->assertEquals('00:00', $this->_json_content[0]['firstTimeStart']); + } + + + /** @test */ + public function lastDateShouldContains20110222() { + $this->assertEquals('2011-02-22', $this->_json_content[0]['lastDate']); + } + + + /** @test */ + public function lastTimeEndShouldBeMidnight() { + $this->assertEquals('00:00', $this->_json_content[0]['lastTimeEnd']); + } + + + /** @test */ + public function timingsShouldContains20110222() { + $this->assertEquals(['start' => '2011-02-17T00:00:00+01:00', + 'end' => '2011-02-22T00:00:00+01:00'], + $this->_json_content[0]['timings']); + } + + + /** @test */ + public function locationShouldBeAnnecy() { + $annecy_place = ['uid' => '41', + 'name' => 'Annecy', + 'address' => 'Rue des tomates', + 'postalCode' => '74000', + 'latitude' => '47.0999715', + 'longitude' => '5.4883906', + 'country' => 'FRANCE']; + + $this->assertEquals($annecy_place, + $this->_json_content[0]['location']); + } + + + /** @test */ + public function keywordsShouldContainsSigb() { + $this->assertContains('sigb', $this->_json_content[0]['keywords']); + } + + + /** @test */ + public function keywordsShouldContainsJeunesse() { + $this->assertContains('Jeunesse', $this->_json_content[0]['keywords']); + } +} + + + + class CmsControllerCalendarActionIcalExportSimpleRecurrentTest extends CmsControllerCalendarActionIcalExportTestCase {