Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.31% covered (success)
92.31%
36 / 39
33.33% covered (danger)
33.33%
1 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
QuestionController
92.31% covered (success)
92.31%
36 / 39
33.33% covered (danger)
33.33%
1 / 3
13.08
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
 delete
90.91% covered (success)
90.91%
20 / 22
0.00% covered (danger)
0.00%
0 / 1
7.04
 toggle
93.75% covered (success)
93.75%
15 / 16
0.00% covered (danger)
0.00%
0 / 1
5.01
1<?php
2
3/**
4 * The Admin Question 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 2023-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     2023-10-30
16 */
17
18declare(strict_types=1);
19
20namespace phpMyFAQ\Controller\Administration\Api;
21
22use Exception;
23use phpMyFAQ\Controller\AbstractController;
24use phpMyFAQ\Enums\PermissionType;
25use phpMyFAQ\Filter;
26use phpMyFAQ\Question;
27use phpMyFAQ\Session\Token;
28use phpMyFAQ\Translation;
29use Symfony\Component\HttpFoundation\JsonResponse;
30use Symfony\Component\HttpFoundation\Request;
31use Symfony\Component\HttpFoundation\Response;
32use Symfony\Component\Routing\Attribute\Route;
33
34final class QuestionController extends AbstractController
35{
36    public function __construct(
37        private readonly Question $question,
38    ) {
39        parent::__construct();
40    }
41
42    /**
43     * @throws Exception
44     */
45    #[Route(path: 'question/delete', name: 'admin.api.question.delete', methods: ['DELETE'])]
46    public function delete(Request $request): JsonResponse
47    {
48        $this->userHasPermission(PermissionType::QUESTION_DELETE);
49
50        $data = $this->getJsonObject($request);
51        $payload = $data->data ?? null;
52        if (!$payload instanceof \stdClass) {
53            return $this->json(['error' => Translation::get(key: 'msgNoPermission')], Response::HTTP_UNAUTHORIZED);
54        }
55
56        if (!Token::getInstance($this->session)->verifyToken(
57            'delete-questions',
58            (string) ($payload->{'pmf-csrf-token'} ?? ''),
59        )) {
60            return $this->json(['error' => Translation::get(key: 'msgNoPermission')], Response::HTTP_UNAUTHORIZED);
61        }
62
63        $questionIds = $payload->{'questions[]'} ?? null;
64        $question = new Question($this->configuration);
65
66        if (!is_null($questionIds)) {
67            if (!is_array($questionIds)) {
68                $questionIds = [$questionIds];
69            }
70
71            foreach ($questionIds as $questionId) {
72                $questionId = Filter::filterVar($questionId, FILTER_VALIDATE_INT);
73                if (!$questionId) {
74                    continue;
75                }
76
77                $question->delete($questionId);
78            }
79
80            return $this->json(['success' => Translation::get(key: 'ad_open_question_deleted')], Response::HTTP_OK);
81        }
82
83        return $this->json(['error' => Translation::get(key: 'msgNoPermission')], Response::HTTP_UNAUTHORIZED);
84    }
85
86    #[Route(path: 'question/visibility/toggle', name: 'admin.api.question.toggle', methods: ['PUT'])]
87    public function toggle(Request $request): JsonResponse
88    {
89        $this->userHasPermission(PermissionType::QUESTION_ADD);
90
91        $data = $this->getJsonObject($request);
92
93        if (!Token::getInstance($this->session)->verifyToken(
94            'toggle-question-visibility',
95            (string) ($data->csrfToken ?? ''),
96        )) {
97            return $this->json(['error' => Translation::get(key: 'msgNoPermission')], Response::HTTP_UNAUTHORIZED);
98        }
99
100        $questionId = (int) ($data->questionId ?? 0);
101
102        if ($questionId !== 0) {
103            $isVisible = $this->question->getVisibility($questionId);
104            $this->question->setVisibility($questionId, $isVisible === 'N' ? 'Y' : 'N');
105            $translation = $isVisible === 'N'
106                ? Translation::get(key: 'ad_gen_yes')
107                : Translation::get(key: 'ad_gen_no');
108            return $this->json(['success' => $translation], Response::HTTP_OK);
109        }
110
111        return $this->json(['error' => 'toggle not successful'], Response::HTTP_BAD_REQUEST);
112    }
113}