Skip to content

Commit

Permalink
feat(layout): added support for custom CSS via admin configuration, c…
Browse files Browse the repository at this point in the history
…loses #3017
  • Loading branch information
thorsten committed Jul 8, 2024
1 parent 28771ca commit 1a38ef4
Show file tree
Hide file tree
Showing 43 changed files with 124 additions and 98 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ This is a log of major user-visible changes in each phpMyFAQ release.
- added Kubernetes manifest samples (OWNDOMAINHOME SAS)
- added experimental import of FAQs from CSV (Jan Harms)
- added CSV export of user sessions (Jan Harms)
- added possibility to add custom CSS via admin frontend (Thorsten)
- added experimental support for PHP 8.4 (Thorsten)
- improved installation and update (Thorsten)
- improved SEO support (Thorsten)
Expand Down
13 changes: 9 additions & 4 deletions phpmyfaq/admin/assets/src/configuration/configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
*/

import { Tab } from 'bootstrap';
import { addElement } from '../../../../assets/src/utils';
import { pushErrorNotification, pushNotification } from '../utils';

export const handleConfiguration = async () => {
const configTabList = [].slice.call(document.querySelectorAll('#configuration-list a'));
const result = document.getElementById('pmf-configuration-result');
const language = document.getElementById('pmf-language');
if (configTabList.length) {
let tabLoaded = false;
configTabList.forEach((element) => {
Expand All @@ -32,6 +32,8 @@ export const handleConfiguration = async () => {
switch (target) {
case '#main':
await handleTranslation();
break;
case '#layout':
await handleTemplates();
break;
case '#records':
Expand Down Expand Up @@ -65,7 +67,6 @@ export const handleConfiguration = async () => {
if (!tabLoaded) {
await fetchConfiguration('#main');
await handleTranslation();
await handleTemplates();
}
}
};
Expand Down Expand Up @@ -132,7 +133,7 @@ const handleTranslation = async () => {
};

const handleTemplates = async () => {
const templateSelectBox = document.getElementsByName('edit[main.templateSet]');
const templateSelectBox = document.getElementsByName('edit[layout.templateSet]');
if (templateSelectBox !== null) {
const options = await fetchTemplates();
templateSelectBox[0].insertAdjacentHTML('beforeend', options);
Expand Down Expand Up @@ -207,7 +208,11 @@ const handleSeoMetaTags = async () => {

const fetchConfiguration = async (target) => {
try {
const response = await fetch(`./api/configuration/list/${target.substring(1)}`);
const response = await fetch(`./api/configuration/list/${target.substring(1)}`, {
headers: {
'Accept-Language': language.value,
},
});

if (!response.ok) {
console.error('Request failed!');
Expand Down
9 changes: 1 addition & 8 deletions phpmyfaq/admin/configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,9 @@
$templateVars = [
'adminHeaderConfiguration' => Translation::get('ad_config_edit'),
'csrfToken' => Token::getInstance()->getTokenString('configuration'),
'language' => $faqLangCode,
'adminConfigurationButtonReset' => Translation::get('ad_config_reset'),
'adminConfigurationButtonSave' => Translation::get('ad_config_save'),
'adminConfigurationMainTab' => Translation::get('mainControlCenter'),
'adminConfigurationFaqsTab' => Translation::get('recordsControlCenter'),
'adminConfigurationSearchTab' => Translation::get('searchControlCenter'),
'adminConfigurationSecurityTab' => Translation::get('securityControlCenter'),
'adminConfigurationSpamTab' => Translation::get('spamControlCenter'),
'adminConfigurationSeoTab' => Translation::get('seoCenter'),
'adminConfigurationMailTab' => Translation::get('mailControlCenter'),
'adminConfigurationUpgradeTab' => Translation::get('upgradeControlCenter'),
];

echo $template->render($templateVars);
Expand Down
2 changes: 1 addition & 1 deletion phpmyfaq/admin/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
//
// Set actual template set name
//
TwigWrapper::setTemplateSetName($faqConfig->get('main.templateSet'));
TwigWrapper::setTemplateSetName($faqConfig->get('layout.templateSet'));

//
// Initialize attachment factory
Expand Down
2 changes: 1 addition & 1 deletion phpmyfaq/assets/templates/admin/configuration/macros.twig
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
<span class="form-text">{{ description }}</span>
</label>
<div class="col-6">
<textarea id="edit[{{ key }}]" name="edit[{{ key }}]" rows="4" class="form-control">{{ value|e }}</textarea>
<textarea id="edit[{{ key }}]" name="edit[{{ key }}]" rows="4" class="form-control" spellcheck="false">{{ value|e }}</textarea>
</div>
{% endmacro %}

Expand Down
36 changes: 22 additions & 14 deletions phpmyfaq/assets/templates/admin/configuration/main.twig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<form id="configuration-list" name="configuration-list" method="post" action="#">
<input type="hidden" id="pmf-csrf-token" name="pmf-csrf-token" value="{{ csrfToken }}">
<input type="hidden" id="pmf-language" name="pmf-language" value="{{ language }}">

<div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
Expand Down Expand Up @@ -28,49 +29,49 @@
<li role="presentation" class="nav-item">
<a href="#main" aria-controls="main" role="tab" data-bs-toggle="tab" class="nav-link active">
<i aria-hidden="true" class="bi bi-house-check"></i>
{{ adminConfigurationMainTab }}
{{ 'mainControlCenter' | translate }}
</a>
</li>
<li role="presentation" class="nav-item">
<a href="#records" aria-controls="records" role="tab" data-bs-toggle="tab" class="nav-link">
<i aria-hidden="true" class="bi bi-list"></i>
{{ adminConfigurationFaqsTab }}
{{ 'recordsControlCenter' | translate }}
</a>
</li>
<li role="presentation" class="nav-item">
<a href="#search" aria-controls="search" role="tab" data-bs-toggle="tab" class="nav-link">
<i aria-hidden="true" class="bi bi-search"></i>
{{ adminConfigurationSearchTab }}
{{ 'searchControlCenter' | translate }}
</a>
</li>
<li role="presentation" class="nav-item">
<a href="#security" aria-controls="security" role="tab" data-bs-toggle="tab" class="nav-link">
<i aria-hidden="true" class="bi bi-exclamation-circle"></i>
{{ adminConfigurationSecurityTab }}
{{ 'securityControlCenter' | translate }}
</a>
</li>
<li role="presentation" class="nav-item">
<a href="#spam" aria-controls="spam" role="tab" data-bs-toggle="tab" class="nav-link">
<i aria-hidden="true" class="bi bi-hand-thumbs-down"></i>
{{ adminConfigurationSpamTab }}
{{ 'spamControlCenter' | translate }}
</a>
</li>
<li role="presentation" class="nav-item">
<a href="#seo" aria-controls="seo" role="tab" data-bs-toggle="tab" class="nav-link">
<i aria-hidden="true" class="bi bi-search"></i>
{{ adminConfigurationSeoTab }}
{{ 'seoCenter' | translate }}
</a>
</li>
<li role="presentation" class="nav-item">
<a href="#mail" aria-controls="mail" role="tab" data-bs-toggle="tab" class="nav-link">
<i aria-hidden="true" class="bi bi-inbox"></i>
{{ adminConfigurationMailTab }}
<a href="#layout" aria-controls="seo" role="tab" data-bs-toggle="tab" class="nav-link">
<i aria-hidden="true" class="bi bi-pencil"></i>
{{ 'layoutControlCenter' | translate }}
</a>
</li>
<li role="presentation" class="nav-item">
<a href="#ldap" aria-controls="ldap" role="tab" data-bs-toggle="tab" class="nav-link">
<i aria-hidden="true" class="bi bi-database"></i>
LDAP
<a href="#mail" aria-controls="mail" role="tab" data-bs-toggle="tab" class="nav-link">
<i aria-hidden="true" class="bi bi-inbox"></i>
{{ 'mailControlCenter' | translate }}
</a>
</li>
<li role="presentation" class="nav-item">
Expand All @@ -82,7 +83,13 @@
<li role="presentation" class="nav-item">
<a href="#upgrade" aria-controls="upgrade" role="tab" data-bs-toggle="tab" class="nav-link">
<i aria-hidden="true" class="bi bi-arrow-clockwise"></i>
{{ adminConfigurationUpgradeTab }}
{{ 'upgradeControlCenter' | translate }}
</a>
</li>
<li role="presentation" class="nav-item">
<a href="#ldap" aria-controls="ldap" role="tab" data-bs-toggle="tab" class="nav-link">
<i aria-hidden="true" class="bi bi-database"></i>
LDAP
</a>
</li>
</ul>
Expand All @@ -94,10 +101,11 @@
<div role="tabpanel" class="tab-pane fade" id="security"></div>
<div role="tabpanel" class="tab-pane fade" id="spam"></div>
<div role="tabpanel" class="tab-pane fade" id="seo"></div>
<div role="tabpanel" class="tab-pane fade" id="layout"></div>
<div role="tabpanel" class="tab-pane fade" id="mail"></div>
<div role="tabpanel" class="tab-pane fade" id="ldap"></div>
<div role="tabpanel" class="tab-pane fade" id="api"></div>
<div role="tabpanel" class="tab-pane fade" id="upgrade"></div>
<div role="tabpanel" class="tab-pane fade" id="ldap"></div>
</div>
</div>
</div>
Expand Down
3 changes: 3 additions & 0 deletions phpmyfaq/assets/templates/default/index.twig
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
{% endif %}

<link href="{{ baseHref }}assets/dist/styles.css" rel="stylesheet">
<style>
{{ customCss }}
</style>

<link href="{{ baseHref }}assets/images/favicon.ico" rel="shortcut icon">
<link href="{{ currentPageUrl }}" rel="canonical">
Expand Down
2 changes: 1 addition & 1 deletion phpmyfaq/contact.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

$captchaHelper = CaptchaHelper::getInstance($faqConfig);

if ($faqConfig->get('main.contactInformationHTML')) {
if ($faqConfig->get('layout.contactInformationHTML')) {
$contactText = html_entity_decode((string) $faqConfig->get('main.contactInformation'));
} else {
$contactText = nl2br($faqConfig->get('main.contactInformation'));
Expand Down
7 changes: 4 additions & 3 deletions phpmyfaq/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@
'isUserLoggedIn' => $user->isLoggedIn(),
'title' => $title,
'baseHref' => $faqSystem->getSystemUri($faqConfig),
'customCss' => $faqConfig->getCustomCss(),
'version' => $faqConfig->getVersion(),
'header' => str_replace('"', '', $faqConfig->getTitle()),
'metaDescription' => $metaDescription ?? $faqConfig->get('seo.description'),
Expand Down Expand Up @@ -568,7 +569,7 @@
'msgTagCloudHeader' => Translation::get('msg_tags'),
'renderedTags' => $oTag->renderTagCloud(),
'currentYear' => date('Y', time()),
'cookieConsentEnabled' => $faqConfig->get('main.enableCookieConsent'),
'cookieConsentEnabled' => $faqConfig->get('layout.enableCookieConsent'),
];

$topNavigation = [
Expand Down Expand Up @@ -624,10 +625,10 @@
'isAskQuestionsEnabled' => $faqConfig->get('main.enableAskQuestions'),
'isOpenQuestionsEnabled' => $faqConfig->get('main.enableAskQuestions'),
'footerNavigation' => $footerNavigation,
'isPrivacyLinkEnabled' => $faqConfig->get('main.enablePrivacyLink'),
'isPrivacyLinkEnabled' => $faqConfig->get('layout.enablePrivacyLink'),
'urlPrivacyLink' => $faqConfig->get('main.privacyURL'),
'msgPrivacyNote' => Translation::get('msgPrivacyNote'),
'isCookieConsentEnabled' => $faqConfig->get('main.enableCookieConsent'),
'isCookieConsentEnabled' => $faqConfig->get('layout.enableCookieConsent'),
'cookiePreferences' => Translation::get('cookiePreferences')
];

Expand Down
11 changes: 8 additions & 3 deletions phpmyfaq/src/phpMyFAQ/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ public function getLdapMapping(): array
'name' => $this->get('ldap.ldap_mapping.name'),
'username' => $this->get('ldap.ldap_mapping.username'),
'mail' => $this->get('ldap.ldap_mapping.mail'),
'memberOf' => $this->get('ldap.ldap_mapping.memberOf')
'memberOf' => $this->get('ldap.ldap_mapping.memberOf'),
];
}

Expand All @@ -299,7 +299,7 @@ public function getLdapOptions(): array
{
return [
'LDAP_OPT_PROTOCOL_VERSION' => $this->get('ldap.ldap_options.LDAP_OPT_PROTOCOL_VERSION'),
'LDAP_OPT_REFERRALS' => $this->get('ldap.ldap_options.LDAP_OPT_REFERRALS')
'LDAP_OPT_REFERRALS' => $this->get('ldap.ldap_options.LDAP_OPT_REFERRALS'),
];
}

Expand Down Expand Up @@ -431,7 +431,7 @@ public function update(array $newConfigs): bool
'core.ldapServer', // Ldap
'core.ldapConfig', // $LDAP
'core.elasticsearch', // Elasticsearch\Client
'core.elasticsearchConfig' // $ES
'core.elasticsearchConfig', // $ES
];

foreach ($newConfigs as $name => $value) {
Expand Down Expand Up @@ -500,4 +500,9 @@ public function getAllowedMediaHosts(): array
{
return explode(',', $this->get('records.allowedMediaHosts'));
}

public function getCustomCss(): string
{
return $this->get('layout.customCss');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@

namespace phpMyFAQ\Controller\Administration;

use phpMyFAQ\Configuration;
use phpMyFAQ\Controller\AbstractController;
use phpMyFAQ\Core\Exception;
use phpMyFAQ\Enums\PermissionType;
use phpMyFAQ\Filter;
use phpMyFAQ\Helper\AdministrationHelper;
use phpMyFAQ\Helper\LanguageHelper;
use phpMyFAQ\Helper\PermissionHelper;
use phpMyFAQ\Language;
use phpMyFAQ\Session\Token;
use phpMyFAQ\Strings;
use phpMyFAQ\System;
use phpMyFAQ\Template\TemplateException;
use phpMyFAQ\Translation;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
Expand All @@ -41,13 +42,25 @@ class ConfigurationTabController extends AbstractController
* @throws TemplateException
* @throws Exception
*/
#[Route('admin/api/configuration/list')]
#[Route('admin/api/configuration/list/{mode}')]
public function list(Request $request): Response
{
$this->userHasPermission(PermissionType::CONFIGURATION_EDIT);

$mode = $request->get('mode');
$language = new Language($this->configuration);
$currentLanguage = $language->setLanguageByAcceptLanguage();

try {
Translation::create()
->setLanguagesDir(PMF_LANGUAGE_DIR)
->setDefaultLanguage('en')
->setCurrentLanguage($currentLanguage)
->setMultiByteLanguage();
} catch (Exception $exception) {
throw new BadRequestException($exception->getMessage());
}

$mode = $request->get('mode');
$configurationList = Translation::getConfigurationItems($mode);

return $this->render(
Expand Down Expand Up @@ -83,7 +96,6 @@ public function save(Request $request): JsonResponse
return $this->json(['error' => Translation::get('err_NotAuth')], Response::HTTP_UNAUTHORIZED);
} else {
// Set the new values
$forbiddenValues = ['{', '}'];
$newConfigValues = [];
$escapeValues = [
'main.contactInformation',
Expand Down Expand Up @@ -124,8 +136,7 @@ public function save(Request $request): JsonResponse
$newConfigClass = [];

foreach ($configurationData as $key => $value) {
// Remove forbidden characters
$newConfigValues[$key] = str_replace($forbiddenValues, '', (string) $value);
$newConfigValues[$key] = (string) $value;
// Escape some values
if (isset($escapeValues[$key])) {
$newConfigValues[$key] = Strings::htmlspecialchars($value, ENT_QUOTES);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ public function render(string $pathToTwigFile, array $templateVars = [], Respons
{
$response ??= new Response();
$twigWrapper = new TwigWrapper(PMF_ROOT_DIR . '/assets/templates');
$twigWrapper->addExtension(new DebugExtension());
$template = $twigWrapper->loadTemplate($pathToTwigFile);

$response->setContent($template->render($templateVars));
Expand Down
11 changes: 6 additions & 5 deletions phpmyfaq/src/phpMyFAQ/Setup/Installer.php
Original file line number Diff line number Diff line change
Expand Up @@ -308,11 +308,9 @@ class Installer extends Setup
'main.enableWysiwygEditor' => 'true',
'main.enableWysiwygEditorFrontend' => 'false',
'main.enableMarkdownEditor' => 'false',
'main.templateSet' => 'default',
'main.dateFormat' => 'Y-m-d H:i',
'main.maintenanceMode' => 'false',
'main.enableGravatarSupport' => 'false',
'main.enableGzipCompression' => 'true',
'main.customPdfHeader' => '',
'main.customPdfFooter' => '',
'main.enableSmartAnswering' => 'true',
Expand All @@ -322,12 +320,9 @@ class Installer extends Setup
'main.enableAutoUpdateHint' => 'true',
'main.enableAskQuestions' => 'false',
'main.enableNotifications' => 'false',
'main.contactInformationHTML' => 'false',
'main.botIgnoreList' => 'nustcrape,webpost,GoogleBot,msnbot,crawler,scooter,bravobrian,archiver,' .
'w3c,controler,wget,bot,spider,Yahoo! Slurp,htdig,gsa-crawler,AirControler,Uptime-Kuma,facebookcatalog/1.0,' .
'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php),facebookexternalhit/1.1',
'main.enableCookieConsent' => 'true',
'main.enablePrivacyLink' => 'true',

'records.numberOfRecordsPerPage' => '10',
'records.numberOfShownNewsEntries' => '3',
Expand Down Expand Up @@ -428,6 +423,12 @@ class Installer extends Setup
'upgrade.lastDownloadedPackage' => '',
'upgrade.onlineUpdateEnabled' => 'false',
'upgrade.releaseEnvironment' => '__PHPMYFAQ_RELEASE__',

'layout.templateSet' => 'default',
'layout.enablePrivacyLink' => 'true',
'layout.enableCookieConsent' => 'true',
'layout.contactInformationHTML' => 'false',
'layout.customCss' => '',
];

public array $formInputs = [
Expand Down
Loading

0 comments on commit 1a38ef4

Please sign in to comment.