diff --git a/application/modules/api/controllers/UserController.php b/application/modules/api/controllers/UserController.php index d67f3182243b44e4b37788969f621102d9f57994..7688562b97a07c4168fbdc4fc421386a10a68301 100644 --- a/application/modules/api/controllers/UserController.php +++ b/application/modules/api/controllers/UserController.php @@ -31,6 +31,7 @@ class Api_UserController extends ZendAfi_Controller_Action { $user = Class_Users::getIdentity(); $this->_helper ->json(['account' => ['label' => $user->getNomAff(), + 'login' => $user->getLogin(), 'card' => ['id'=> $user->getIdabon(), 'expire_at' => $user->getDateFin()] ]]); @@ -38,7 +39,49 @@ class Api_UserController extends ZendAfi_Controller_Action { public function loansAction() { - $this->view->loans = (new Class_User_Cards(Class_Users::getIdentity()))->getLoans(); + $this->view->loans = $this->_userCards()->getLoans(); + } + + + public function holdsAction() { + $this->view->holds = $this->_userCards()->getHolds(); + } + + + public function renewLoanAction() { + $cards = $this->_userCards(); + $loan_id = $this->_getParam('id'); + + $status = $cards->renewLoan($loan_id); + + if ($status['statut'] == false) + return $this->_helper->json(['status' => 'error', + 'error' => $status['erreur']]); + + $loan = $cards->getLoans() + ->detect(function($loan) use ($loan_id) + { + return $loan->getId() == $loan_id; + }); + + return $this->_helper->json(['status' => 'renewed', + 'date_due' => $loan->getDateRetourISO8601()]); + } + + + public function cancelHoldAction() { + $status = $this->_userCards() + ->cancelHold($this->_getParam('id')); + + return ($status['statut'] == false) + ? $this->_helper->json(['status' => 'error', + 'error' => $status['erreur']]) + : $this->_helper->json(['status' => 'canceled']); + } + + + protected function _userCards() { + return new Class_User_Cards(Class_Users::getIdentity()); } diff --git a/application/modules/api/views/scripts/user/holds.pjson b/application/modules/api/views/scripts/user/holds.pjson new file mode 100644 index 0000000000000000000000000000000000000000..87732946fb1170d8d50fbf7a5b3c62d234ebddb1 --- /dev/null +++ b/application/modules/api/views/scripts/user/holds.pjson @@ -0,0 +1,3 @@ +{ + "holds": <?php echo $this->holds($this->holds) ?> +} diff --git a/library/Class/WebService/SIGB/Emprunt.php b/library/Class/WebService/SIGB/Emprunt.php index e946729ea042e1c9c401322e220b669e0256df79..05901c3cb2d5d063c4933979de7491adcb10d9e3 100644 --- a/library/Class/WebService/SIGB/Emprunt.php +++ b/library/Class/WebService/SIGB/Emprunt.php @@ -32,6 +32,11 @@ class Class_WebService_SIGB_Emprunt extends Class_WebService_SIGB_ExemplaireOper } + public function getDateRetourISO8601() { + return implode('-', array_reverse(explode('/', $this->getDateRetour()))); + } + + /** * @param string $retour * @return Class_WebService_SIGB_Emprunt diff --git a/library/ZendAfi/View/Helper/Api/Holds.php b/library/ZendAfi/View/Helper/Api/Holds.php new file mode 100644 index 0000000000000000000000000000000000000000..ddafc3d948cd3f7122b1fbee0c5d5b1b9f8a2b43 --- /dev/null +++ b/library/ZendAfi/View/Helper/Api/Holds.php @@ -0,0 +1,51 @@ +<?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_View_Helper_Api_Holds extends Zend_View_Helper_Abstract { + public function holds($holds) { + return json_encode( + $holds->collect([$this, 'holdToArray']) + ->getArrayCopy() + ); + } + + + public function holdToArray($hold) { + $datas = [ + 'id' => $hold->getId(), + 'title' => $hold->getTitre(), + 'author' => $hold->getAuteur(), + 'status' => $hold->getEtat(), + 'held_by' => $hold->getUserFullName(), + 'library' => $hold->getBibliotheque() ]; + + if (!$record = $hold->getNoticeOPAC()) + return $datas; + + $datas['record'] = ['id' => $record->getId()]; + if ($record->hasVignette()) + $datas['record']['thumbnail'] = $record->getUrlVignette(); + + return $datas; + } +} +?> \ No newline at end of file diff --git a/library/ZendAfi/View/Helper/Api/Loans.php b/library/ZendAfi/View/Helper/Api/Loans.php index c4542a247d7c893166d2905a249ba9d1b61b44d3..d90cedf859b652827378b89951947af53c278167 100644 --- a/library/ZendAfi/View/Helper/Api/Loans.php +++ b/library/ZendAfi/View/Helper/Api/Loans.php @@ -30,13 +30,22 @@ class ZendAfi_View_Helper_Api_Loans extends Zend_View_Helper_Abstract { public function loanToArray($loan) { - return [ - 'title' => $loan->getTitre(), - 'author' => $loan->getAuteur(), - 'date_due' => implode('-', array_reverse(explode('/', $loan->getDateRetour()))), - 'loaned_by' => $loan->getUserFullName(), - 'library' => $loan->getBibliotheque() - ]; + $datas = [ + 'id' => $loan->getId(), + 'title' => $loan->getTitre(), + 'author' => $loan->getAuteur(), + 'date_due' => $loan->getDateRetourISO8601(), + 'loaned_by' => $loan->getUserFullName(), + 'library' => $loan->getBibliotheque() ]; + + if (!$record = $loan->getNoticeOPAC()) + return $datas; + + $datas['record'] = ['id' => $record->getId()]; + if ($record->hasVignette()) + $datas['record']['thumbnail'] = $record->getUrlVignette(); + + return $datas; } } ?> \ No newline at end of file diff --git a/tests/application/modules/AbstractControllerTestCase.php b/tests/application/modules/AbstractControllerTestCase.php index aca406855712afce0e1b929e58348b34794a4b34..6ad5af88956c096a4c4c5bd58e4a3a730b2c5fc6 100644 --- a/tests/application/modules/AbstractControllerTestCase.php +++ b/tests/application/modules/AbstractControllerTestCase.php @@ -197,6 +197,7 @@ abstract class AbstractControllerTestCase extends Zend_Test_PHPUnit_ControllerTe Class_WebService_BibNumerique_Vignette::resetInstance(); Class_FileManager::reset(); Class_Notice_Xsl::reset(); + Class_CommSigb::setInstance(null); } diff --git a/tests/scenarios/MobileApplication/UserAccountTest.php b/tests/scenarios/MobileApplication/UserAccountTest.php index 1106b77ecc80507ab00c6787b1d1673f40d79b1d..935ef9517a35a14cc70864501c4d5ad257b0f684 100644 --- a/tests/scenarios/MobileApplication/UserAccountTest.php +++ b/tests/scenarios/MobileApplication/UserAccountTest.php @@ -20,13 +20,17 @@ */ abstract class Scenario_MobileApplication_UserAccountTestCase extends AbstractControllerTestCase { protected - $_storm_default_to_volatile = true; + $_storm_default_to_volatile = true, + $_potter, + $_sigb; public function setUp() { parent::setUp(); $_SERVER['HTTPS'] = 'on'; + Class_CommSigb::setInstance($this->_sigb = $this->mock()); + $puppy = $this->fixture('Class_Users', ['id' => 345, 'pseudo' => 'Puppy', @@ -43,24 +47,40 @@ abstract class Scenario_MobileApplication_UserAccountTestCase extends AbstractCo 'client_id' => 'My mobile app', 'user' => $puppy]); - $potter = new Class_WebService_SIGB_Emprunt('12', new Class_WebService_SIGB_Exemplaire(123)); - $potter + $this->_potter = new Class_WebService_SIGB_Emprunt('12', new Class_WebService_SIGB_Exemplaire(123)); + $this->_potter ->setDateRetour('01/01/1974') - ->setAuteur('J.K.R') ->setBibliotheque('Annecy') - ->getExemplaire()->setTitre('Potter'); + ->getExemplaire() + ->setNoticeOPAC($this->fixture('Class_Notice', + ['id' => 34, + 'url_vignette' => 'http://img.com/potter.jpg', + 'titre_principal' => 'Potter', + 'auteur_principal' => 'J.K.R' ])); $alice = new Class_WebService_SIGB_Emprunt('13', new Class_WebService_SIGB_Exemplaire(456)); $alice ->setDateRetour(date('d/m/Y', strtotime('tomorrow'))) ->getExemplaire()->setTitre('Alice'); - $emprunteur = (new Class_WebService_SIGB_Emprunteur(345, 'puppy')) - ->empruntsAddAll([$potter, $alice]); - - $puppy->setFicheSIGB(['fiche' => $emprunteur]); - $puppy->assertSave(); + $afrodeezia = new Class_WebService_SIGB_Reservation('18', new Class_WebService_SIGB_Exemplaire(938)); + $afrodeezia + ->setBibliotheque('Annecy') + ->setEtat('En attente') + ->getExemplaire() + ->setNoticeOPAC($this->fixture('Class_Notice', + ['id' => 83, + 'url_vignette' => 'http://img.com/marcus.jpg', + 'titre_principal' => 'Afrodeezia', + 'auteur_principal' => 'Marcus Miller' ])); + + $puppy + ->setFicheSigb(['fiche' => + (new Class_WebService_SIGB_Emprunteur(345, 'puppy')) + ->empruntsAddAll([$this->_potter, $alice]) + ->reservationsAddAll([$afrodeezia])]) + ->assertSave(); ZendAfi_Auth::getInstance()->clearIdentity(); } @@ -93,11 +113,14 @@ class Scenario_MobileApplication_UserAccountLoansWithTokenTest extends Scenario_ /** @test */ public function responseShouldContainsPotterLoan() { - $this->assertEquals(['title' => 'Potter', + $this->assertEquals(['id' => '345_12', + 'title' => 'Potter', 'author' => 'J.K.R', 'date_due' => '1974-01-01', 'loaned_by' => 'puppy', - 'library' => 'Annecy' + 'library' => 'Annecy', + 'record' => [ 'id' => '34', + 'thumbnail' => 'http://img.com/potter.jpg' ] ], $this->_json['loans'][0]); } @@ -120,6 +143,61 @@ class Scenario_MobileApplication_UserAccountLoansWithTokenTest extends Scenario_ +class Scenario_MobileApplication_UserAccountRenewTest extends Scenario_MobileApplication_UserAccountTestCase { + /** @test */ + public function resultShouldAnswerSuccess() { + $this->_sigb->whenCalled('prolongerPret') + ->answers(['statut' => true, + 'erreur' => '']); + + $this->_potter->setDateRetour('2018-02-17'); + $this->dispatch('/api/user/renew-loan/id/345_12', + true, + ["Authorization" => "Bearer nonos" , + "Content-Type" => "application/json"]); + + $this->assertEquals(['status' => 'renewed', + 'date_due' => '2018-02-17'], + json_decode($this->_response->getBody(), true)); + } + + + /** @test */ + public function resultShouldAnswerErrorOnSIGBError() { + $this->_sigb->whenCalled('prolongerPret') + ->answers(['statut' => false, + 'erreur' => 'could not renew']); + + $this->dispatch('/api/user/renew-loan/id/345_12', + true, + ["Authorization" => "Bearer nonos" , + "Content-Type" => "application/json"]); + + $this->assertEquals(['status' => 'error', + 'error' => 'could not renew'], + json_decode($this->_response->getBody(), true)); + } + + + /** @test */ + public function resultShouldAnswerErrorOnLoanNotFound() { + $this->dispatch('/api/user/renew-loan/id/666_12', + true, + ["Authorization" => "Bearer nonos" , + "Content-Type" => "application/json"]); + + $this->assertEquals(['status' => 'error', + 'error' => 'Prêt introuvable'], + json_decode($this->_response->getBody(), true)); + } + +} + + + + + + class Scenario_MobileApplication_UserAccountLoansWithoutTokenTest extends Scenario_MobileApplication_UserAccountTestCase { /** @test */ public function withoutAuthorizationShouldAnswerInvalidRequest() { @@ -202,13 +280,13 @@ class Scenario_MobileApplication_UserAccountLoansWithoutTokenTest extends Scenar "Content-Type" => "application/json"]); $loans = json_decode($this->_response->getBody(), true); - $this->assertEquals(['title' => 'Potter', - 'author' => 'J.K.R', - 'date_due' => '1974-01-01', - 'loaned_by' => 'puppy', - 'library' => 'Annecy' - ], - $loans['loans'][0]); + $this->assertArraySubset(['title' => 'Potter', + 'author' => 'J.K.R', + 'date_due' => '1974-01-01', + 'loaned_by' => 'puppy', + 'library' => 'Annecy' + ], + $loans['loans'][0]); } } @@ -389,6 +467,7 @@ class Scenario_MobileApplication_UserAccountWithTokenTest extends Scenario_Mobil /** @test */ public function responseShouldContainsCardValidityAndLabel() { $this->assertEquals(['label' => 'Puppy', + 'login' => 'puppy', 'card' => [ 'id' => '234', 'expire_at' => '2018-02-12'] @@ -396,4 +475,90 @@ class Scenario_MobileApplication_UserAccountWithTokenTest extends Scenario_Mobil $this->_json['account']); } } + + + +class Scenario_MobileApplication_UserAccountHoldsWithTokenTest extends Scenario_MobileApplication_UserAccountTestCase { + protected + $_json; + + public function setUp() { + parent::setUp(); + + $this->dispatch('/api/user/holds', + true, + ["Authorization" => "Bearer nonos" , + "Content-Type" => "application/json"]); + + $this->_json = json_decode($this->_response->getBody(), true); + } + + + /** @test */ + public function responseShouldContainsAfrodeeziaHold() { + $this->assertEquals(['id' => '345_18', + 'title' => 'Afrodeezia', + 'author' => 'Marcus Miller', + 'status' => 'En attente', + 'held_by' => 'puppy', + 'library' => 'Annecy', + 'record' => [ 'id' => '83', + 'thumbnail' => 'http://img.com/marcus.jpg' ] + ], + $this->_json['holds'][0]); + } + +} + + + + +class Scenario_MobileApplication_UserAccountCancelHoldTest extends Scenario_MobileApplication_UserAccountTestCase { + /** @test */ + public function resultShouldAnswerSuccess() { + $this->_sigb->whenCalled('supprimerReservation') + ->answers(['statut' => true, + 'erreur' => '']); + + $this->dispatch('/api/user/cancel-hold/id/345_18', + true, + ["Authorization" => "Bearer nonos" , + "Content-Type" => "application/json"]); + + $this->assertEquals(['status' => 'canceled'], + json_decode($this->_response->getBody(), true)); + } + + + /** @test */ + public function resultShouldAnswerErrorOnSIGBError() { + $this->_sigb->whenCalled('supprimerReservation') + ->answers(['statut' => false, + 'erreur' => 'could not cancel']); + + $this->dispatch('/api/user/cancel-hold/id/345_18', + true, + ["Authorization" => "Bearer nonos" , + "Content-Type" => "application/json"]); + + $this->assertEquals(['status' => 'error', + 'error' => 'could not cancel'], + json_decode($this->_response->getBody(), true)); + } + + + /** @test */ + public function resultShouldAnswerErrorOnHoldNotFound() { + $this->dispatch('/api/user/cancel-hold/id/666_18', + true, + ["Authorization" => "Bearer nonos" , + "Content-Type" => "application/json"]); + + $this->assertEquals(['status' => 'error', + 'error' => 'Réservation introuvable'], + json_decode($this->_response->getBody(), true)); + } + +} + ?> \ No newline at end of file