diff --git a/nginx.conf b/nginx.conf
index cfad3bc568..613f27d89e 100644
--- a/nginx.conf
+++ b/nginx.conf
@@ -129,7 +129,7 @@ server {
rewrite admin/api/(.*) /admin/api/index.php last;
# Administration pages
- rewrite admin/(attachments|backup|comments|configuration|elasticsearch|export|glossary|group|import|instance|instances|news|password|questions|session-keep-alive|statistics|stopwords|system|tags|update|user) /admin/front.php last;
+ rewrite admin/(attachments|backup|comments|configuration|elasticsearch|export|glossary|group|import|instance|instances|news|password|questions|session-keep-alive|statistics|sticky-faqs|stopwords|system|tags|update|user) /admin/front.php last;
# REST API v3.0 and v3.1
rewrite ^api/v3\.[01]/(.*) /api/index.php last;
diff --git a/phpmyfaq/.htaccess b/phpmyfaq/.htaccess
index 7b3387a1a9..f673055876 100644
--- a/phpmyfaq/.htaccess
+++ b/phpmyfaq/.htaccess
@@ -143,7 +143,7 @@ Header set Access-Control-Allow-Headers "Content-Type, Authorization"
# Administration API
RewriteRule ^admin/api/(.*) admin/api/index.php [L,QSA]
# Administration pages
- RewriteRule ^admin/(attachments|backup|comments|configuration|elasticsearch|export|glossary|group|import|instance|instances|news|password|questions|session-keep-alive|statistics|stopwords|system|tags|update|user) admin/front.php [L,QSA]
+ RewriteRule ^admin/(attachments|backup|comments|configuration|elasticsearch|export|glossary|group|import|instance|instances|news|password|questions|session-keep-alive|statistics|sticky-faqs|stopwords|system|tags|update|user) admin/front.php [L,QSA]
# Private APIs
RewriteRule ^api/(autocomplete|bookmark/delete|bookmark/create|user/data/update|user/password/update|user/request-removal|user/remove-twofactor|contact|voting|register|captcha|share|comment/create|faq/create|question/create|webauthn/prepare|webauthn/register|webauthn/prepare-login|webauthn/login) api/index.php [L,QSA]
# Setup APIs
diff --git a/phpmyfaq/admin/header.php b/phpmyfaq/admin/header.php
index ca3097755a..243928e044 100644
--- a/phpmyfaq/admin/header.php
+++ b/phpmyfaq/admin/header.php
@@ -77,7 +77,8 @@
$secLevelEntries['content'] .= $adminHelper->addMenuEntry(
PermissionType::FAQ_EDIT->value,
'stickyfaqs',
- 'stickyRecordsHeader'
+ 'stickyRecordsHeader',
+ 'sticky-faqs'
);
$secLevelEntries['content'] .= $adminHelper->addMenuEntry('delquestion', 'question', 'ad_menu_open', 'questions');
$secLevelEntries['content'] .= $adminHelper->addMenuEntry('delcomment', 'comments', 'ad_menu_comments', 'comments');
diff --git a/phpmyfaq/admin/index.php b/phpmyfaq/admin/index.php
index 62a54dd934..411d8a44b0 100755
--- a/phpmyfaq/admin/index.php
+++ b/phpmyfaq/admin/index.php
@@ -267,9 +267,6 @@
case 'copyentry':
require 'faqs.editor.php';
break;
- case 'stickyfaqs':
- require 'stickyfaqs.php';
- break;
// category administration
case 'savecategory':
case 'updatecategory':
diff --git a/phpmyfaq/admin/stickyfaqs.php b/phpmyfaq/admin/stickyfaqs.php
deleted file mode 100644
index 4d03cff4e8..0000000000
--- a/phpmyfaq/admin/stickyfaqs.php
+++ /dev/null
@@ -1,47 +0,0 @@
-
- * @copyright 2003-2024 phpMyFAQ Team
- * @license https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
- * @link https://www.phpmyfaq.de
- * @since 2023-12-27
- */
-
-use phpMyFAQ\Faq;
-use phpMyFAQ\Configuration;
-use phpMyFAQ\Template\TwigWrapper;
-use phpMyFAQ\Translation;
-use phpMyFAQ\Session\Token;
-
-if (!defined('IS_VALID_PHPMYFAQ')) {
- http_response_code(400);
- exit();
-}
-
-$faqConfig = Configuration::getConfigurationInstance();
-
-$twig = new TwigWrapper(PMF_ROOT_DIR . '/assets/templates');
-$template = $twig->loadTemplate('@admin/content/stickyfaqs.twig');
-
-$faq = new Faq($faqConfig);
-$stickyData = $faq->getStickyFaqsData();
-
-$templateVars = [
- 'stickyFAQsHeader' => Translation::get('stickyRecordsHeader'),
- 'stickyData' => $stickyData,
- 'sortableDisabled' => ($faqConfig->get('records.orderStickyFaqsCustom') === false) ? 'sortable-disabled' : '',
- 'orderingStickyFaqsActivated' => $faqConfig->get('records.orderStickyFaqsCustom'),
- 'alertMessageStickyFaqsDeactivated' => Translation::get('msgOrderStickyFaqsCustomDeactivated'),
- 'alertMessageNoStickyRecords' => Translation::get('msgNoStickyFaqs'),
- 'csrfToken' => Token::getInstance($container->get('session'))->getTokenString('order-stickyfaqs')
-];
-
-echo $template->render($templateVars);
diff --git a/phpmyfaq/assets/templates/admin/content/sticky-faqs.twig b/phpmyfaq/assets/templates/admin/content/sticky-faqs.twig
new file mode 100644
index 0000000000..e4ec7856b1
--- /dev/null
+++ b/phpmyfaq/assets/templates/admin/content/sticky-faqs.twig
@@ -0,0 +1,35 @@
+{% extends '@admin/index.twig' %}
+
+{% block content %}
+
+
+ {{ stickyFAQsHeader }}
+
+
+
+ {% if orderingStickyFaqsActivated == false %}
+ {{ alertMessageStickyFaqsDeactivated | raw }}
+
+
+ {% endif %}
+
+ {% if stickyData is empty %}
+ {{ alertMessageNoStickyRecords | raw }}
+
+
+ {% endif %}
+
+ {% if orderingStickyFaqsActivated != false %}
+
+ {% endif %}
+{% endblock %}
diff --git a/phpmyfaq/assets/templates/admin/content/stickyfaqs.twig b/phpmyfaq/assets/templates/admin/content/stickyfaqs.twig
deleted file mode 100644
index e9d1687395..0000000000
--- a/phpmyfaq/assets/templates/admin/content/stickyfaqs.twig
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
- {{ stickyFAQsHeader }}
-
-
-
-{% if orderingStickyFaqsActivated == false %}
- {{ alertMessageStickyFaqsDeactivated | raw }}
-
-
-{% endif %}
-
-{% if stickyData is empty %}
- {{ alertMessageNoStickyRecords | raw }}
-
-
-{% endif %}
-
-{% if orderingStickyFaqsActivated != false %}
-
-{% endif %}
diff --git a/phpmyfaq/src/admin-routes.php b/phpmyfaq/src/admin-routes.php
index b24e436f25..6f559b71f5 100644
--- a/phpmyfaq/src/admin-routes.php
+++ b/phpmyfaq/src/admin-routes.php
@@ -34,6 +34,7 @@
use phpMyFAQ\Controller\Administration\SessionKeepAliveController;
use phpMyFAQ\Controller\Administration\StatisticsSearchController;
use phpMyFAQ\Controller\Administration\StatisticsSessionsController;
+use phpMyFAQ\Controller\Administration\StickyFaqsController;
use phpMyFAQ\Controller\Administration\StopWordsController;
use phpMyFAQ\Controller\Administration\SystemInformationController;
use phpMyFAQ\Controller\Administration\TagController;
@@ -65,6 +66,11 @@
'controller' => [BackupController::class, 'restore'],
'methods' => 'POST'
],
+ 'admin.content.sticky-faqs' => [
+ 'path' => '/sticky-faqs',
+ 'controller' => [StickyFaqsController::class, 'index'],
+ 'methods' => 'GET'
+ ],
'admin.comments' => [
'path' => '/comments',
'controller' => [CommentsController::class, 'index'],
diff --git a/phpmyfaq/src/phpMyFAQ/Controller/Administration/AbstractAdministrationController.php b/phpmyfaq/src/phpMyFAQ/Controller/Administration/AbstractAdministrationController.php
index 5d58534e7c..1b11f1440d 100644
--- a/phpmyfaq/src/phpMyFAQ/Controller/Administration/AbstractAdministrationController.php
+++ b/phpmyfaq/src/phpMyFAQ/Controller/Administration/AbstractAdministrationController.php
@@ -90,7 +90,8 @@ protected function getHeader(Request $request): array
$secLevelEntries['content'] .= $adminHelper->addMenuEntry(
PermissionType::FAQ_EDIT->value,
'stickyfaqs',
- 'stickyRecordsHeader'
+ 'stickyRecordsHeader',
+ 'sticky-faqs'
);
$secLevelEntries['content'] .= $adminHelper->addMenuEntry(
'delquestion',
@@ -232,7 +233,6 @@ protected function getHeader(Request $request): array
case 'editentry':
case 'copyentry':
case 'takequestion':
- case 'stickyfaqs':
$contentPage = true;
break;
case 'forms':
@@ -259,6 +259,7 @@ protected function getHeader(Request $request): array
$userPage = true;
break;
case 'admin.attachments':
+ case 'admin.content.sticky-faqs':
case 'admin.comments':
case 'admin.glossary':
case 'admin.news':
diff --git a/phpmyfaq/src/phpMyFAQ/Controller/Administration/Api/FaqController.php b/phpmyfaq/src/phpMyFAQ/Controller/Administration/Api/FaqController.php
index 5a7c662556..87fb207755 100644
--- a/phpmyfaq/src/phpMyFAQ/Controller/Administration/Api/FaqController.php
+++ b/phpmyfaq/src/phpMyFAQ/Controller/Administration/Api/FaqController.php
@@ -504,7 +504,7 @@ public function activate(Request $request): JsonResponse
$faqLanguage = Filter::filterVar($data->faqLanguage, FILTER_SANITIZE_SPECIAL_CHARS);
$checked = Filter::filterVar($data->checked, FILTER_VALIDATE_BOOLEAN);
- if (!Token::getInstance()->verifyToken('faq-overview', $data->csrf)) {
+ if (!Token::getInstance($this->container->get('session'))->verifyToken('faq-overview', $data->csrf)) {
return $this->json(['error' => Translation::get('msgNoPermission')], Response::HTTP_UNAUTHORIZED);
}
@@ -542,7 +542,7 @@ public function sticky(Request $request): JsonResponse
$faqLanguage = Filter::filterVar($data->faqLanguage, FILTER_SANITIZE_SPECIAL_CHARS);
$checked = Filter::filterVar($data->checked, FILTER_VALIDATE_BOOLEAN);
- if (!Token::getInstance()->verifyToken('faq-overview', $data->csrf)) {
+ if (!Token::getInstance($this->container->get('session'))->verifyToken('faq-overview', $data->csrf)) {
return $this->json(['error' => Translation::get('msgNoPermission')], Response::HTTP_UNAUTHORIZED);
}
@@ -582,7 +582,7 @@ public function delete(Request $request): JsonResponse
$faqId = Filter::filterVar($data->faqId, FILTER_VALIDATE_INT);
$faqLanguage = Filter::filterVar($data->faqLanguage, FILTER_SANITIZE_SPECIAL_CHARS);
- if (!Token::getInstance()->verifyToken('faq-overview', $data->csrf)) {
+ if (!Token::getInstance($this->container->get('session'))->verifyToken('faq-overview', $data->csrf)) {
return $this->json(['error' => Translation::get('msgNoPermission')], Response::HTTP_UNAUTHORIZED);
}
@@ -610,7 +610,7 @@ public function search(Request $request): JsonResponse
$data = json_decode($request->getContent());
- if (!Token::getInstance()->verifyToken('edit-faq', $data->csrf)) {
+ if (!Token::getInstance($this->container->get('session'))->verifyToken('edit-faq', $data->csrf)) {
return $this->json(['error' => Translation::get('msgNoPermission')], Response::HTTP_UNAUTHORIZED);
}
@@ -648,7 +648,7 @@ public function saveOrderOfStickyFaqs(Request $request): JsonResponse
$data = json_decode($request->getContent());
- if (!Token::getInstance()->verifyToken('order-stickyfaqs', $data->csrf)) {
+ if (!Token::getInstance($this->container->get('session'))->verifyToken('order-stickyfaqs', $data->csrf)) {
return $this->json(['error' => Translation::get('msgNoPermission')], Response::HTTP_UNAUTHORIZED);
}
@@ -666,12 +666,14 @@ public function import(Request $request): JsonResponse
{
$this->userHasPermission(PermissionType::FAQ_ADD);
+ $session = $this->container->get('session');
+
$file = $request->files->get('file');
if (!isset($file)) {
return $this->json(['error' => 'Bad request: There is no file submitted.'], Response::HTTP_BAD_REQUEST);
}
- if (!Token::getInstance()->verifyToken('importfaqs', $request->request->get('csrf'))) {
+ if (!Token::getInstance($session)->verifyToken('importfaqs', $request->request->get('csrf'))) {
return $this->json(['error' => Translation::get('msgNoPermission')], Response::HTTP_UNAUTHORIZED);
}
diff --git a/phpmyfaq/src/phpMyFAQ/Controller/Administration/StickyFaqsController.php b/phpmyfaq/src/phpMyFAQ/Controller/Administration/StickyFaqsController.php
new file mode 100644
index 0000000000..301ea27fca
--- /dev/null
+++ b/phpmyfaq/src/phpMyFAQ/Controller/Administration/StickyFaqsController.php
@@ -0,0 +1,45 @@
+userHasPermission(PermissionType::FAQ_EDIT);
+
+ $customOrdering = $this->configuration->get('records.orderStickyFaqsCustom');
+
+ return $this->render(
+ '@admin/content/sticky-faqs.twig',
+ [
+ ... $this->getHeader($request),
+ ... $this->getFooter(),
+ 'stickyFAQsHeader' => Translation::get('stickyRecordsHeader'),
+ 'stickyData' => $this->container->get('phpmyfaq.faq')->getStickyFaqsData(),
+ 'sortableDisabled' => ($customOrdering === false) ? 'sortable-disabled' : '',
+ 'orderingStickyFaqsActivated' => $this->configuration->get('records.orderStickyFaqsCustom'),
+ 'alertMessageStickyFaqsDeactivated' => Translation::get('msgOrderStickyFaqsCustomDeactivated'),
+ 'alertMessageNoStickyRecords' => Translation::get('msgNoStickyFaqs'),
+ 'csrfToken' => Token::getInstance($this->container->get('session'))->getTokenString('order-stickyfaqs')
+ ]
+ );
+ }
+}