Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 169 |
|
0.00% |
0 / 9 |
CRAP | |
0.00% |
0 / 1 |
LibraryCardsController | |
0.00% |
0 / 169 |
|
0.00% |
0 / 9 |
2162 | |
0.00% |
0 / 1 |
homeAction | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
6 | |||
editCardAction | |
0.00% |
0 / 31 |
|
0.00% |
0 / 1 |
110 | |||
deleteCardAction | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
12 | |||
adjustCardRedirectUrl | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
selectCardAction | |
0.00% |
0 / 22 |
|
0.00% |
0 / 1 |
42 | |||
connectCardLoginAction | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
connectCardAction | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
processEditLibraryCard | |
0.00% |
0 / 55 |
|
0.00% |
0 / 1 |
240 | |||
processEmailLink | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | |
3 | /** |
4 | * LibraryCards Controller |
5 | * |
6 | * PHP version 8 |
7 | * |
8 | * Copyright (C) Villanova University 2010. |
9 | * Copyright (C) The National Library of Finland 2015-2019. |
10 | * |
11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2, |
13 | * as published by the Free Software Foundation. |
14 | * |
15 | * This program is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | * GNU General Public License for more details. |
19 | * |
20 | * You should have received a copy of the GNU General Public License |
21 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
23 | * |
24 | * @category VuFind |
25 | * @package Controller |
26 | * @author Demian Katz <demian.katz@villanova.edu> |
27 | * @author Ere Maijala <ere.maijala@helsinki.fi> |
28 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
29 | * @link https://vufind.org Main Site |
30 | */ |
31 | |
32 | namespace VuFind\Controller; |
33 | |
34 | use VuFind\Db\Entity\UserEntityInterface; |
35 | use VuFind\Db\Service\UserCardServiceInterface; |
36 | use VuFind\Exception\ILS as ILSException; |
37 | |
38 | /** |
39 | * Controller for the library card functionality. |
40 | * |
41 | * @category VuFind |
42 | * @package Controller |
43 | * @author Demian Katz <demian.katz@villanova.edu> |
44 | * @author Ere Maijala <ere.maijala@helsinki.fi> |
45 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
46 | * @link https://vufind.org Main Site |
47 | */ |
48 | class LibraryCardsController extends AbstractBase |
49 | { |
50 | /** |
51 | * Send user's library cards to the view |
52 | * |
53 | * @return mixed |
54 | */ |
55 | public function homeAction() |
56 | { |
57 | if (!($user = $this->getUser())) { |
58 | return $this->forceLogin(); |
59 | } |
60 | |
61 | // Connect to the ILS for login drivers: |
62 | $catalog = $this->getILS(); |
63 | $cardService = $this->getDbService(UserCardServiceInterface::class); |
64 | |
65 | return $this->createViewModel( |
66 | [ |
67 | 'libraryCards' => $cardService->getLibraryCards($user), |
68 | 'multipleTargets' => $catalog->checkCapability('getLoginDrivers'), |
69 | 'allowConnectingCards' => $this->getAuthManager() |
70 | ->supportsConnectingLibraryCard(), |
71 | ] |
72 | ); |
73 | } |
74 | |
75 | /** |
76 | * Send user's library card to the edit view |
77 | * |
78 | * @return mixed |
79 | */ |
80 | public function editCardAction() |
81 | { |
82 | // User must be logged in to edit library cards: |
83 | if (!($user = $this->getUser())) { |
84 | return $this->forceLogin(); |
85 | } |
86 | |
87 | // Process email authentication: |
88 | if ( |
89 | $this->params()->fromQuery('auth_method') === 'Email' |
90 | && ($hash = $this->params()->fromQuery('hash')) |
91 | ) { |
92 | return $this->processEmailLink($user, $hash); |
93 | } |
94 | |
95 | // Process form submission: |
96 | if ($this->formWasSubmitted()) { |
97 | if ($redirect = $this->processEditLibraryCard($user)) { |
98 | return $redirect; |
99 | } |
100 | } |
101 | |
102 | $id = $this->params()->fromRoute('id', $this->params()->fromQuery('id')); |
103 | $cardService = $this->getDbService(UserCardServiceInterface::class); |
104 | $card = $cardService->getOrCreateLibraryCard($user, $id == 'NEW' ? null : $id); |
105 | |
106 | $target = null; |
107 | $username = $card->getCatUsername(); |
108 | |
109 | $loginSettings = $this->getILSLoginSettings(); |
110 | // Split target and username if multiple login targets are available: |
111 | if ($loginSettings['targets'] && strstr($username, '.')) { |
112 | [$target, $username] = explode('.', $username, 2); |
113 | } |
114 | |
115 | $cardName = $this->params()->fromPost('card_name', $card->getCardName()); |
116 | $username = $this->params()->fromPost('username', $username); |
117 | $target = $this->params()->fromPost('target', $target); |
118 | |
119 | // Send the card to the view: |
120 | return $this->createViewModel( |
121 | [ |
122 | 'card' => $card, |
123 | 'cardName' => $cardName, |
124 | 'target' => $target ?: $loginSettings['defaultTarget'], |
125 | 'username' => $username, |
126 | 'targets' => $loginSettings['targets'], |
127 | 'defaultTarget' => $loginSettings['defaultTarget'], |
128 | 'loginMethod' => $loginSettings['loginMethod'], |
129 | 'loginMethods' => $loginSettings['loginMethods'], |
130 | ] |
131 | ); |
132 | } |
133 | |
134 | /** |
135 | * Creates a confirmation box to delete or not delete the current list |
136 | * |
137 | * @return mixed |
138 | */ |
139 | public function deleteCardAction() |
140 | { |
141 | // User must be logged in to edit library cards: |
142 | if (!($user = $this->getUser())) { |
143 | return $this->forceLogin(); |
144 | } |
145 | |
146 | // Get requested library card ID: |
147 | $cardID = $this->params() |
148 | ->fromPost('cardID', $this->params()->fromQuery('cardID')); |
149 | |
150 | // Have we confirmed this? |
151 | $confirm = $this->params()->fromPost( |
152 | 'confirm', |
153 | $this->params()->fromQuery('confirm') |
154 | ); |
155 | if ($confirm) { |
156 | $this->getDbService(UserCardServiceInterface::class)->deleteLibraryCard($user, $cardID); |
157 | |
158 | // Success Message |
159 | $this->flashMessenger()->addMessage('Library Card Deleted', 'success'); |
160 | // Redirect to MyResearch library cards |
161 | return $this->redirect()->toRoute('librarycards-home'); |
162 | } |
163 | |
164 | // If we got this far, we must display a confirmation message: |
165 | return $this->confirm( |
166 | 'confirm_delete_library_card_brief', |
167 | $this->url()->fromRoute('librarycards-deletecard'), |
168 | $this->url()->fromRoute('librarycards-home'), |
169 | 'confirm_delete_library_card_text', |
170 | ['cardID' => $cardID] |
171 | ); |
172 | } |
173 | |
174 | /** |
175 | * When redirecting after selecting a library card, adjust the URL to make |
176 | * sure it will work correctly. |
177 | * |
178 | * @param string $url URL to adjust |
179 | * |
180 | * @return string |
181 | */ |
182 | protected function adjustCardRedirectUrl($url) |
183 | { |
184 | // If there is pagination in the URL, reset it to page 1, since the |
185 | // new card may have a different number of pages of data: |
186 | return preg_replace('/([&?]page)=[0-9]+/', '$1=1', $url); |
187 | } |
188 | |
189 | /** |
190 | * Activates a library card |
191 | * |
192 | * @return \Laminas\Http\Response |
193 | */ |
194 | public function selectCardAction() |
195 | { |
196 | if (!($user = $this->getUser())) { |
197 | return $this->forceLogin(); |
198 | } |
199 | |
200 | $cardID = $this->params()->fromQuery('cardID'); |
201 | if (null === $cardID) { |
202 | return $this->redirect()->toRoute('myresearch-home'); |
203 | } |
204 | $cardService = $this->getDbService(UserCardServiceInterface::class); |
205 | $cardService->activateLibraryCard($user, $cardID); |
206 | |
207 | // Connect to the ILS and check that the credentials are correct: |
208 | try { |
209 | $catalog = $this->getILS(); |
210 | $patron = $catalog->patronLogin( |
211 | $user->getCatUsername(), |
212 | $this->getILSAuthenticator()->getCatPasswordForUser($user) |
213 | ); |
214 | if (!$patron) { |
215 | $this->flashMessenger() |
216 | ->addMessage('authentication_error_invalid', 'error'); |
217 | } |
218 | } catch (ILSException $e) { |
219 | $this->flashMessenger() |
220 | ->addMessage('authentication_error_technical', 'error'); |
221 | } |
222 | |
223 | $this->setFollowupUrlToReferer(false); |
224 | if ($url = $this->getAndClearFollowupUrl()) { |
225 | return $this->redirect()->toUrl($this->adjustCardRedirectUrl($url)); |
226 | } |
227 | return $this->redirect()->toRoute('myresearch-home'); |
228 | } |
229 | |
230 | /** |
231 | * Redirects to authentication to connect a new library card |
232 | * |
233 | * @return \Laminas\Http\Response |
234 | */ |
235 | public function connectCardLoginAction() |
236 | { |
237 | if (!($user = $this->getUser())) { |
238 | return $this->forceLogin(); |
239 | } |
240 | $url = $this->getServerUrl('librarycards-connectcard'); |
241 | $redirectUrl = $this->getAuthManager()->getSessionInitiator($url); |
242 | if (!$redirectUrl) { |
243 | $this->flashMessenger() |
244 | ->addMessage('authentication_error_technical', 'error'); |
245 | return $this->redirect()->toRoute('librarycards-home'); |
246 | } |
247 | return $this->redirect()->toUrl($redirectUrl); |
248 | } |
249 | |
250 | /** |
251 | * Connects a new library card for authenticated user |
252 | * |
253 | * @return \Laminas\Http\Response |
254 | */ |
255 | public function connectCardAction() |
256 | { |
257 | if (!($user = $this->getUser())) { |
258 | return $this->forceLogin(); |
259 | } |
260 | try { |
261 | $this->getAuthManager()->connectLibraryCard($this->getRequest(), $user); |
262 | } catch (\Exception $ex) { |
263 | $this->flashMessenger()->setNamespace('error') |
264 | ->addMessage($ex->getMessage()); |
265 | } |
266 | return $this->redirect()->toRoute('librarycards-home'); |
267 | } |
268 | |
269 | /** |
270 | * Process the "edit library card" submission. |
271 | * |
272 | * @param UserEntityInterface $user Logged in user |
273 | * |
274 | * @return object|bool Response object if redirect is |
275 | * needed, false if form needs to be redisplayed. |
276 | */ |
277 | protected function processEditLibraryCard($user) |
278 | { |
279 | $cardName = $this->params()->fromPost('card_name', ''); |
280 | $target = $this->params()->fromPost('target', ''); |
281 | $username = $this->params()->fromPost('username', ''); |
282 | $password = $this->params()->fromPost('password', ''); |
283 | $id = $this->params()->fromRoute('id', $this->params()->fromQuery('id')); |
284 | |
285 | if (!$username) { |
286 | $this->flashMessenger() |
287 | ->addMessage('authentication_error_blank', 'error'); |
288 | return false; |
289 | } |
290 | |
291 | if ($target) { |
292 | $username = "$target.$username"; |
293 | } |
294 | |
295 | // Check the credentials if the username is changed or a new password is |
296 | // entered: |
297 | $cardService = $this->getDbService(UserCardServiceInterface::class); |
298 | $card = $cardService->getOrCreateLibraryCard($user, $id == 'NEW' ? null : $id); |
299 | if ($card->getCatUsername() !== $username || trim($password)) { |
300 | // Connect to the ILS and check that the credentials are correct: |
301 | $loginMethod = $this->getILSLoginMethod($target); |
302 | if ( |
303 | 'password' === $loginMethod |
304 | && !$this->getAuthManager()->allowsUserIlsLogin() |
305 | ) { |
306 | throw new \Exception( |
307 | 'Illegal configuration: ' |
308 | . 'password-based library cards and disabled user login' |
309 | ); |
310 | } |
311 | $catalog = $this->getILS(); |
312 | try { |
313 | $patron = $catalog->patronLogin($username, $password); |
314 | } catch (ILSException $e) { |
315 | $this->flashMessenger()->addErrorMessage('ils_connection_failed'); |
316 | return false; |
317 | } |
318 | if ('password' === $loginMethod && !$patron) { |
319 | $this->flashMessenger() |
320 | ->addMessage('authentication_error_invalid', 'error'); |
321 | return false; |
322 | } |
323 | if ('email' === $loginMethod) { |
324 | if ($patron) { |
325 | $info = $patron; |
326 | $info['cardID'] = $id; |
327 | $info['cardName'] = $cardName; |
328 | $emailAuthenticator = $this->getService(\VuFind\Auth\EmailAuthenticator::class); |
329 | $emailAuthenticator->sendAuthenticationLink( |
330 | $info['email'], |
331 | $info, |
332 | ['auth_method' => 'Email'], |
333 | 'editLibraryCard' |
334 | ); |
335 | } |
336 | // Don't reveal the result |
337 | $this->flashMessenger()->addSuccessMessage('email_login_link_sent'); |
338 | return $this->redirect()->toRoute('librarycards-home'); |
339 | } |
340 | } |
341 | |
342 | try { |
343 | $cardService->persistLibraryCardData( |
344 | $user, |
345 | $id == 'NEW' ? null : $id, |
346 | $cardName, |
347 | $username, |
348 | $password |
349 | ); |
350 | } catch (\VuFind\Exception\LibraryCard $e) { |
351 | $this->flashMessenger()->addMessage($e->getMessage(), 'error'); |
352 | return false; |
353 | } |
354 | |
355 | return $this->redirect()->toRoute('librarycards-home'); |
356 | } |
357 | |
358 | /** |
359 | * Process library card addition via an email link |
360 | * |
361 | * @param UserEntityInterface $user User object |
362 | * @param string $hash Hash |
363 | * |
364 | * @return \Laminas\Http\Response Response object |
365 | */ |
366 | protected function processEmailLink($user, $hash) |
367 | { |
368 | $emailAuthenticator = $this->getService(\VuFind\Auth\EmailAuthenticator::class); |
369 | try { |
370 | $info = $emailAuthenticator->authenticate($hash); |
371 | $cardService = $this->getDbService(UserCardServiceInterface::class); |
372 | $cardService->persistLibraryCardData( |
373 | $user, |
374 | 'NEW' === $info['cardID'] ? null : $info['cardID'], |
375 | $info['cardName'], |
376 | $info['cat_username'], |
377 | ' ' |
378 | ); |
379 | } catch (\VuFind\Exception\Auth | \VuFind\Exception\LibraryCard $e) { |
380 | $this->flashMessenger()->addErrorMessage($e->getMessage()); |
381 | } |
382 | |
383 | return $this->redirect()->toRoute('librarycards-home'); |
384 | } |
385 | } |