Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
86.67% covered (warning)
86.67%
39 / 45
33.33% covered (danger)
33.33%
1 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
CommentRecord
86.67% covered (warning)
86.67%
39 / 45
33.33% covered (danger)
33.33%
1 / 3
13.40
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 checkCaptcha
50.00% covered (danger)
50.00%
2 / 4
0.00% covered (danger)
0.00%
0 / 1
2.50
 handleRequest
90.00% covered (success)
90.00%
36 / 40
0.00% covered (danger)
0.00%
0 / 1
10.10
1<?php
2
3/**
4 * AJAX handler to comment on a record.
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 2018-2024.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2,
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 * @category VuFind
24 * @package  AJAX
25 * @author   Demian Katz <demian.katz@villanova.edu>
26 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
27 * @link     https://vufind.org/wiki/development Wiki
28 */
29
30namespace VuFind\AjaxHandler;
31
32use Laminas\Mvc\Controller\Plugin\Params;
33use VuFind\Config\AccountCapabilities;
34use VuFind\Controller\Plugin\Captcha;
35use VuFind\Db\Entity\UserEntityInterface;
36use VuFind\Db\Service\CommentsServiceInterface;
37use VuFind\I18n\Translator\TranslatorAwareInterface;
38use VuFind\Ratings\RatingsService;
39use VuFind\Record\Loader as RecordLoader;
40use VuFind\Record\ResourcePopulator;
41
42use function intval;
43
44/**
45 * AJAX handler to comment on a record.
46 *
47 * @category VuFind
48 * @package  AJAX
49 * @author   Demian Katz <demian.katz@villanova.edu>
50 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
51 * @link     https://vufind.org/wiki/development Wiki
52 */
53class CommentRecord extends AbstractBase implements TranslatorAwareInterface
54{
55    use \VuFind\I18n\Translator\TranslatorAwareTrait;
56
57    /**
58     * Constructor
59     *
60     * @param ResourcePopulator        $resourcePopulator   Resource populator service
61     * @param CommentsServiceInterface $commentsService     Comments database service
62     * @param Captcha                  $captcha             Captcha controller plugin
63     * @param ?UserEntityInterface     $user                Logged in user (or null)
64     * @param bool                     $enabled             Are comments enabled?
65     * @param RecordLoader             $recordLoader        Record loader
66     * @param AccountCapabilities      $accountCapabilities Account capabilities helper
67     * @param RatingsService           $ratingsService      Ratings service
68     */
69    public function __construct(
70        protected ResourcePopulator $resourcePopulator,
71        protected CommentsServiceInterface $commentsService,
72        protected Captcha $captcha,
73        protected ?UserEntityInterface $user,
74        protected bool $enabled,
75        protected RecordLoader $recordLoader,
76        protected AccountCapabilities $accountCapabilities,
77        protected RatingsService $ratingsService
78    ) {
79    }
80
81    /**
82     * Is CAPTCHA valid? (Also returns true if CAPTCHA is disabled).
83     *
84     * @return bool
85     */
86    protected function checkCaptcha()
87    {
88        // Not enabled? Report success!
89        if (!$this->captcha->active('userComments')) {
90            return true;
91        }
92        $this->captcha->setErrorMode('none');
93        return $this->captcha->verify();
94    }
95
96    /**
97     * Handle a request.
98     *
99     * @param Params $params Parameter helper from controller
100     *
101     * @return array [response data, HTTP status code]
102     */
103    public function handleRequest(Params $params)
104    {
105        // Make sure comments are enabled:
106        if (!$this->enabled) {
107            return $this->formatResponse(
108                $this->translate('Comments disabled'),
109                self::STATUS_HTTP_BAD_REQUEST
110            );
111        }
112
113        if (!$this->user) {
114            return $this->formatResponse(
115                $this->translate('You must be logged in first'),
116                self::STATUS_HTTP_NEED_AUTH
117            );
118        }
119
120        $id = $params->fromPost('id');
121        $source = $params->fromPost('source', DEFAULT_SEARCH_BACKEND);
122        $comment = $params->fromPost('comment');
123        if (empty($id) || empty($comment)) {
124            return $this->formatResponse(
125                $this->translate('bulk_error_missing'),
126                self::STATUS_HTTP_BAD_REQUEST
127            );
128        }
129        $driver = $this->recordLoader->load($id, $source, false);
130
131        if (!$this->checkCaptcha()) {
132            return $this->formatResponse(
133                $this->translate('captcha_not_passed'),
134                self::STATUS_HTTP_FORBIDDEN
135            );
136        }
137
138        $resource = $this->resourcePopulator->getOrCreateResourceForRecordId($id, $source);
139        $commentId = $this->commentsService->addComment(
140            $comment,
141            $this->user,
142            $resource
143        );
144
145        $rating = $params->fromPost('rating', '');
146        if (
147            $driver->isRatingAllowed()
148            && ('' !== $rating
149            || $this->accountCapabilities->isRatingRemovalAllowed())
150        ) {
151            $this->ratingsService->saveRating(
152                $driver,
153                $this->user->getId(),
154                '' === $rating ? null : intval($rating)
155            );
156        }
157
158        return $this->formatResponse(compact('commentId'));
159    }
160}