Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
81.82% covered (success)
81.82%
27 / 33
20.00% covered (danger)
20.00%
1 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
StatisticsController
81.82% covered (success)
81.82%
27 / 33
20.00% covered (danger)
20.00%
1 / 5
14.02
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
 truncateSessions
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
3.14
 truncateSearchTerms
90.00% covered (success)
90.00%
9 / 10
0.00% covered (danger)
0.00%
0 / 1
3.01
 clearRatings
85.71% covered (success)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
3.03
 clearVisits
71.43% covered (warning)
71.43%
5 / 7
0.00% covered (danger)
0.00%
0 / 1
3.21
1<?php
2
3/**
4 * The Statistics Controller
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public License,
7 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
8 * obtain one at https://mozilla.org/MPL/2.0/.
9 *
10 * @package   phpMyFAQ
11 * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
12 * @copyright 2024-2026 phpMyFAQ Team
13 * @license   https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
14 * @link      https://www.phpmyfaq.de
15 * @since     2024-04-21
16 */
17
18declare(strict_types=1);
19
20namespace phpMyFAQ\Controller\Administration\Api;
21
22use JsonException;
23use phpMyFAQ\Controller\AbstractController;
24use phpMyFAQ\Core\Exception;
25use phpMyFAQ\Enums\PermissionType;
26use phpMyFAQ\Filter;
27use phpMyFAQ\Helper\StatisticsHelper;
28use phpMyFAQ\Rating;
29use phpMyFAQ\Search;
30use phpMyFAQ\Session\Token;
31use phpMyFAQ\Translation;
32use Symfony\Component\HttpFoundation\JsonResponse;
33use Symfony\Component\HttpFoundation\Request;
34use Symfony\Component\HttpFoundation\Response;
35use Symfony\Component\Routing\Attribute\Route;
36
37final class StatisticsController extends AbstractController
38{
39    public function __construct(
40        private readonly StatisticsHelper $statisticsHelper,
41        private readonly Search $search,
42        private readonly Rating $rating,
43    ) {
44        parent::__construct();
45    }
46
47    /**
48     * @throws Exception|JsonException
49     * @throws \Exception
50     */
51    #[Route(path: 'statistics/sessions', name: 'admin.api.statistics.sessions.truncate', methods: ['DELETE'])]
52    public function truncateSessions(Request $request): JsonResponse
53    {
54        $this->userHasPermission(PermissionType::STATISTICS_VIEWLOGS);
55
56        $data = $this->getJsonObject($request);
57
58        if (!Token::getInstance($this->session)->verifyToken('sessions', (string) ($data->csrfToken ?? ''))) {
59            return $this->json(['error' => Translation::get(key: 'msgNoPermission')], Response::HTTP_UNAUTHORIZED);
60        }
61
62        $month = Filter::filterVar($request->getPayload()->get('month'), FILTER_SANITIZE_SPECIAL_CHARS, '');
63
64        if ($this->statisticsHelper->deleteTrackingFiles($month)) {
65            return $this->json(['success' => Translation::get(key: 'ad_adminlog_delete_success')], Response::HTTP_OK);
66        }
67
68        return $this->json(['error' => 'Cannot delete sessions.'], Response::HTTP_BAD_REQUEST);
69    }
70
71    /**
72     * @throws Exception|JsonException
73     * @throws \Exception
74     */
75    #[Route(path: 'statistics/search-terms', name: 'admin.api.statistics.search-terms.truncate', methods: ['DELETE'])]
76    public function truncateSearchTerms(Request $request): JsonResponse
77    {
78        $this->userHasPermission(PermissionType::STATISTICS_VIEWLOGS);
79
80        $data = $this->getJsonObject($request);
81
82        if (!Token::getInstance($this->session)->verifyToken(
83            'truncate-search-terms',
84            (string) ($data->csrfToken ?? ''),
85        )) {
86            return $this->json(['error' => Translation::get(key: 'msgNoPermission')], Response::HTTP_UNAUTHORIZED);
87        }
88
89        if ($this->search->deleteAllSearchTerms()) {
90            return $this->json(['success' => Translation::get(key: 'ad_searchterm_del_suc')], Response::HTTP_OK);
91        }
92
93        return $this->json(['error' => Translation::get(key: 'ad_searchterm_del_err')], Response::HTTP_BAD_REQUEST);
94    }
95
96    /**
97     * @throws \Exception
98     */
99    #[Route(path: 'statistics/ratings/clear', name: 'admin.api.statistics.ratings.clear', methods: ['DELETE'])]
100    public function clearRatings(Request $request): JsonResponse
101    {
102        $this->userHasPermission(PermissionType::STATISTICS_VIEWLOGS);
103
104        $data = $this->getJsonObject($request);
105
106        if (!Token::getInstance($this->session)->verifyToken('clear-statistics', (string) ($data->csrfToken ?? ''))) {
107            return $this->json(['error' => Translation::get(key: 'msgNoPermission')], Response::HTTP_UNAUTHORIZED);
108        }
109
110        if ($this->rating->deleteAll()) {
111            return $this->json(['success' => Translation::get(key: 'msgDeleteAllVotings')], Response::HTTP_OK);
112        }
113
114        return $this->json(['error' => Translation::get(key: 'msgDeleteAllVotings')], Response::HTTP_BAD_REQUEST);
115    }
116
117    /**
118     * @throws \Exception
119     */
120    #[Route(path: 'statistics/visits/clear', name: 'admin.api.statistics.visits.clear', methods: ['DELETE'])]
121    public function clearVisits(Request $request): JsonResponse
122    {
123        $this->userHasPermission(PermissionType::STATISTICS_VIEWLOGS);
124
125        $data = $this->getJsonObject($request);
126
127        if (!Token::getInstance($this->session)->verifyToken('clear-visits', (string) ($data->csrfToken ?? ''))) {
128            return $this->json(['error' => Translation::get(key: 'msgNoPermission')], Response::HTTP_UNAUTHORIZED);
129        }
130
131        if ($this->statisticsHelper->clearAllVisits()) {
132            return $this->json(['success' => Translation::get(key: 'ad_reset_visits_success')], Response::HTTP_OK);
133        }
134
135        return $this->json(['error' => 'Cannot clear visits.'], Response::HTTP_BAD_REQUEST);
136    }
137}