Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
75.93% covered (warning)
75.93%
41 / 54
40.00% covered (danger)
40.00%
2 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
GlossaryController
75.93% covered (warning)
75.93%
41 / 54
40.00% covered (danger)
40.00%
2 / 5
15.36
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
 fetch
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 delete
46.67% covered (danger)
46.67%
7 / 15
0.00% covered (danger)
0.00%
0 / 1
6.43
 create
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
3.01
 update
76.47% covered (warning)
76.47%
13 / 17
0.00% covered (danger)
0.00%
0 / 1
4.21
1<?php
2
3/**
4 * The Admin Glossary 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-01-27
16 */
17
18declare(strict_types=1);
19
20namespace phpMyFAQ\Controller\Administration\Api;
21
22use phpMyFAQ\Controller\AbstractController;
23use phpMyFAQ\Core\Exception;
24use phpMyFAQ\Enums\PermissionType;
25use phpMyFAQ\Filter;
26use phpMyFAQ\Glossary;
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 GlossaryController extends AbstractController
35{
36    public function __construct(
37        private readonly Glossary $glossary,
38    ) {
39        parent::__construct();
40    }
41
42    /**
43     * @throws Exception|\Exception
44     */
45    #[Route(path: 'glossary', name: 'admin.api.glossary', methods: ['GET'])]
46    public function fetch(Request $request): JsonResponse
47    {
48        $this->userHasPermission(PermissionType::GLOSSARY_EDIT);
49
50        $glossaryId = (int) Filter::filterVar($request->attributes->get('glossaryId'), FILTER_VALIDATE_INT);
51        $glossaryLanguage = Filter::filterVar(
52            $request->attributes->get('glossaryLanguage'),
53            FILTER_SANITIZE_SPECIAL_CHARS,
54            '',
55        );
56
57        $this->glossary->setLanguage($glossaryLanguage);
58
59        return $this->json($this->glossary->fetch($glossaryId), Response::HTTP_OK);
60    }
61
62    /**
63     * @throws Exception|\Exception
64     */
65    #[Route(path: 'glossary/delete', name: 'admin.api.glossary.delete', methods: ['DELETE'])]
66    public function delete(Request $request): JsonResponse
67    {
68        $this->userHasPermission(PermissionType::GLOSSARY_DELETE);
69
70        $data = $this->getJsonObject($request);
71
72        $glossaryId = Filter::filterVar($data->id ?? null, FILTER_VALIDATE_INT);
73        $glossaryLanguage = Filter::filterVar($data->lang ?? null, FILTER_SANITIZE_SPECIAL_CHARS, '');
74        $csrfToken = Filter::filterVar($data->csrf ?? null, FILTER_SANITIZE_SPECIAL_CHARS);
75
76        if (!Token::getInstance($this->session)->verifyToken('delete-glossary', $csrfToken)) {
77            return $this->json(['error' => Translation::get(key: 'msgNoPermission')], Response::HTTP_UNAUTHORIZED);
78        }
79
80        if ($glossaryId === null) {
81            return $this->json([
82                'error' => Translation::get(key: 'ad_glossary_delete_error'),
83            ], Response::HTTP_BAD_REQUEST);
84        }
85
86        $this->glossary->setLanguage($glossaryLanguage);
87
88        if ($this->glossary->delete($glossaryId)) {
89            return $this->json(['success' => Translation::get(key: 'ad_glossary_delete_success')], Response::HTTP_OK);
90        }
91
92        return $this->json(['error' => Translation::get(key: 'ad_glossary_delete_error')], Response::HTTP_BAD_REQUEST);
93    }
94
95    /**
96     * @throws Exception|\Exception
97     */
98    #[Route(path: 'glossary/create', name: 'admin.api.glossary.create', methods: ['POST'])]
99    public function create(Request $request): JsonResponse
100    {
101        $this->userHasPermission(PermissionType::GLOSSARY_ADD);
102
103        $data = $this->getJsonObject($request);
104
105        $glossaryLanguage = Filter::filterVar($data->language ?? null, FILTER_SANITIZE_SPECIAL_CHARS, '');
106        $glossaryItem = Filter::filterVar($data->item ?? null, FILTER_SANITIZE_SPECIAL_CHARS, '');
107        $glossaryDefinition = Filter::filterVar($data->definition ?? null, FILTER_SANITIZE_SPECIAL_CHARS, '');
108        $csrfToken = Filter::filterVar($data->csrf ?? null, FILTER_SANITIZE_SPECIAL_CHARS);
109
110        if (!Token::getInstance($this->session)->verifyToken('add-glossary', $csrfToken)) {
111            return $this->json(['error' => Translation::get(key: 'msgNoPermission')], Response::HTTP_UNAUTHORIZED);
112        }
113
114        $this->glossary->setLanguage($glossaryLanguage);
115
116        if ($this->glossary->create($glossaryItem, $glossaryDefinition)) {
117            return $this->json(['success' => Translation::get(key: 'ad_glossary_save_success')], Response::HTTP_OK);
118        }
119
120        return $this->json(['error' => Translation::get(key: 'ad_glossary_save_error')], Response::HTTP_BAD_REQUEST);
121    }
122
123    /**
124     * @throws Exception|\Exception
125     */
126    #[Route(path: 'glossary/update', name: 'admin.api.glossary.update', methods: ['PUT'])]
127    public function update(Request $request): JsonResponse
128    {
129        $this->userHasPermission(PermissionType::GLOSSARY_EDIT);
130
131        $data = $this->getJsonObject($request);
132
133        $glossaryId = Filter::filterVar($data->id ?? null, FILTER_VALIDATE_INT);
134        $glossaryLanguage = Filter::filterVar($data->lang ?? null, FILTER_SANITIZE_SPECIAL_CHARS, '');
135        $glossaryItem = Filter::filterVar($data->item ?? null, FILTER_SANITIZE_SPECIAL_CHARS, '');
136        $glossaryDefinition = Filter::filterVar($data->definition ?? null, FILTER_SANITIZE_SPECIAL_CHARS, '');
137        $csrfToken = Filter::filterVar($data->csrf ?? null, FILTER_SANITIZE_SPECIAL_CHARS);
138
139        if (!Token::getInstance($this->session)->verifyToken('update-glossary', $csrfToken)) {
140            return $this->json(['error' => Translation::get(key: 'msgNoPermission')], Response::HTTP_UNAUTHORIZED);
141        }
142
143        if ($glossaryId === null) {
144            return $this->json([
145                'error' => Translation::get(key: 'ad_glossary_update_error'),
146            ], Response::HTTP_BAD_REQUEST);
147        }
148
149        $this->glossary->setLanguage($glossaryLanguage);
150
151        if ($this->glossary->update($glossaryId, $glossaryItem, $glossaryDefinition)) {
152            return $this->json(['success' => Translation::get(key: 'ad_glossary_update_success')], Response::HTTP_OK);
153        }
154
155        return $this->json(['error' => Translation::get(key: 'ad_glossary_update_error')], Response::HTTP_BAD_REQUEST);
156    }
157}