<?php namespace HashOver;// Copyright (C) 2018-2021 Jacob Barkdull// This file is part of HashOver.//// HashOver is free software: you can redistribute it and/or modify// it under the terms of the GNU Affero General Public License as// published by the Free Software Foundation, either version 3 of the// License, or (at your option) any later version.//// HashOver is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU Affero General Public License for more details.//// You should have received a copy of the GNU Affero General Public License// along with HashOver.  If not, see <http://www.gnu.org/licenses/>.// Generates an array of various settings informationfunction ui_array (Setup $setup, Locale $locale){	// Theme names	$themes = array ();	// Themes directory	$themes_directory = $setup->getAbsolutePath ('themes');	// Get each theme directory name	foreach (glob ($themes_directory . '/*', GLOB_ONLYDIR) as $directory) {		$theme = basename ($directory);		$themes[$theme] = $theme;	}	// Form fields options	$field_options = array (		'on'		=> $locale->text['enabled'],		'required'	=> $locale->text['required'],		'off'		=> $locale->text['disabled'],	);	// Return array of settings allowed to be changed	return array (		'general' => array (			'language' => array (				'type' => 'select',				'value' => $setup->language,				'options' => array (					'en-us' => 'English',					'pt-br' => 'Brazilian Portuguese',					'da-dk' => 'Danish',					'nl-nl' => 'Dutch',					'eo-eo' => 'Esperanto',					'fr-fr' => 'French',					'de-de' => 'German',					'el-el' => 'Greek',					'ja-jp' => 'Japanese',					'ko-kr' => 'Korean',					'lt-lt' => 'Lithuanian',					'fa-ir' => 'Persian',					'pl-pl' => 'Polish',					'ro-ro' => 'Romanian',					'ru-ru' => 'Russian',					'zh-cn' => 'Simplified Chinese',					'es-es' => 'Spanish',					'sv-se' => 'Swedish',					'tr-tr' => 'Turkish'				)			),			'theme' => array (				'type' => 'select',				'value' => $setup->theme,				'options' => $themes			),			'default-sorting' => array (				'type' => 'select',				'value' => $setup->defaultSorting,				'options' => array (					'ascending'	=> $locale->text['sort-ascending'],					'descending'	=> $locale->text['sort-descending'],					'by-date'	=> $locale->text['sort-by-date'],					'by-likes'	=> $locale->text['sort-by-likes'],					'by-replies'	=> $locale->text['sort-by-replies'],					'by-name'	=> $locale->text['sort-by-name'],					'threads' => array (						'threaded-descending'	=> $locale->text['sort-descending'],						'threaded-by-date'	=> $locale->text['sort-by-date'],						'threaded-by-likes'	=> $locale->text['sort-by-likes'],						'by-popularity'		=> $locale->text['sort-by-popularity'],						'by-discussion'		=> $locale->text['sort-by-discussion'],						'threaded-by-name'	=> $locale->text['sort-by-name']					)				)			),			'uses-markdown' => array (				'type' => 'checkbox',				'value' => $setup->usesMarkdown			),			'uses-ajax' => array (				'type' => 'checkbox',				'value' => $setup->usesAjax			),			'shows-reply-count' => array (				'type' => 'checkbox',				'value' => $setup->showsReplyCount			),			'allows-images' => array (				'type' => 'checkbox',				'value' => $setup->allowsImages			),			'allows-likes' => array (				'type' => 'checkbox',				'value' => $setup->allowsLikes			),			'allows-dislikes' => array (				'type' => 'checkbox',				'value' => $setup->allowsDislikes			)		),		'moderation' => array (			'uses-moderation' => array (				'type' => 'checkbox',				'value' => $setup->usesModeration			),			'pends-user-edits' => array (				'type' => 'checkbox',				'value' => $setup->pendsUserEdits			)		),		'e-mail' => array (			'sends-notifications' => array (				'type' => 'select',				'value' => $setup->sendsNotifications,				'options' => array (					'to-everyone' => 'Everyone, admin and users',					'to-users' => 'Users only, when they reply to each other',					'to-admin' => 'Admin only',					'to-nobody' => 'Nobody'				)			),			'mail-type' => array (				'type' => 'select',				'value' => $setup->mailType,				'options' => array (					'text' => 'Text',					'html' => 'HTML'				)			),			'mailer' => array (				'type' => 'select',				'value' => $setup->mailer,				'options' => array (					'sendmail' => 'Sendmail',					'smtp' => 'SMTP'				)			),			'subscribes-user' => array (				'type' => 'checkbox',				'value' => $setup->subscribesUser			),			'allows-user-replies' => array (				'type' => 'checkbox',				'value' => $setup->allowsUserReplies			)		),		'cookies' => array (			'sets-cookies' => array (				'type' => 'checkbox',				'value' => $setup->setsCookies			),			'cookie-expiration' => array (				'type' => 'text',				'value' => $setup->cookieExpiration			),			'secure-cookies' => array (				'type' => 'checkbox',				'value' => $setup->secureCookies			)		),		'comment-collapsing' => array (			'collapses-interface' => array (				'type' => 'checkbox',				'value' => $setup->collapsesInterface			),			'collapses-comments' => array (				'type' => 'checkbox',				'value' => $setup->collapsesComments			),			'collapse-limit' => array (				'type' => 'number',				'value' => $setup->collapseLimit			)		),		'popular-comments' => array (			'popularity-threshold' => array (				'type' => 'number',				'value' => $setup->popularityThreshold			),			'popularity-limit' => array (				'type' => 'number',				'value' => $setup->popularityLimit			)		),		'spam-protection' => array (			'spam-database' => array (				'type' => 'select',				'value' => $setup->spamDatabase,				'options' => array (					'remote' => 'StopForumSpam.com',					'local' => 'Local CSV file'				)			),			'spam-check-modes' => array (				'type' => 'select',				'value' => $setup->spamCheckModes,				'options' => array (					'both' => 'Both',					'json' => 'JavaScript',					'php' => 'PHP'				)			)		),		'avatars' => array (			'icon-mode' => array (				'type' => 'select',				'value' => $setup->iconMode,				'options' => array (					'image' => 'Image',					'count' => 'Count',					'none' => 'None'				)			),			'icon-size' => array (				'type' => 'number',				'value' => $setup->iconSize			),			'gravatar-default' => array (				'type' => 'select',				'value' => $setup->gravatarDefault,				'options' => array (					'custom' => 'Custom',					'identicon' => 'Identicon',					'monsterid' => 'Monsterid',					'wavatar' => 'Wavatar',					'retro' => 'Retro'				)			),			'gravatar-force' => array (				'type' => 'checkbox',				'value' => $setup->gravatarForce			)		),		'form-fields' => array (			'form-position' => array (				'type' => 'select',				'value' => $setup->formPosition,				'options' => array (					'top' => 'Top',					'bottom' => 'Bottom'				)			),			'name-field' => array (				'type' => 'select',				'value' => $setup->nameField,				'options' => $field_options			),			'password-field' => array (				'type' => 'select',				'value' => $setup->passwordField,				'options' => $field_options			),			'email-field' => array (				'type' => 'select',				'value' => $setup->emailField,				'options' => $field_options			),			'website-field' => array (				'type' => 'select',				'value' => $setup->websiteField,				'options' => $field_options			),			'displays-title' => array (				'type' => 'checkbox',				'value' => $setup->displaysTitle			),			'uses-cancel-buttons' => array (				'type' => 'checkbox',				'value' => $setup->usesCancelButtons			),			'uses-labels' => array (				'type' => 'checkbox',				'value' => $setup->usesLabels			)		),		'date-time' => array (			'date-pattern' => array (				'type' => 'text',				'value' => $setup->datePattern,				'show' => $setup->hasIntl			),			'time-pattern' => array (				'type' => 'text',				'value' => $setup->timePattern,				'show' => $setup->hasIntl			),			'date-format' => array (				'type' => 'text',				'value' => $setup->dateFormat,				'show' => !$setup->hasIntl			),			'time-format' => array (				'type' => 'text',				'value' => $setup->timeFormat,				'show' => !$setup->hasIntl			),			'server-timezone' => array (				'type' => 'text',				'value' => $setup->serverTimezone			),			'uses-user-timezone' => array (				'type' => 'checkbox',				'value' => $setup->usesUserTimezone			),			'uses-short-dates' => array (				'type' => 'checkbox',				'value' => $setup->usesShortDates			)		),		'login' => array (			'login-method' => array (				'type' => 'select',				'value' => $setup->loginMethod,				'options' => array (					'DefaultLogin' => 'Cookies Login',					'SessionLogin' => 'Session Login'				)			),			'allows-login' => array (				'type' => 'checkbox',				'value' => $setup->allowsLogin			),			'uses-auto-login' => array (				'type' => 'checkbox',				'value' => $setup->usesAutoLogin			)		),		'technical' => array (			'data-format' => array (				'type' => 'select',				'value' => $setup->dataFormat,				'options' => array (					'xml' => 'XML',					'json' => 'JSON',					'sql' => 'SQL'				)			),			'default-name' => array (				'type' => 'text',				'value' => $setup->defaultName			),			'reply-mode' => array (				'type' => 'select',				'value' => $setup->replyMode,				'options' => array (					'thread' => 'Threaded',					'stream' => 'Stream'				)			),			'stream-depth' => array (				'type' => 'number',				'value' => $setup->streamDepth			),			'image-format' => array (				'type' => 'select',				'value' => $setup->imageFormat,				'options' => array (					'png' => 'PNG',					'svg' => 'SVG'				)			),			'appends-css' => array (				'type' => 'checkbox',				'value' => $setup->appendsCss			),			'appends-rss' => array (				'type' => 'checkbox',				'value' => $setup->appendsRss			),			'counts-deletions' => array (				'type' => 'checkbox',				'value' => $setup->countsDeletions			),			'local-metadata' => array (				'type' => 'checkbox',				'value' => $setup->localMetadata			),			'stores-ip-address' => array (				'type' => 'checkbox',				'value' => $setup->storesIpAddress			)		),		'JavaScript' => array (			'minifies-javascript' => array (				'type' => 'checkbox',				'value' => $setup->minifiesJavascript			),			'minify-level' => array (				'type' => 'select',				'cast' => 'number',				'value' => $setup->minifyLevel,				'options' => array (					1 => 'Basic (removes code comments)',					2 => 'Low (removes whitespace + Basic)',					3 => 'Medium (removes newlines + Low)',					4 => 'High (removes extra bits + Medium)'				)			)		)	);}// Creates a select element with setting optionsfunction create_select ($hashover, $name, array $setting){	// Create wrapper element for dropdown menu	$element = new HTMLTag ('span', array (		'class' => 'select-wrapper'	));	// Create dropdown menu	$select = new HTMLTag ('select', array (		'id' => $name,		'name' => $name,		'size' => 1	));	// Run through setting options	foreach ($setting['options'] as $value => $data) {		// Check if the current option is an array		if (is_array ($data)) {			// If so, add an option group spacer to menu			$select->appendChild (new HTMLTag ('optgroup', array (				'label' => '&nbsp;'			)));			// Create an option group with localized label			$optgroup = new HTMLTag ('optgroup', array (				'label' => $hashover->locale->text[$value]			));			// Run through each optgroup option			foreach ($data as $opt_value => $opt_text) {				// Create setting option				$option = new HTMLTag ('option', array (					'value' => $opt_value,					'innerHTML' => $opt_text				), false);				// Select proper option				if ($opt_value === $setting['value']) {					$option->createAttribute ('selected', 'true');				}				// Append option to optgroup				$optgroup->appendChild ($option);			}			// And append optgroup to menu			$select->appendChild ($optgroup);		} else {			// If not, create setting option			$option = new HTMLTag ('option', array (				'value' => $value,				'innerHTML' => $data			), false);			// Select proper option			if ($value === $setting['value']) {				$option->createAttribute ('selected', 'true');			}			// Append option to menu			$select->appendChild ($option);		}	}	// Append dropdown menu to wrapper element	$element->appendChild ($select);	return $element;}// Creates a paragraph element for a setting valuefunction create_paragraph ($hashover, $name, array $setting){	// Create setting description and value paragraph	$paragraph = new HTMLTag ('p');	// Setting description locale string	$text = $hashover->locale->text['setting-' . $name];	// Create description label	$label = new HTMLTag ('label', array (		'for' => $name,		'innerHTML' => $text	), false);	// Get documentation locale string	$docs = $hashover->locale->text['documentation'];	// Create documentation link	$docs_link = new HTMLTag ('a', array (		'class' => 'docs-link',		'href' => '../docs/en-us/settings/#' . $name,		'target' => '_blank',		'title' => $docs,		'innerHTML' => '?'	), false);	// Handle specific setting types	switch ($setting['type']) {		// Create checkbox for enabling/disabling the setting		case 'checkbox': {			// Create checkbox type input element			$element = new HTMLTag ('input', array (				'id' => $name,				'type' => 'checkbox',				'name' => $name			), false, true);			// Set check based on current setting			if ($setting['value'] !== false) {				$element->createAttribute ('checked', 'true');			}			break;		}		// Create text/number box for entering the setting value		case 'number' : case 'text': {			// Add class to make label a block element			$label->createAttribute ('class', 'block');			// And create number or text type input element			$element = new HTMLTag ('input', array (				'id' => $name,				'type' => $setting['type'],				'name' => $name,				'value' => $setting['value'],				'size' => ($setting['type'] === 'text') ? '25' : '10'			), false, true);			break;		}		// Create dropdown menu for selecting the setting value		case 'select': {			// Add class to make label a block element			$label->createAttribute ('class', 'block');			// Create select element			$element = create_select ($hashover, $name, $setting);			break;		}	}	// Check if setting is a checkbox	if ($setting['type'] === 'checkbox') {		// If so, append setting value element to paragraph		$paragraph->appendChild ($element);		// Then append label element to paragraph		$paragraph->appendChild ($label);		// Append documentation link to description and value paragraph		$paragraph->appendChild ($docs_link);	} else {		// If not, append documentation link to description label		$label->appendChild ($docs_link);		// Append label element to paragraph		$paragraph->appendChild ($label);		// Then append setting value element to paragraph		$paragraph->appendChild ($element);	}	// And return paragraph element	return $paragraph;}try {	// Do some standard HashOver setup work	require (realpath ('../../backend/standard-setup.php'));	// View setup	require (realpath ('../view-setup.php'));	// Get array of UI elements to create	$ui = ui_array ($hashover->setup, $hashover->locale);	// Check if the form has been submitted	if (isset ($_POST['save'])) {		// Settings JSON file path		$settings_file = $hashover->setup->getAbsolutePath ('config/settings.json');		// Read JSON settings file		$json = $data_files->readJSON ($settings_file);		// Existing JSON settings or an empty array		$settings = ($json !== false) ? $json : array ();		// Run through configurable settings		foreach ($ui as $items) {			// Run through each settings category			foreach ($items as $name => $setting) {				// Use specified type or optional cast				$type = !empty ($setting['cast']) ? 'cast' : 'type';				// Handle specific setting types				switch ($setting[$type]) {					// Set value to boolean based on POST data					case 'checkbox': {						$settings[$name] = isset ($_POST[$name]);						break;					}					// Cast number values to integers					case 'number': {						$settings[$name] = (int)($_POST[$name]);						break;					}					// All other values are strings					default: {						// Check if setting has a value						if (!empty ($_POST[$name])) {							// If so, cast it to string before setting it							$settings[$name] = (string)($_POST[$name]);						} else {							// If not, remove the setting entirely							unset ($settings[$name]);						}						break;					}				}			}		}		// Check if the user login is admin		if ($hashover->login->verifyAdmin () === true) {			// If so, attempt to save the settings			$saved = $data_files->saveJSON ($settings_file, $settings);			// If saved successfully, redirect with success indicator			if ($saved === true) {				redirect ('./?status=success');			}		}		// Otherwise, redirect with failure indicator		redirect ('./?status=failure');	}	// Otherwise, create settings div	$div = new HTMLTag ('div', array (		'id' => 'settings'	));	// Create settings divs	foreach ($ui as $locale => $settings) {		// Replace key with locale string if one exists		if (!empty ($hashover->locale->text[$locale])) {			$locale = $hashover->locale->text[$locale];		}		// Append settings category text to settings div		$div->appendChild (new HTMLTag ('p', array (			'class' => 'settings-category',			'innerHTML' => $locale		), false));		// Create settings items element		$items = new HTMLTag ('div', array (			'class' => 'settings'		));		// Run through settings		foreach ($settings as $name => $setting) {			// Append each settings category items to div if they are to be shown			if (!isset ($setting['show']) or $setting['show'] === true) {				$items->appendChild (create_paragraph ($hashover, $name, $setting));			}		}		// Append settings items element to div		$div->appendChild ($items);	}	// Template data	$template = array (		'title'		=> $hashover->locale->text['settings'],		'sub-title'	=> $hashover->locale->text['settings-sub'],		'settings'	=> $div->asHTML ("\t"),		'save-button'	=> $hashover->locale->text['save']	);	// Load and parse HTML template	echo parse_templates ('admin', 'settings.html', $template, $hashover);} catch (\Exception $error) {	echo Misc::displayException ($error);}