Browse Source

Merge pull request #4 from fusionpbx/master

Pull Upstream
demonspork 5 years ago
parent
commit
2c13b248f2
64 changed files with 3165 additions and 1588 deletions
  1. 0 70
      core/apps/app_config.php
  2. 0 160
      core/apps/app_languages.php
  3. 0 28
      core/apps/app_menu.php
  4. 0 106
      core/apps/apps.php
  5. 0 90
      core/apps/root.php
  6. 7 3
      core/default_settings/app_config.php
  7. 1 1
      core/default_settings/app_defaults.php
  8. 36 3
      core/default_settings/default_setting_edit.php
  9. 28 1
      core/default_settings/default_settings.php
  10. 4 1
      core/domain_settings/app_config.php
  11. 42 0
      core/domain_settings/app_languages.php
  12. 33 4
      core/domain_settings/domain_setting_edit.php
  13. 45 8
      core/domain_settings/domain_settings.php
  14. 4 1
      core/domains/app_config.php
  15. 21 21
      core/domains/app_languages.php
  16. 89 81
      core/domains/domain_edit.php
  17. 7 3
      core/domains/domains.php
  18. 8 0
      core/groups/app_config.php
  19. 5 0
      core/groups/app_defaults.php
  20. 21 3
      core/groups/group_edit.php
  21. 30 38
      core/groups/group_members.php
  22. 374 323
      core/groups/group_permissions.php
  23. 3 3
      core/groups/groupmemberadd.php
  24. 1 1
      core/groups/groupmemberdelete.php
  25. 3 16
      core/groups/groups.php
  26. 4 2
      core/groups/resources/classes/groups.php
  27. 21 15
      core/groups/resources/classes/permission.php
  28. 0 1
      core/menu/app_menu.php
  29. 230 229
      core/menu/menu_edit.php
  30. 62 0
      core/menu/menu_reload.php
  31. 12 1
      core/software/app_defaults.php
  32. 2 2
      core/software/resources/classes/software.php
  33. 1 1
      core/upgrade/app_defaults.php
  34. 2 1
      core/upgrade/index.php
  35. 4 1
      core/user_settings/app_config.php
  36. 0 34
      core/user_settings/user_dashboard.php
  37. 36 7
      core/user_settings/user_setting_edit.php
  38. 160 0
      core/user_settings/user_setting_set.php
  39. 16 4
      core/user_settings/user_settings.php
  40. 5 1
      core/users/app_config.php
  41. 7 7
      core/users/app_languages.php
  42. 3 1
      core/users/user_edit.php
  43. 1 1
      core/users/user_imports.php
  44. 5 3
      core/users/users.php
  45. 229 0
      resources/app_languages.php
  46. BIN
      resources/captcha/fonts/hanshand.ttf
  47. 24 27
      resources/check_auth.php
  48. 605 36
      resources/classes/database.php
  49. 0 5
      resources/classes/domains.php
  50. 59 48
      resources/classes/menu.php
  51. 4 4
      resources/classes/modal.php
  52. 3 0
      resources/classes/schema.php
  53. 11 2
      resources/footer.php
  54. 34 30
      resources/functions.php
  55. 20 0
      resources/header.php
  56. 5 0
      resources/login.php
  57. 5 2
      resources/paging.php
  58. 15 33
      resources/php.php
  59. 10 10
      resources/phpmailer/class.phpmailer.php
  60. 2 0
      robots.txt
  61. 170 2
      themes/default/app_config.php
  62. 162 1
      themes/default/app_languages.php
  63. 209 54
      themes/default/css.php
  64. 265 58
      themes/default/template.php

+ 0 - 70
core/apps/app_config.php

@@ -1,70 +0,0 @@
-<?php
-
-	//application details
-		$apps[$x]['name'] = "App Manager";
-		$apps[$x]['uuid'] = "d8704214-75a0-e52f-1336-f0780e29fef8";
-		$apps[$x]['category'] = "";
-		$apps[$x]['subcategory'] = "";
-		$apps[$x]['version'] = "1.0";
-		$apps[$x]['license'] = "Mozilla Public License 1.1";
-		$apps[$x]['url'] = "http://www.fusionpbx.com";
-		$apps[$x]['description']['en-us'] = "Manage Applications";
-		$apps[$x]['description']['en-gb'] = "Manage Applications";
-		$apps[$x]['description']['ar-eg'] = "";
-		$apps[$x]['description']['de-at'] = "Applikationen Verwalten";
-		$apps[$x]['description']['de-ch'] = "";
-		$apps[$x]['description']['de-de'] = "Applikationen Verwalten";
-		$apps[$x]['description']['es-cl'] = "";
-		$apps[$x]['description']['es-mx'] = "";
-		$apps[$x]['description']['fr-ca'] = "";
-		$apps[$x]['description']['fr-fr'] = "";
-		$apps[$x]['description']['he-il'] = "";
-		$apps[$x]['description']['it-it'] = "";
-		$apps[$x]['description']['nl-nl'] = "";
-		$apps[$x]['description']['pl-pl'] = "";
-		$apps[$x]['description']['pt-br'] = "Gerenciador de Aplicações";
-		$apps[$x]['description']['pt-pt'] = "";
-		$apps[$x]['description']['ro-ro'] = "";
-		$apps[$x]['description']['ru-ru'] = "";
-		$apps[$x]['description']['sv-se'] = "";
-		$apps[$x]['description']['uk-ua'] = "";
-
-	//permission details
-		$y=0;
-		$apps[$x]['permissions'][$y]['name'] = "app_view";
-		$apps[$x]['permissions'][$y]['menu']['uuid'] = "ef00f229-7890-00c2-bf23-fed5b8fa9fe7";
-		$apps[$x]['permissions'][$y]['groups'][] = "superadmin";
-		$y++;
-		$apps[$x]['permissions'][$y]['name'] = "app_add";
-		$apps[$x]['permissions'][$y]['groups'][] = "superadmin";
-		$y++;
-		$apps[$x]['permissions'][$y]['name'] = "app_edit";
-		$apps[$x]['permissions'][$y]['groups'][] = "superadmin";
-		$y++;
-		$apps[$x]['permissions'][$y]['name'] = "app_delete";
-		$apps[$x]['permissions'][$y]['groups'][] = "superadmin";
-
-	//schema details
-		$y=0;
-		$apps[$x]['db'][$y]['table']['name'] = "v_apps";
-		$apps[$x]['db'][$y]['table']['parent'] = "";
-		$z=0;
-		$apps[$x]['db'][$y]['fields'][$z]['name'] = "app_uuid";
-		$apps[$x]['db'][$y]['fields'][$z]['type']['pgsql'] = "uuid";
-		$apps[$x]['db'][$y]['fields'][$z]['type']['sqlite'] = "text";
-		$apps[$x]['db'][$y]['fields'][$z]['type']['mysql'] = "char(36)";
-		$apps[$x]['db'][$y]['fields'][$z]['key']['type'] = "primary";
-		$z++;
-		$apps[$x]['db'][$y]['fields'][$z]['name'] = "app_category";
-		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
-		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
-		$z++;
-		$apps[$x]['db'][$y]['fields'][$z]['name'] = "app_version";
-		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
-		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
-		$z++;
-		$apps[$x]['db'][$y]['fields'][$z]['name'] = "app_enabled";
-		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
-		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
-
-?>

+ 0 - 160
core/apps/app_languages.php

@@ -1,160 +0,0 @@
-<?php
-#This file was last reorganized on 19th of September 2017 08:54:24 AM UTC
-
-$text['title-apps']['en-us'] = "App Manager";
-$text['title-apps']['en-gb'] = "App Manager";
-$text['title-apps']['ar-eg'] = "";
-$text['title-apps']['de-at'] = "Applikation Verwaltung"; //copied from de-de
-$text['title-apps']['de-ch'] = "Applikation Verwaltung"; //copied from de-de
-$text['title-apps']['de-de'] = "Applikation Verwaltung";
-$text['title-apps']['es-cl'] = "Administrador de Aplicaciones";
-$text['title-apps']['es-mx'] = "Administrador de Aplicaciones"; //copied from es-cl
-$text['title-apps']['fr-ca'] = "Gestionnaire App"; //copied from fr-fr
-$text['title-apps']['fr-fr'] = "Gestionnaire App";
-$text['title-apps']['he-il'] = "";
-$text['title-apps']['it-it'] = "Gestore App";
-$text['title-apps']['nl-nl'] = "";
-$text['title-apps']['pl-pl'] = "Menedżer aplikacji";
-$text['title-apps']['pt-br'] = "Gerenciador de aplicações";
-$text['title-apps']['pt-pt'] = "Gestor de Aplicações";
-$text['title-apps']['ro-ro'] = "";
-$text['title-apps']['ru-ru'] = "Управление приложениями";
-$text['title-apps']['sv-se'] = "App Inställningar";
-$text['title-apps']['uk-ua'] = "Керування додатками";
-$text['title-apps']['tr-tr'] = "Uygulama Yöneticisi";
-
-
-$text['title-app-edit']['en-us'] = "App Edit";
-$text['title-app-edit']['en-gb'] = "App Edit";
-$text['title-app-edit']['ar-eg'] = "";
-$text['title-app-edit']['de-at'] = "Applikationen Editieren"; //copied from de-de
-$text['title-app-edit']['de-ch'] = "Applikationen Editieren"; //copied from de-de
-$text['title-app-edit']['de-de'] = "Applikationen Editieren";
-$text['title-app-edit']['es-cl'] = "Editar Aplicaciones";
-$text['title-app-edit']['es-mx'] = "Editar Aplicaciones"; //copied from es-cl
-$text['title-app-edit']['fr-ca'] = "Editer l'application"; //copied from fr-fr
-$text['title-app-edit']['fr-fr'] = "Editer l'application";
-$text['title-app-edit']['he-il'] = "";
-$text['title-app-edit']['it-it'] = "Modifica App";
-$text['title-app-edit']['nl-nl'] = "";
-$text['title-app-edit']['pl-pl'] = "Edytuj aplikację ";
-$text['title-app-edit']['pt-br'] = "Editar aplicação"; //copied from pt-pt
-$text['title-app-edit']['pt-pt'] = "Editar aplicação";
-$text['title-app-edit']['ro-ro'] = "";
-$text['title-app-edit']['ru-ru'] = "Изменеие приложения";
-$text['title-app-edit']['sv-se'] = "Ändra App";
-$text['title-app-edit']['uk-ua'] = "Редагувати додаток";
-$text['title-app-edit']['tr-tr'] = "Uygulama Düzenle";
-
-$text['label-version']['en-us'] = "Version";
-$text['label-version']['en-gb'] = "Version";
-$text['label-version']['ar-eg'] = "";
-$text['label-version']['de-at'] = "Version"; //copied from de-de
-$text['label-version']['de-ch'] = "Version"; //copied from de-de
-$text['label-version']['de-de'] = "Version";
-$text['label-version']['es-cl'] = "Versión";
-$text['label-version']['es-mx'] = "Versión"; //copied from es-cl
-$text['label-version']['fr-ca'] = "Version"; //copied from fr-fr
-$text['label-version']['fr-fr'] = "Version";
-$text['label-version']['he-il'] = "";
-$text['label-version']['it-it'] = "Versione";
-$text['label-version']['nl-nl'] = "";
-$text['label-version']['pl-pl'] = "Wersja";
-$text['label-version']['pt-br'] = "Versão"; //copied from pt-pt
-$text['label-version']['pt-pt'] = "Versão";
-$text['label-version']['ro-ro'] = "";
-$text['label-version']['ru-ru'] = "Версия";
-$text['label-version']['sv-se'] = "Version";
-$text['label-version']['uk-ua'] = "Версія";
-$text['label-version']['tr-tr'] = "Sürüm";
-
-$text['header-apps']['en-us'] = "App Manager";
-$text['header-apps']['en-gb'] = "App Manager";
-$text['header-apps']['ar-eg'] = "";
-$text['header-apps']['de-at'] = "Applikation verwalten"; //copied from de-de
-$text['header-apps']['de-ch'] = "Applikation verwalten"; //copied from de-de
-$text['header-apps']['de-de'] = "Applikation verwalten";
-$text['header-apps']['es-cl'] = "Administrador de Aplicaciones";
-$text['header-apps']['es-mx'] = "Administrador de Aplicaciones"; //copied from es-cl
-$text['header-apps']['fr-ca'] = "Gestionnaire App"; //copied from fr-fr
-$text['header-apps']['fr-fr'] = "Gestionnaire App";
-$text['header-apps']['he-il'] = "";
-$text['header-apps']['it-it'] = "Gestore App";
-$text['header-apps']['nl-nl'] = "";
-$text['header-apps']['pl-pl'] = "Menedżer aplikacji";
-$text['header-apps']['pt-br'] = "Gerenciador de aplicações";
-$text['header-apps']['pt-pt'] = "Gestor de Aplicações";
-$text['header-apps']['ro-ro'] = "";
-$text['header-apps']['ru-ru'] = "Управление приложениями";
-$text['header-apps']['sv-se'] = "App Inställningar";
-$text['header-apps']['uk-ua'] = "Керування додатками";
-$text['header-apps']['tr-tr'] = "Uygulama Yöneticisi";
-
-$text['header-app-edit']['en-us'] = "App Edit";
-$text['header-app-edit']['en-gb'] = "App Edit";
-$text['header-app-edit']['ar-eg'] = "";
-$text['header-app-edit']['de-at'] = "Applikation bearbeiten"; //copied from de-de
-$text['header-app-edit']['de-ch'] = "Applikation bearbeiten"; //copied from de-de
-$text['header-app-edit']['de-de'] = "Applikation bearbeiten";
-$text['header-app-edit']['es-cl'] = "Editar Aplicaciones";
-$text['header-app-edit']['es-mx'] = "Editar Aplicaciones"; //copied from es-cl
-$text['header-app-edit']['fr-ca'] = "Editer l'application"; //copied from fr-fr
-$text['header-app-edit']['fr-fr'] = "Editer l'application";
-$text['header-app-edit']['he-il'] = "";
-$text['header-app-edit']['it-it'] = "Modifica App";
-$text['header-app-edit']['nl-nl'] = "";
-$text['header-app-edit']['pl-pl'] = "Edytuj aplikację ";
-$text['header-app-edit']['pt-br'] = "Editar aplicação"; //copied from pt-pt
-$text['header-app-edit']['pt-pt'] = "Editar aplicação";
-$text['header-app-edit']['ro-ro'] = "";
-$text['header-app-edit']['ru-ru'] = "Изменеие приложения";
-$text['header-app-edit']['sv-se'] = "Ändra App";
-$text['header-app-edit']['uk-ua'] = "Редагувати додаток";
-$text['header-app-edit']['tr-tr'] = "Uygulama Düzenle";
-
-$text['description-apps']['en-us'] = "Manage the applications that are installed.";
-$text['description-apps']['en-gb'] = "Manage the applications that are installed.";
-$text['description-apps']['ar-eg'] = "";
-$text['description-apps']['de-at'] = "Installierte Applikationen verwalten"; //copied from de-de
-$text['description-apps']['de-ch'] = "Installierte Applikationen verwalten"; //copied from de-de
-$text['description-apps']['de-de'] = "Installierte Applikationen verwalten";
-$text['description-apps']['es-cl'] = "Administre las aplicaciones instaladas.";
-$text['description-apps']['es-mx'] = "Administre las aplicaciones instaladas."; //copied from es-cl
-$text['description-apps']['fr-ca'] = "Gérer les applications installées."; //copied from fr-fr
-$text['description-apps']['fr-fr'] = "Gérer les applications installées.";
-$text['description-apps']['he-il'] = "";
-$text['description-apps']['it-it'] = "Gestisce le applicazioni installate.";
-$text['description-apps']['nl-nl'] = "";
-$text['description-apps']['pl-pl'] = "Zarządzajnie zainstalowanymi aplikacjami.";
-$text['description-apps']['pt-br'] = "Gerenciar as aplicações instaladas";
-$text['description-apps']['pt-pt'] = "Gerir as aplicações instaladas.";
-$text['description-apps']['ro-ro'] = "";
-$text['description-apps']['ru-ru'] = "Управление установленными приложениями.";
-$text['description-apps']['sv-se'] = "Hantera de applikationer som är installerade.";
-$text['description-apps']['uk-ua'] = "Керування встановленими додатками";
-$text['description-apps']['tr-tr'] = "Yüklü bulunan uygulamaları düzenleyin.";
-
-$text['description-app-edit']['en-us'] = "Manage the applications that are installed.";
-$text['description-app-edit']['en-gb'] = "Manage the applications that are installed.";
-$text['description-app-edit']['ar-eg'] = "";
-$text['description-app-edit']['de-at'] = "Installierte Applikationen verwalten"; //copied from de-de
-$text['description-app-edit']['de-ch'] = "Installierte Applikationen verwalten"; //copied from de-de
-$text['description-app-edit']['de-de'] = "Installierte Applikationen verwalten";
-$text['description-app-edit']['es-cl'] = "Administre las aplicaciones instaladas.";
-$text['description-app-edit']['es-mx'] = "Administre las aplicaciones instaladas."; //copied from es-cl
-$text['description-app-edit']['fr-ca'] = "Gérer les applications installées"; //copied from fr-fr
-$text['description-app-edit']['fr-fr'] = "Gérer les applications installées";
-$text['description-app-edit']['he-il'] = "";
-$text['description-app-edit']['it-it'] = "Gestisce le applicazioni installate.";
-$text['description-app-edit']['nl-nl'] = "";
-$text['description-app-edit']['pl-pl'] = "Zarządzajnie zainstalowanymi aplikacjami.";
-$text['description-app-edit']['pt-br'] = "Gerenciar as aplicações instaladas";
-$text['description-app-edit']['pt-pt'] = "Gerir as aplicações instaladas.";
-$text['description-app-edit']['ro-ro'] = "";
-$text['description-app-edit']['ru-ru'] = "Управление установленными приложениями.";
-$text['description-app-edit']['sv-se'] = "Hantera de applikationer som är installerade.";
-$text['description-app-edit']['uk-ua'] = "Керування встановленими додатками";
-$text['description-app-edit']['tr-tr'] = "Yüklü bulunan uygulamaları düzenleyin.";
-
-
-?>

+ 0 - 28
core/apps/app_menu.php

@@ -1,28 +0,0 @@
-<?php
-
-	$y=0;	
-	$apps[$x]['menu'][$y]['title']['en-us'] = "App Manager";
-	$apps[$x]['menu'][$y]['title']['en-gb'] = "App Manager";
-	$apps[$x]['menu'][$y]['title']['ar-eg'] = "";
-	$apps[$x]['menu'][$y]['title']['de-at'] = "Applikation Verwalten";
-	$apps[$x]['menu'][$y]['title']['de-de'] = "Applikation Verwalten";
-	$apps[$x]['menu'][$y]['title']['es-cl'] = "Administrador de Aplicaciones";
-	$apps[$x]['menu'][$y]['title']['es-mx'] = "";
-	$apps[$x]['menu'][$y]['title']['fr-ca'] = "";
-	$apps[$x]['menu'][$y]['title']['fr-fr'] = "Gestion App";
-	$apps[$x]['menu'][$y]['title']['he-il'] = "";
-	$apps[$x]['menu'][$y]['title']['it-it'] = "";
-	$apps[$x]['menu'][$y]['title']['nl-nl'] = "";
-	$apps[$x]['menu'][$y]['title']['pl-pl'] = "Menedżer aplikacji";
-	$apps[$x]['menu'][$y]['title']['pt-br'] = "Gerenciador de aplicações";
-	$apps[$x]['menu'][$y]['title']['pt-pt'] = "Gestor de Aplicações";
-	$apps[$x]['menu'][$y]['title']['ro-ro'] = "";
-	$apps[$x]['menu'][$y]['title']['ru-ru'] = "Менеджер приложений";
-	$apps[$x]['menu'][$y]['title']['sv-se'] = "App Inställningar";
-	$apps[$x]['menu'][$y]['uuid'] = "ef00f229-7890-00c2-bf23-fed5b8fa9fe7";
-	$apps[$x]['menu'][$y]['parent_uuid'] = "594d99c5-6128-9c88-ca35-4b33392cec0f";
-	$apps[$x]['menu'][$y]['category'] = "internal";
-	$apps[$x]['menu'][$y]['path'] = "/core/apps/apps.php";
-	$apps[$x]['menu'][$y]['groups'][] = "superadmin";
-
-?>

+ 0 - 106
core/apps/apps.php

@@ -1,106 +0,0 @@
-<?php
-/*
-	FusionPBX
-	Version: MPL 1.1
-
-	The contents of this file are subject to the Mozilla Public License Version
-	1.1 (the "License"); you may not use this file except in compliance with
-	the License. You may obtain a copy of the License at
-	http://www.mozilla.org/MPL/
-
-	Software distributed under the License is distributed on an "AS IS" basis,
-	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-	for the specific language governing rights and limitations under the
-	License.
-
-	The Original Code is FusionPBX
-
-	The Initial Developer of the Original Code is
-	Mark J Crane <[email protected]>
-	Portions created by the Initial Developer are Copyright (C) 2008-2020
-	the Initial Developer. All Rights Reserved.
-
-	Contributor(s):
-	Mark J Crane <[email protected]>
-*/
-
-//includes
-	require_once "root.php";
-	require_once "resources/require.php";
-	require_once "resources/check_auth.php";
-	require_once "resources/paging.php";
-
-//check permissions
-	if (if_group("admin") || if_group("superadmin")) {
-		//access granted
-	}
-	else {
-		echo "access denied";
-		exit;
-	}
-
-//add multi-lingual support
-	$language = new text;
-	$text = $language->get();
-
-//get variables used to control the order
-	$order_by = $_GET["order_by"];
-	$order = $_GET["order"];
-
-//get the list of installed apps from the core and mod directories
-	$config_list = glob($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH."/*/*/app_config.php");
-	$x=0;
-	foreach ($config_list as $config_path) {
-		include($config_path);
-		$x++;
-	}
-
-//include the header
-	$document['title'] = $text['title-apps'];
-	require_once "resources/header.php";
-
-//show the content
-	echo "<div class='action_bar' id='action_bar'>\n";
-	echo "	<div class='heading'><b>".$text['header-apps']."</b></div>\n";
-	echo "	<div class='actions'>\n";
-	echo "	</div>\n";
-	echo "	<div style='clear: both;'></div>\n";
-	echo "</div>\n";
-
-	echo $text['description-apps'];
-	echo "<br /><br />\n";
-
-	echo "<table class='list'>\n";
-	echo "<tr class='list-header'>\n";
-	echo "	<th>".$text['label-name']."</th>\n";
-	echo "	<th>".$text['label-category']."</th>\n";
-	echo "	<th>".$text['label-subcategory']."</th>\n";
-	echo "	<th class='center'>".$text['label-version']."</th>\n";
-	echo "	<th class='hide-sm-dn'>".$text['label-description']."</th>\n";
-	echo "</tr>\n";
-
-	foreach ($apps as $row) {
-		if ($row['uuid'] == "d8704214-75a0-e52f-1336-f0780e29fef8") { continue; }
-
-		$description = $row['description'][$_SESSION['domain']['language']['code']];
-		if (strlen($description) == 0) { $description = $row['description']['en-us']; }
-		if (strlen($description) == 0) { $description = ''; }
-		$row['$description'] = $description;
-
-		echo "<tr class='list-row' href='".$list_row_url."'>\n";
-		echo "	<td class='no-wrap'>".$row['name']."</td>\n";
-		echo "	<td>".escape($row['category'])."&nbsp;</td>\n";
-		echo "	<td>".escape($row['subcategory'])."&nbsp;</td>\n";
-		echo "	<td class='center'>".escape($row['version'])."&nbsp;</td>\n";
-		echo "	<td class='description overflow hide-sm-dn pct-35'>".escape($row['$description'])."</td>\n";
-		echo "</tr>\n";
-	}
-	unset($apps);
-
-	echo "</table>";
-	echo "<br /><br />";
-
-//include the footer
-	require_once "resources/footer.php";
-
-?>

+ 0 - 90
core/apps/root.php

@@ -1,90 +0,0 @@
-<?php
-/*
-	FusionPBX
-	Version: MPL 1.1
-
-	The contents of this file are subject to the Mozilla Public License Version
-	1.1 (the "License"); you may not use this file except in compliance with
-	the License. You may obtain a copy of the License at
-	http://www.mozilla.org/MPL/
-
-	Software distributed under the License is distributed on an "AS IS" basis,
-	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-	for the specific language governing rights and limitations under the
-	License.
-
-	The Original Code is FusionPBX
-
-	The Initial Developer of the Original Code is
-	Mark J Crane <[email protected]>
-	Portions created by the Initial Developer are Copyright (C) 2008-2012
-	the Initial Developer. All Rights Reserved.
-
-	Contributor(s):
-	Mark J Crane <[email protected]>
-*/
-
-// make sure the PATH_SEPARATOR is defined
-	umask(2);
-	if (!defined("PATH_SEPARATOR")) {
-		if (strpos($_ENV["OS"], "Win") !== false) {
-			define("PATH_SEPARATOR", ";");
-		} else {
-			define("PATH_SEPARATOR", ":");
-		}
-	}
-
-	if (!isset($output_format)) $output_format = (PHP_SAPI == 'cli') ? 'text' : 'html';
-
-	// make sure the document_root is set
-	$_SERVER["SCRIPT_FILENAME"] = str_replace("\\", '/', $_SERVER["SCRIPT_FILENAME"]);
-	if(PHP_SAPI == 'cli'){
-		chdir(pathinfo(realpath($_SERVER["PHP_SELF"]), PATHINFO_DIRNAME));
-		$script_full_path = str_replace("\\", '/', getcwd() . '/' . $_SERVER["SCRIPT_FILENAME"]);
-		$dirs = explode('/', pathinfo($script_full_path, PATHINFO_DIRNAME));
-		if (file_exists('/project_root.php')) {
-			$path = '/';
-		} else {
-			$i    = 1;
-			$path = '';
-			while ($i < count($dirs)) {
-				$path .= '/' . $dirs[$i];
-				if (file_exists($path. '/project_root.php')) {
-					break;
-				}
-				$i++;
-			}
-		}
-		$_SERVER["DOCUMENT_ROOT"] = $path;
-	}else{
-		$_SERVER["DOCUMENT_ROOT"]   = str_replace($_SERVER["PHP_SELF"], "", $_SERVER["SCRIPT_FILENAME"]);
-	}
-	$_SERVER["DOCUMENT_ROOT"]   = realpath($_SERVER["DOCUMENT_ROOT"]);
-// try to detect if a project path is being used
-	if (!defined('PROJECT_PATH')) {
-		if (is_dir($_SERVER["DOCUMENT_ROOT"]. '/fusionpbx')) {
-			define('PROJECT_PATH', '/fusionpbx');
-		} elseif (file_exists($_SERVER["DOCUMENT_ROOT"]. '/project_root.php')) {
-			define('PROJECT_PATH', '');
-		} else {
-			$dirs = explode('/', str_replace('\\', '/', pathinfo($_SERVER["PHP_SELF"], PATHINFO_DIRNAME)));
-			$i    = 1;
-			$path = $_SERVER["DOCUMENT_ROOT"];
-			while ($i < count($dirs)) {
-				$path .= '/' . $dirs[$i];
-				if (file_exists($path. '/project_root.php')) {
-					break;
-				}
-				$i++;
-			}
-			if(!file_exists($path. '/project_root.php')){
-				die("Failed to locate the Project Root by searching for project_root.php please contact support for assistance");
-			}
-			$project_path = str_replace($_SERVER["DOCUMENT_ROOT"], "", $path);
-			define('PROJECT_PATH', $project_path);
-		}
-		$_SERVER["PROJECT_ROOT"] = realpath($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH);
-		set_include_path(get_include_path() . PATH_SEPARATOR . $_SERVER["PROJECT_ROOT"]);
-	}
-
-?>

+ 7 - 3
core/default_settings/app_config.php

@@ -82,7 +82,7 @@
 		$apps[$x]['default_settings'][$y]['default_setting_category'] = "domain";
 		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "time_zone";
 		$apps[$x]['default_settings'][$y]['default_setting_name'] = "name";
-		$apps[$x]['default_settings'][$y]['default_setting_value'] = "";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "UTC";
 		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
 		$apps[$x]['default_settings'][$y]['default_setting_description'] = "";
 		$y++;
@@ -487,7 +487,10 @@
 		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
 		$z++;
 		$apps[$x]['db'][$y]['fields'][$z]['name'] = "default_setting_enabled";
-		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['pgsql'] = "boolean";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['sqlite'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['mysql'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['toggle'] = ['true','false'];
 		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
 		$z++;
 		$apps[$x]['db'][$y]['fields'][$z]['name'] = "default_setting_description";
@@ -539,7 +542,8 @@
 		$apps[$x]['db'][$y]['fields'][$z]['type'] = "numeric";
 		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "The numerical code.";
 		$z++;
-		$apps[$x]['db'][$y]['fields'][$z]['name'] = "calling_code";
+		$apps[$x]['db'][$y]['fields'][$z]['name']['text'] = "country_code";
+		$apps[$x]['db'][$y]['fields'][$z]['name']['deprecated'] = "calling_code";
 		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
 		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "The calling code.";
 

+ 1 - 1
core/default_settings/app_defaults.php

@@ -215,7 +215,7 @@
 			$database = new database;
 			$num_rows = $database->select($sql, null, 'column');
 			if ($num_rows == 0) {
-				$sql = "insert into v_countries (country_uuid, country, iso_a2, iso_a3, num, calling_code) values ";
+				$sql = "insert into v_countries (country_uuid, country, iso_a2, iso_a3, num, country_code) values ";
 				$sql .= "('".uuid()."', 'Afghanistan', 'AF', 'AFG', 4, '93'), ";
 				$sql .= "('".uuid()."', 'Albania', 'AL', 'ALB', 8, '355'), ";
 				$sql .= "('".uuid()."', 'Algeria', 'DZ', 'DZA', 12, '213'), ";

+ 36 - 3
core/default_settings/default_setting_edit.php

@@ -170,6 +170,11 @@
 						$cache = new cache;
 						$cache->delete("dialplan:".$domain_name);
 				}
+				elseif ($default_setting_category == "destinations" && $default_setting_subcategory == "dialplan_mode" ) {
+					//clear the cache
+						$cache = new cache;
+						$cache->delete("dialplan:mode");
+				}
 
 				//build the array of data
 				$x = 0;
@@ -206,7 +211,8 @@
 //pre-populate the form
 	if (count($_GET) > 0 && $_POST["persistformvar"] != "true") {
 		$default_setting_uuid = $_GET["id"];
-		$sql = "select * from v_default_settings ";
+		$sql = "select default_setting_uuid, default_setting_category, default_setting_subcategory, default_setting_name, default_setting_value, cast(default_setting_enabled as text), default_setting_description ";
+		$sql .= "from v_default_settings ";
 		$sql .= "where default_setting_uuid = :default_setting_uuid ";
 		$parameters['default_setting_uuid'] = $default_setting_uuid;
 		$database = new database;
@@ -609,6 +615,33 @@
 		echo "    	<option value='never' ".($default_setting_value == "never" ? "selected='selected'" : null).">".$text['option-button_icons_never']."</option>\n";
 		echo "    </select>\n";
 	}
+	elseif ($category == "theme" && $subcategory == "menu_side_state" && $name == "text" ) {
+		echo "    <select class='formfld' id='default_setting_value' name='default_setting_value'>\n";
+		echo "    	<option value='expanded'>".$text['option-expanded']."</option>\n";
+		echo "    	<option value='contracted' ".($default_setting_value == "contracted" ? "selected='selected'" : null).">".$text['option-contracted']."</option>\n";
+		echo "    	<option value='hidden' ".($default_setting_value == "hidden" ? "selected='selected'" : null).">".$text['option-hidden']."</option>\n";
+		echo "    </select>\n";
+	}
+	elseif ($category == "theme" && $subcategory == "menu_side_toggle" && $name == "text" ) {
+		echo "    <select class='formfld' id='default_setting_value' name='default_setting_value'>\n";
+		echo "    	<option value='hover'>".$text['option-hover']."</option>\n";
+		echo "    	<option value='click' ".($default_setting_value == "click" ? "selected='selected'" : null).">".$text['option-click']."</option>\n";
+		echo "    </select>\n";
+	}
+	elseif ($category == "theme" && $subcategory == "menu_side_toggle_body_width" && $name == "text" ) {
+		echo "    <select class='formfld' id='default_setting_value' name='default_setting_value'>\n";
+		echo "    	<option value='shrink'>".$text['option-shrink']."</option>\n";
+		echo "    	<option value='fixed' ".($default_setting_value == "fixed" ? "selected='selected'" : null).">".$text['option-fixed']."</option>\n";
+		echo "    </select>\n";
+	}
+	elseif ($category == "theme" && $subcategory == "body_header_brand_type" && $name == "text" ) {
+		echo "    <select class='formfld' id='default_setting_value' name='default_setting_value'>\n";
+		echo "    	<option value='image' ".(($default_setting_value == "image") ? "selected='selected'" : null).">".$text['label-image']."</option>\n";
+		echo "    	<option value='text' ".(($default_setting_value == "text") ? "selected='selected'" : null).">".$text['label-text']."</option>\n";
+		echo "    	<option value='image_text' ".(($default_setting_value == "image_text") ? "selected='selected'" : null).">".$text['label-image_text']."</option>\n";
+		echo "    	<option value='none' ".(($default_setting_value == "none") ? "selected='selected'" : null).">".$text['label-none']."</option>\n";
+		echo "    </select>\n";
+	}
 	elseif ($category == "voicemail" && $subcategory == "voicemail_file" && $name == "text" ) {
 		echo "    <select class='formfld' id='default_setting_value' name='default_setting_value'>\n";
 		echo "    	<option value='listen' ".(($default_setting_value == "listen") ? "selected='selected'" : null).">".$text['option-voicemail_file_listen']."</option>\n";
@@ -701,7 +734,7 @@
 	echo "	".$text['label-description']."\n";
 	echo "</td>\n";
 	echo "<td class='vtable' align='left'>\n";
-	echo "	<input class='formfld' type='text' name='default_setting_description' maxlength='255' value=\"".$default_setting_description."\">\n";
+	echo "	<input class='formfld' type='text' name='default_setting_description' style='width: 80%; max-width: 600px; min-width: 167px;' maxlength='255' value=\"".$default_setting_description."\">\n";
 	echo "<br />\n";
 	echo $text['description-description']."\n";
 	echo "</td>\n";
@@ -739,4 +772,4 @@
 //include the footer
 	require_once "resources/footer.php";
 
-?>
+?>

+ 28 - 1
core/default_settings/default_settings.php

@@ -104,7 +104,24 @@
 	$num_rows = $database->select($sql, $parameters, 'column');
 
 //get the list
-	$sql = str_replace('count(default_setting_uuid)', '*', $sql);
+	$sql = "select default_setting_uuid, default_setting_category, default_setting_subcategory, default_setting_name, ";
+	$sql .= "default_setting_value, cast(default_setting_enabled as text), default_setting_description ";
+	$sql .= "from v_default_settings ";
+	if (isset($search) && strlen($search) > 0) {
+		$sql .= "where (";
+		$sql .= "	lower(default_setting_category) like :search ";
+		$sql .= "	or lower(default_setting_subcategory) like :search ";
+		$sql .= "	or lower(default_setting_name) like :search ";
+		$sql .= "	or lower(default_setting_value) like :search ";
+		$sql .= "	or lower(default_setting_description) like :search ";
+		$sql .= ") ";
+		$parameters['search'] = '%'.$search.'%';
+	}
+	if (isset($default_setting_category) && strlen($default_setting_category) > 0) {
+		$sql .= (stripos($sql,'WHERE') === false) ? 'where ' : 'and ';
+		$sql .= "lower(default_setting_category) = :default_setting_category ";
+		$parameters['default_setting_category'] = strtolower($default_setting_category);
+	}
 	$sql .= order_by($order_by, $order, 'default_setting_category, default_setting_subcategory, default_setting_order', 'asc');
 	$sql .= limit_offset($rows_per_page, $offset);
 	$database = new database;
@@ -324,6 +341,7 @@
 				( $category == "theme" && $subcategory == "menu_brand_type" && $name == "text" ) ||
 				( $category == "theme" && $subcategory == "menu_style" && $name == "text" ) ||
 				( $category == "theme" && $subcategory == "menu_position" && $name == "text" ) ||
+				( $category == "theme" && $subcategory == "body_header_brand_type" && $name == "text" ) ||
 				( $category == "theme" && $subcategory == "logo_align" && $name == "text" )
 				) {
 				echo "		".$text['label-'.$row['default_setting_value']];
@@ -337,6 +355,15 @@
 			else if ($category == 'theme' && $subcategory == 'button_icons' && $name == 'text') {
 				echo "		".$text['option-button_icons_'.$row['default_setting_value']]."\n";
 			}
+			else if ($category == 'theme' && $subcategory == 'menu_side_state' && $name == 'text') {
+				echo "		".$text['option-'.$row['default_setting_value']]."\n";
+			}
+			else if ($category == 'theme' && $subcategory == 'menu_side_toggle' && $name == 'text') {
+				echo "		".$text['option-'.$row['default_setting_value']]."\n";
+			}
+			else if ($category == 'theme' && $subcategory == 'menu_side_toggle_body_width' && $name == 'text') {
+				echo "		".$text['option-'.$row['default_setting_value']]."\n";
+			}
 			else if ($category == "theme" && substr_count($subcategory, "_color") > 0 && ($name == "text" || $name == 'array')) {
 				echo "		".(img_spacer('15px', '15px', 'background: '.escape($row['default_setting_value']).'; margin-right: 4px; vertical-align: middle; border: 1px solid '.(color_adjust($row['default_setting_value'], -0.18)).'; padding: -1px;'));
 				echo "<span style=\"font-family: 'Courier New'; line-height: 6pt;\">".escape($row['default_setting_value'])."</span>\n";

+ 4 - 1
core/domain_settings/app_config.php

@@ -100,7 +100,10 @@
 		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
 		$z++;
 		$apps[$x]['db'][$y]['fields'][$z]['name'] = "domain_setting_enabled";
-		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['pgsql'] = "boolean";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['sqlite'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['mysql'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['toggle'] = ['true','false'];
 		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
 		$z++;
 		$apps[$x]['db'][$y]['fields'][$z]['name'] = "domain_setting_description";

+ 42 - 0
core/domain_settings/app_languages.php

@@ -22,6 +22,27 @@ $text['title-domains']['ru-ru'] = "Домены";
 $text['title-domains']['sv-se'] = "Domäner";
 $text['title-domains']['uk-ua'] = "Домени";
 
+$text['title-domain_settings']['en-us'] = "Domain Setting";
+$text['title-domain_settings']['en-gb'] = "Domain Setting";
+$text['title-domain_settings']['ar-eg'] = "";
+$text['title-domain_settings']['de-at'] = "Domain Einstellungen"; //copied from de-de
+$text['title-domain_settings']['de-ch'] = "Domain Einstellungen"; //copied from de-de
+$text['title-domain_settings']['de-de'] = "Domain Einstellungen";
+$text['title-domain_settings']['es-cl'] = "Configuraciones de dominio.";
+$text['title-domain_settings']['es-mx'] = "Configuraciones de dominio."; //copied from es-cl
+$text['title-domain_settings']['fr-ca'] = "Paramètres du domaine"; //copied from fr-fr
+$text['title-domain_settings']['fr-fr'] = "Paramètres du domaine";
+$text['title-domain_settings']['he-il'] = "";
+$text['title-domain_settings']['it-it'] = "Parametri di Dominio";
+$text['title-domain_settings']['nl-nl'] = "";
+$text['title-domain_settings']['pl-pl'] = "Ustawienia domen";
+$text['title-domain_settings']['pt-br'] = "Configurações do dominio";
+$text['title-domain_settings']['pt-pt'] = "Definições do Domínio";
+$text['title-domain_settings']['ro-ro'] = "";
+$text['title-domain_settings']['ru-ru'] = "Настройки домена";
+$text['title-domain_settings']['sv-se'] = "Domän Inställning";
+$text['title-domain_settings']['uk-ua'] = "Налаштування доменів";
+
 $text['title-domain_setting-edit']['en-us'] = "Domain Setting";
 $text['title-domain_setting-edit']['en-gb'] = "Domain Setting";
 $text['title-domain_setting-edit']['ar-eg'] = "";
@@ -106,6 +127,27 @@ $text['title-domain-add']['ru-ru'] = "Добавить домен";
 $text['title-domain-add']['sv-se'] = "Lägg Till Domän";
 $text['title-domain-add']['uk-ua'] = "Новий домен";
 
+$text['header_description-domain_settings']['en-us'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['en-gb'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['ar-eg'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['de-at'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['de-ch'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['de-de'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['es-cl'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['es-mx'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['fr-ca'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['fr-fr'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['he-il'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['it-it'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['nl-nl'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['pl-pl'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['pt-br'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['pt-pt'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['ro-ro'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['ru-ru'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['sv-se'] = "Settings for this domain override those defined in Default Settings.";
+$text['header_description-domain_settings']['uk-ua'] = "Settings for this domain override those defined in Default Settings.";
+
 $text['message-delete_failed']['en-us'] = "No Settings Checked";
 $text['message-delete_failed']['en-gb'] = "No Settings Checked";
 $text['message-delete_failed']['ar-eg'] = "";

+ 33 - 4
core/domain_settings/domain_setting_edit.php

@@ -317,7 +317,7 @@ if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
 				if ($action == "add") {
 					message::add($text['message-add']);
 				}
-				header("Location: ".PROJECT_PATH."/core/domains/domain_edit.php?id=".$domain_uuid);
+				header("Location: ".PROJECT_PATH."/core/domain_settings/domain_settings.php?id=".$domain_uuid);
 				exit;
 		}
 }
@@ -325,7 +325,8 @@ if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
 //pre-populate the form
 	if (count($_GET)>0 && $_POST["persistformvar"] != "true" && is_uuid($_GET["id"])) {
 		$domain_setting_uuid = $_GET["id"];
-		$sql = "select * from v_domain_settings ";
+		$sql = "select domain_setting_uuid, domain_setting_category, domain_setting_subcategory, domain_setting_name, domain_setting_value, cast(domain_setting_enabled as text), domain_setting_description ";
+		$sql .= "from v_domain_settings ";
 		$sql .= "where domain_uuid = :domain_uuid ";
 		$sql .= "and domain_setting_uuid = :domain_setting_uuid ";
 		$parameters['domain_uuid'] = $domain_uuid;
@@ -631,6 +632,7 @@ if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
 		echo "    <select class='formfld' id='domain_setting_value' name='domain_setting_value'>\n";
 		echo "    	<option value='image' ".(($row['domain_setting_value'] == "image") ? "selected='selected'" : null).">".$text['label-image']."</option>\n";
 		echo "    	<option value='text' ".(($row['domain_setting_value'] == "text") ? "selected='selected'" : null).">".$text['label-text']."</option>\n";
+		echo "    	<option value='image_text' ".(($row['domain_setting_value'] == "image_text") ? "selected='selected'" : null).">".$text['label-image_text']."</option>\n";
 		echo "    	<option value='none' ".(($row['domain_setting_value'] == "none") ? "selected='selected'" : null).">".$text['label-none']."</option>\n";
 		echo "    </select>\n";
 	}
@@ -666,6 +668,33 @@ if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
 		echo "    	<option value='never' ".($row['domain_setting_value'] == "never" ? "selected='selected'" : null).">".$text['option-button_icons_never']."</option>\n";
 		echo "    </select>\n";
 	}
+	elseif ($category == "theme" && $subcategory == "menu_side_state" && $name == "text" ) {
+		echo "    <select class='formfld' id='domain_setting_value' name='domain_setting_value'>\n";
+		echo "    	<option value='expanded'>".$text['option-expanded']."</option>\n";
+		echo "    	<option value='contracted' ".($row['domain_setting_value'] == "contracted" ? "selected='selected'" : null).">".$text['option-contracted']."</option>\n";
+		echo "    	<option value='hidden' ".($row['domain_setting_value'] == "hidden" ? "selected='selected'" : null).">".$text['option-hidden']."</option>\n";
+		echo "    </select>\n";
+	}
+	elseif ($category == "theme" && $subcategory == "menu_side_toggle" && $name == "text" ) {
+		echo "    <select class='formfld' id='domain_setting_value' name='domain_setting_value'>\n";
+		echo "    	<option value='hover'>".$text['option-hover']."</option>\n";
+		echo "    	<option value='click' ".($row['domain_setting_value'] == "click" ? "selected='selected'" : null).">".$text['option-click']."</option>\n";
+		echo "    </select>\n";
+	}
+	elseif ($category == "theme" && $subcategory == "menu_side_toggle_body_width" && $name == "text" ) {
+		echo "    <select class='formfld' id='domain_setting_value' name='domain_setting_value'>\n";
+		echo "    	<option value='shrink'>".$text['option-shrink']."</option>\n";
+		echo "    	<option value='fixed' ".($row['domain_setting_value'] == "fixed" ? "selected='selected'" : null).">".$text['option-fixed']."</option>\n";
+		echo "    </select>\n";
+	}
+	elseif ($category == "theme" && $subcategory == "body_header_brand_type" && $name == "text" ) {
+		echo "    <select class='formfld' id='domain_setting_value' name='domain_setting_value'>\n";
+		echo "    	<option value='image' ".(($row['domain_setting_value'] == "image") ? "selected='selected'" : null).">".$text['label-image']."</option>\n";
+		echo "    	<option value='text' ".(($row['domain_setting_value'] == "text") ? "selected='selected'" : null).">".$text['label-text']."</option>\n";
+		echo "    	<option value='image_text' ".(($row['domain_setting_value'] == "image_text") ? "selected='selected'" : null).">".$text['label-image_text']."</option>\n";
+		echo "    	<option value='none' ".(($row['domain_setting_value'] == "none") ? "selected='selected'" : null).">".$text['label-none']."</option>\n";
+		echo "    </select>\n";
+	}
 	elseif ($category == "voicemail" && $subcategory == "voicemail_file" && $name == "text" ) {
 		echo "    <select class='formfld' id='domain_setting_value' name='domain_setting_value'>\n";
 		echo "    	<option value='listen' ".(($row['domain_setting_value'] == "listen") ? "selected='selected'" : null).">".$text['option-voicemail_file_listen']."</option>\n";
@@ -760,7 +789,7 @@ if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
 	echo "	".$text['label-description']."\n";
 	echo "</td>\n";
 	echo "<td class='vtable' align='left'>\n";
-	echo "	<input class='formfld' type='text' name='domain_setting_description' maxlength='255' value=\"".escape($domain_setting_description)."\">\n";
+	echo "	<input class='formfld' type='text' name='domain_setting_description' style='width: 80%; max-width: 600px; min-width: 167px;' maxlength='255' value=\"".escape($domain_setting_description)."\">\n";
 	echo "<br />\n";
 	echo $text['description-description']."\n";
 	echo "</td>\n";
@@ -794,4 +823,4 @@ if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
 //include the footer
 	require_once "resources/footer.php";
 
-?>
+?>

+ 45 - 8
core/domain_settings/domain_settings.php

@@ -17,7 +17,7 @@
 
  The Initial Developer of the Original Code is
  Mark J Crane <[email protected]>
- Portions created by the Initial Developer are Copyright (C) 2008-2019
+ Portions created by the Initial Developer are Copyright (C) 2008-2020
  the Initial Developer. All Rights Reserved.
 
  Contributor(s):
@@ -38,6 +38,15 @@
 		exit;
 	}
 
+//add multi-lingual support
+	$language = new text;
+	$text = $language->get();
+
+//get the domain_uuid
+	if (is_uuid($_GET['id'])) {
+		$domain_uuid = $_GET['id'];
+	}
+
 //get the http post data
 	if ($_POST['action'] != '') {
 		$action = $_POST['action'];
@@ -74,7 +83,7 @@
 			}
 
 		//redirect
-			header('Location: '.PROJECT_PATH.'/core/domains/domain_edit.php?id='.urlencode($_REQUEST['domain_uuid']));
+			header('Location: '.PROJECT_PATH.'/core/domain_settings/domain_settings.php?id='.urlencode($_REQUEST['domain_uuid']));
 			exit;
 	}
 
@@ -82,6 +91,13 @@
 	$order_by = $_GET["order_by"];
 	$order = $_GET["order"];
 
+//get the domain_name
+	$sql = "select domain_name from v_domains ";
+	$sql .= "where domain_uuid = :domain_uuid ";
+	$parameters['domain_uuid'] = $domain_uuid;
+	$database = new database;
+	$domain_name = $database->select($sql, $parameters, 'column');
+
 //prepare to page the results
 	$sql = "select count(domain_setting_uuid) from v_domain_settings ";
 	$sql .= "where domain_uuid = :domain_uuid ";
@@ -90,13 +106,17 @@
 	$num_rows = $database->select($sql, $parameters, 'column');
 
 //get the list
-	$sql = str_replace('count(domain_setting_uuid)', '*', $sql);
+	$sql = "select domain_setting_uuid, domain_setting_category, domain_setting_subcategory, domain_setting_name, ";
+	$sql .= "domain_setting_value, cast(domain_setting_enabled as text), domain_setting_description ";
+	$sql .= "from v_domain_settings ";
+	$sql .= "where domain_uuid = :domain_uuid ";
 	if ($order_by == '') {
-		$sql .= " order by domain_setting_category, domain_setting_subcategory, domain_setting_order asc, domain_setting_name, domain_setting_value ";
+		$sql .= "order by domain_setting_category, domain_setting_subcategory, domain_setting_order asc, domain_setting_name, domain_setting_value ";
 	}
 	else {
 		$sql .= order_by($order_by, $order);
 	}
+	$parameters['domain_uuid'] = $domain_uuid;
 	$database = new database;
 	$domain_settings = $database->select($sql, $parameters, 'all');
 	unset($sql, $parameters);
@@ -105,6 +125,10 @@
 	$object = new token;
 	$token = $object->create('/core/domain_settings/domain_settings.php');
 
+//include the header
+	$document['title'] = $text['title-domain_settings'];
+	require_once "resources/header.php";
+
 //copy settings javascript
 	if (
 		permission_exists("domain_select") &&
@@ -136,9 +160,9 @@
 
 //show the content
 	echo "<div class='action_bar' id='action_bar_sub'>\n";
-	echo "	<div class='heading'><b id='heading_sub'>".$text['header-domain_settings']." (".$num_rows.")</b></div>\n";
+	echo "	<div class='heading'><b id='heading_sub'>".$domain_name." (".$num_rows.")</b></div>\n"; //$text['title-domain_settings']
 	echo "	<div class='actions'>\n";
-	echo button::create(['type'=>'button','label'=>$text['button-back'],'icon'=>$_SESSION['theme']['button_icon_back'],'id'=>'action_bar_sub_button_back','style'=>'margin-right: 15px; display: none;','link'=>'domains.php']);
+	echo button::create(['type'=>'button','label'=>$text['button-back'],'icon'=>$_SESSION['theme']['button_icon_back'],'id'=>'action_bar_sub_button_back','style'=>'','link'=>PROJECT_PATH.'/core/domains/domains.php']);
 	if (permission_exists('default_setting_view') && $num_rows) {
 		echo button::create(['type'=>'button','label'=>$text['button-reload'],'icon'=>$_SESSION['theme']['button_icon_reload'],'style'=>'margin-right: 15px;','link'=>PROJECT_PATH.'/core/default_settings/default_settings_reload.php?id='.$domain_uuid]);
 	}
@@ -234,7 +258,7 @@
 				echo "</tr>\n";
 			}
 			if (permission_exists('domain_setting_edit')) {
-				$list_row_url = PROJECT_PATH."/core/domain_settings/domain_setting_edit.php?domain_uuid=".escape($row['domain_uuid'])."&id=".escape($row['domain_setting_uuid']);
+				$list_row_url = PROJECT_PATH."/core/domain_settings/domain_setting_edit.php?domain_uuid=".escape($domain_uuid)."&id=".escape($row['domain_setting_uuid']);
 			}
 			echo "<tr class='list-row' href='".$list_row_url."'>\n";
 			if (permission_exists('domain_setting_add') || permission_exists('domain_setting_edit') || permission_exists('domain_setting_delete')) {
@@ -284,6 +308,7 @@
 				( $category == "theme" && $subcategory == "menu_brand_type" && $name == "text" ) ||
 				( $category == "theme" && $subcategory == "menu_style" && $name == "text" ) ||
 				( $category == "theme" && $subcategory == "menu_position" && $name == "text" ) ||
+				( $category == "theme" && $subcategory == "body_header_brand_type" && $name == "text" ) ||
 				( $category == "theme" && $subcategory == "logo_align" && $name == "text" )
 				) {
 				echo "		".$text['label-'.escape($row['domain_setting_value'])];
@@ -294,6 +319,15 @@
 			else if ($category == 'theme' && $subcategory == 'button_icons' && $name == 'text') {
 				echo "		".$text['option-button_icons_'.$row['domain_setting_value']]."\n";
 			}
+			else if ($category == 'theme' && $subcategory == 'menu_side_state' && $name == 'text') {
+				echo "		".$text['option-'.$row['domain_setting_value']]."\n";
+			}
+			else if ($category == 'theme' && $subcategory == 'menu_side_toggle' && $name == 'text') {
+				echo "		".$text['option-'.$row['domain_setting_value']]."\n";
+			}
+			else if ($category == 'theme' && $subcategory == 'menu_side_toggle_body_width' && $name == 'text') {
+				echo "		".$text['option-'.$row['domain_setting_value']]."\n";
+			}
 			else if ($category == "theme" && substr_count($subcategory, "_color") > 0 && ($name == "text" || $name == 'array')) {
 				echo "		".(img_spacer('15px', '15px', 'background: '.escape($row['domain_setting_value']).'; margin-right: 4px; vertical-align: middle; border: 1px solid '.(color_adjust($row['domain_setting_value'], -0.18)).'; padding: -1px;'));
 				echo "<span style=\"font-family: 'Courier New'; line-height: 6pt;\">".escape($row['domain_setting_value'])."</span>\n";
@@ -351,4 +385,7 @@
 
 	echo "</script>\n";
 
-?>
+//include the footer
+	require_once "resources/footer.php";
+
+?>

+ 4 - 1
core/domains/app_config.php

@@ -82,7 +82,10 @@
 		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "Enter the domain name.";
 		$z++;
 		$apps[$x]['db'][$y]['fields'][$z]['name'] = "domain_enabled";
-		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['pgsql'] = "boolean";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['sqlite'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['mysql'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['toggle'] = ['true','false'];
 		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "Set the status of the domain.";
 		$z++;
 		$apps[$x]['db'][$y]['fields'][$z]['name'] = "domain_description";

+ 21 - 21
core/domains/app_languages.php

@@ -280,6 +280,27 @@ $text['message-delete_failed']['ru-ru'] = "Не выбрана настройк
 $text['message-delete_failed']['sv-se'] = "Ingen Inställning Markerad";
 $text['message-delete_failed']['uk-ua'] = "Налаштування не вказано";
 
+$text['message-domain_exists']['en-us'] = "Domain Already Exists";
+$text['message-domain_exists']['en-gb'] = "Domain Already Exists";
+$text['message-domain_exists']['ar-eg'] = "Domain Already Exists";
+$text['message-domain_exists']['de-at'] = "Domain Already Exists";
+$text['message-domain_exists']['de-ch'] = "Domain Already Exists";
+$text['message-domain_exists']['de-de'] = "Domain Already Exists";
+$text['message-domain_exists']['es-cl'] = "Domain Already Exists";
+$text['message-domain_exists']['es-mx'] = "Domain Already Exists";
+$text['message-domain_exists']['fr-ca'] = "Domain Already Exists";
+$text['message-domain_exists']['fr-fr'] = "Domain Already Exists";
+$text['message-domain_exists']['he-il'] = "Domain Already Exists";
+$text['message-domain_exists']['it-it'] = "Domain Already Exists";
+$text['message-domain_exists']['nl-nl'] = "Domain Already Exists";
+$text['message-domain_exists']['pl-pl'] = "Domain Already Exists";
+$text['message-domain_exists']['pt-br'] = "Domain Already Exists";
+$text['message-domain_exists']['pt-pt'] = "Domain Already Exists";
+$text['message-domain_exists']['ro-ro'] = "Domain Already Exists";
+$text['message-domain_exists']['ru-ru'] = "Domain Already Exists";
+$text['message-domain_exists']['sv-se'] = "Domain Already Exists";
+$text['message-domain_exists']['uk-ua'] = "Domain Already Exists";
+
 $text['label-web_fonts']['en-us'] = "Web Fonts";
 $text['label-web_fonts']['en-gb'] = "Web Fonts";
 $text['label-web_fonts']['ar-eg'] = "الخطوط على شبكة الإنترنت";
@@ -805,27 +826,6 @@ $text['header-domain_settings']['ru-ru'] = "Настройки домена";
 $text['header-domain_settings']['sv-se'] = "Domän Inställning";
 $text['header-domain_settings']['uk-ua'] = "Налаштування домену";
 
-$text['header_description-domain_settings']['en-us'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['en-gb'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['ar-eg'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['de-at'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['de-ch'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['de-de'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['es-cl'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['es-mx'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['fr-ca'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['fr-fr'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['he-il'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['it-it'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['nl-nl'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['pl-pl'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['pt-br'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['pt-pt'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['ro-ro'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['ru-ru'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['sv-se'] = "Settings for this domain that should override those defined in Default Settings.";
-$text['header_description-domain_settings']['uk-ua'] = "Settings for this domain that should override those defined in Default Settings.";
-
 $text['header-domain_setting-edit']['en-us'] = "Domain Setting";
 $text['header-domain_setting-edit']['en-gb'] = "Domain Setting";
 $text['header-domain_setting-edit']['ar-eg'] = "";

+ 89 - 81
core/domains/domain_edit.php

@@ -44,7 +44,7 @@
 	$text = $language->get();
 
 //action add or update
-	if (!permission_exists('domain_add') || (file_exists($_SERVER["PROJECT_ROOT"]."/app/domains/") && !permission_exists('domain_parent') && permission_exists('domain_descendants'))) {
+	if (!permission_exists('domain_add') || (file_exists($_SERVER["PROJECT_ROOT"]."/app/domains/") && !permission_exists('domain_all'))) {
 		//admin editing own domain/settings
 		$domain_uuid = $_SESSION['domain_uuid'];
 		$action = "update";
@@ -61,7 +61,7 @@
 
 //get http post variables and set them to php variables
 	if (count($_POST) > 0) {
-		$domain_name = $_POST["domain_name"];
+		$domain_name = strtolower($_POST["domain_name"]);
 		$domain_enabled = $_POST["domain_enabled"];
 		$domain_description = $_POST["domain_description"];
 	}
@@ -118,16 +118,60 @@
 			if ($_POST["persistformvar"] != "true") {
 				if ($action == "add" && permission_exists('domain_add')) {
 					$sql = "select count(*) from v_domains ";
-					$sql .= "where domain_name = :domain_name ";
+					$sql .= "where lower(domain_name) = :domain_name ";
 					$parameters['domain_name'] = $domain_name;
 					$database = new database;
 					$num_rows = $database->select($sql, $parameters, 'column');
 					unset($sql, $parameters);
 
 					if ($num_rows == 0) {
+
 						//add the domain name
-						$domain_enabled = 'true';
-						$domain_uuid = uuid();
+							$domain_enabled = 'true';
+							$domain_uuid = uuid();
+							$array['domains'][0]['domain_uuid'] = $domain_uuid;
+							$array['domains'][0]['domain_name'] = $domain_name;
+							$array['domains'][0]['domain_enabled'] = $domain_enabled;
+							$array['domains'][0]['domain_description'] = $domain_description;
+							$database = new database;
+							$database->app_name = 'domains';
+							$database->app_uuid = '8b91605b-f6d2-42e6-a56d-5d1ded01bb44';
+							$database->save($array);
+
+						//add dialplans to the domain
+							if (file_exists($_SERVER["PROJECT_ROOT"]."/app/dialplans/app_config.php")) {
+								//import the dialplans
+								$dialplan = new dialplan;
+								$dialplan->import($array['domains']);
+								unset($array);
+
+								//add xml for each dialplan where the dialplan xml is empty
+								$dialplans = new dialplan;
+								$dialplans->source = "details";
+								$dialplans->destination = "database";
+								$dialplans->context = $domain_name;
+								$dialplans->is_empty = "dialplan_xml";
+								$array = $dialplans->xml();
+							}
+					}
+					else {
+						message::add($text['message-domain_exists'],'negative');
+						header("Location: domains.php");
+						exit;
+					}
+				}
+
+				if ($action == "update" && permission_exists('domain_edit')) {
+
+					//get original domain name
+						$sql = "select domain_name from v_domains ";
+						$sql .= "where domain_uuid = :domain_uuid ";
+						$parameters['domain_uuid'] = $domain_uuid;
+						$database = new database;
+						$original_domain_name = $database->select($sql, $parameters, 'column');
+						unset($sql, $parameters);
+
+					//update domain name, description
 						$array['domains'][0]['domain_uuid'] = $domain_uuid;
 						$array['domains'][0]['domain_name'] = $domain_name;
 						$array['domains'][0]['domain_enabled'] = $domain_enabled;
@@ -137,7 +181,7 @@
 						$database->app_uuid = '8b91605b-f6d2-42e6-a56d-5d1ded01bb44';
 						$database->save($array);
 
-						//add dialplans to the domain
+					//add dialplans to the domain
 						if (file_exists($_SERVER["PROJECT_ROOT"]."/app/dialplans/app_config.php")) {
 							//import the dialplans
 							$dialplan = new dialplan;
@@ -152,47 +196,10 @@
 							$dialplans->is_empty = "dialplan_xml";
 							$array = $dialplans->xml();
 						}
-					}
-				}
-
-				if ($action == "update" && permission_exists('domain_edit')) {
-					// get original domain name
-					$sql = "select domain_name from v_domains ";
-					$sql .= "where domain_uuid = :domain_uuid ";
-					$parameters['domain_uuid'] = $domain_uuid;
-					$database = new database;
-					$original_domain_name = $database->select($sql, $parameters, 'column');
-					unset($sql, $parameters);
-
-					// update domain name, description
-					$array['domains'][0]['domain_uuid'] = $domain_uuid;
-					$array['domains'][0]['domain_name'] = $domain_name;
-					$array['domains'][0]['domain_enabled'] = $domain_enabled;
-					$array['domains'][0]['domain_description'] = $domain_description;
-					$database = new database;
-					$database->app_name = 'domains';
-					$database->app_uuid = '8b91605b-f6d2-42e6-a56d-5d1ded01bb44';
-					$database->save($array);
-
-					// add dialplans to the domain
-					if (file_exists($_SERVER["PROJECT_ROOT"]."/app/dialplans/app_config.php")) {
-						//import the dialplans
-						$dialplan = new dialplan;
-						$dialplan->import($array['domains']);
-						unset($array);
-
-						//add xml for each dialplan where the dialplan xml is empty
-						$dialplans = new dialplan;
-						$dialplans->source = "details";
-						$dialplans->destination = "database";
-						$dialplans->context = $domain_name;
-						$dialplans->is_empty = "dialplan_xml";
-						$array = $dialplans->xml();
-					}
 
 					if ($original_domain_name != $domain_name) {
 
-						// update dialplans
+						//update dialplans
 							if (file_exists($_SERVER["PROJECT_ROOT"]."/app/dialplans/app_config.php")) {
 								$sql = "update v_dialplans set ";
 								$sql .= "dialplan_context = replace(dialplan_context, :domain_name_old, :domain_name_new), ";
@@ -216,7 +223,7 @@
 								unset($sql, $parameters);
 							}
 
-						// update destinations
+						//update destinations
 							if (file_exists($_SERVER["PROJECT_ROOT"]."/app/destinations/app_config.php")) {
 								$sql = "update v_destinations set ";
 								$sql .= "destination_data = replace(destination_data, :destination_data_old, :destination_data_new) ";
@@ -229,7 +236,7 @@
 								unset($sql, $parameters);
 							}
 
-						// update extensions (accountcode, user_context, dial_domain)
+						//update extensions (accountcode, user_context, dial_domain)
 							if (file_exists($_SERVER["PROJECT_ROOT"]."/app/extensions/app_config.php")) {
 								$sql = "update v_extensions set ";
 								$sql .= "user_context = replace(user_context, :domain_name_old, :domain_name_new), ";
@@ -244,7 +251,7 @@
 								unset($sql, $parameters);
 							}
 
-						// update ivr_menus (ivr_menu_context, ivr_menu_greet_long, ivr_menu_greet_short) and ivr_menu_options (ivr_menu_option_param)
+						//update ivr_menus (ivr_menu_context, ivr_menu_greet_long, ivr_menu_greet_short) and ivr_menu_options (ivr_menu_option_param)
 							if (file_exists($_SERVER["PROJECT_ROOT"]."/app/ivr_menus/app_config.php")) {
 								$sql = "update v_ivr_menus set ";
 								$sql .= "ivr_menu_context = replace(ivr_menu_context, :domain_name_old, :domain_name_new), ";
@@ -269,7 +276,7 @@
 								unset($sql, $parameters);
 							}
 
-						// update ring_groups (ring_group_context, ring_group_forward_destination, ring_group_timeout_data)
+						//update ring_groups (ring_group_context, ring_group_forward_destination, ring_group_timeout_data)
 							if (file_exists($_SERVER["PROJECT_ROOT"]."/app/ring_groups/app_config.php")) {
 								$sql = "update v_ring_groups set ";
 								$sql .= "ring_group_context = replace(ring_group_context, :domain_name_old, :domain_name_new), ";
@@ -284,7 +291,7 @@
 								unset($sql, $parameters);
 							}
 
-						// update cdr records (domain_name, context)
+						//update cdr records (domain_name, context)
 							if (file_exists($_SERVER["PROJECT_ROOT"]."/app/xml_cdr/app_config.php")){
 								$sql = "update v_xml_cdr set ";
 								$sql .= "domain_name = :domain_name_new ";
@@ -309,7 +316,7 @@
 								unset($sql, $parameters);
 							}
 
-						// update billing, if installed
+						//update billing, if installed
 							if (file_exists($_SERVER["PROJECT_ROOT"]."/app/billing/app_config.php")){
 								$sql = "update v_billings set ";
 								$sql .= "type_value = :type_value_new ";
@@ -323,7 +330,7 @@
 								unset($sql, $parameters);
 							}
 
-						// update conference session recording paths
+						//update conference session recording paths
 							if (file_exists($_SERVER["PROJECT_ROOT"]."/app/conference_centers/app_config.php")) {
 								$sql = "update v_conference_sessions set ";
 								$sql .= "recording = replace(recording, :domain_name_old, :domain_name_new) ";
@@ -336,7 +343,7 @@
 								unset($sql, $parameters);
 							}
 
-						// update conference center greetings
+						//update conference center greetings
 							if (file_exists($_SERVER["PROJECT_ROOT"]."/app/conference_centers/app_config.php")) {
 								$sql = "update v_conference_centers set ";
 								$sql .= "conference_center_greeting = replace(conference_center_greeting, :domain_name_old, :domain_name_new) ";
@@ -349,7 +356,7 @@
 								unset($sql, $parameters);
 							}
 
-						// update call center queue record templates
+						//update call center queue record templates
 							if (file_exists($_SERVER["PROJECT_ROOT"]."/app/call_center/app_config.php")) {
 								$sql = "update v_call_center_queues set ";
 								$sql .= "queue_record_template = replace(queue_record_template, :domain_name_old, :domain_name_new) ";
@@ -362,7 +369,7 @@
 								unset($sql, $parameters);
 							}
 
-						// update call center agent contacts
+						//update call center agent contacts
 							if (file_exists($_SERVER["PROJECT_ROOT"]."/app/call_center/app_config.php")) {
 								$sql = "update v_call_center_agents set ";
 								$sql .= "agent_contact = replace(agent_contact, :domain_name_old, :domain_name_new) ";
@@ -375,7 +382,7 @@
 								unset($sql, $parameters);
 							}
 
-						// update call flows data, alternate-data and contexts
+						//update call flows data, alternate-data and contexts
 							if (file_exists($_SERVER["PROJECT_ROOT"]."/app/call_flows/app_config.php")) {
 								$sql = "update v_call_flows set ";
 								$sql .= "call_flow_data = replace(call_flow_data, :domain_name_old, :domain_name_new), ";
@@ -390,7 +397,7 @@
 								unset($sql, $parameters);
 							}
 
-						// update device lines server_address, server_address_primary, server_address_secondary, outbound_proxy_primary, outbound_proxy_secondary
+						//update device lines server_address, server_address_primary, server_address_secondary, outbound_proxy_primary, outbound_proxy_secondary
 							if (file_exists($_SERVER["PROJECT_ROOT"]."/app/devices/app_config.php")) {
 								$sql = "update v_device_lines set ";
 								$sql .= "server_address = replace(server_address, :domain_name_old, :domain_name_new), ";
@@ -407,17 +414,17 @@
 								unset($sql, $parameters);
 							}
 
-						// rename switch/storage/voicemail/default/[domain] (folder)
+						//rename switch/storage/voicemail/default/[domain] (folder)
 							if (isset($_SESSION['switch']['voicemail']['dir']) && file_exists($_SESSION['switch']['voicemail']['dir']."/default/".$original_domain_name)) {
 								@rename($_SESSION['switch']['voicemail']['dir']."/default/".$original_domain_name, $_SESSION['switch']['voicemail']['dir']."/default/".$domain_name); // folder
 							}
 
-						// rename switch/storage/fax/[domain] (folder)
+						//rename switch/storage/fax/[domain] (folder)
 							if (isset($_SESSION['switch']['storage']['dir']) && file_exists($_SESSION['switch']['storage']['dir']."/fax/".$original_domain_name)) {
 								@rename($_SESSION['switch']['storage']['dir']."/fax/".$original_domain_name, $_SESSION['switch']['storage']['dir']."/fax/".$domain_name); // folder
 							}
 
-						// rename switch/conf/dialplan/[domain] (folder/file)
+						//rename switch/conf/dialplan/[domain] (folder/file)
 							if (isset($_SESSION['switch']['dialplan']['dir'])) {
 								if (file_exists($_SESSION['switch']['dialplan']['dir']."/".$original_domain_name)) {
 									@rename($_SESSION['switch']['dialplan']['dir']."/".$original_domain_name, $_SESSION['switch']['dialplan']['dir']."/".$domain_name); // folder
@@ -427,7 +434,7 @@
 								}
 							}
 
-						// rename switch/conf/dialplan/public/[domain] (folder/file)
+						//rename switch/conf/dialplan/public/[domain] (folder/file)
 							if (isset($_SESSION['switch']['dialplan']['dir'])) {
 								if (file_exists($_SESSION['switch']['dialplan']['dir']."/public/".$original_domain_name)) {
 									@rename($_SESSION['switch']['dialplan']['dir']."/public/".$original_domain_name, $_SESSION['switch']['dialplan']['dir']."/public/".$domain_name); // folder
@@ -437,7 +444,7 @@
 								}
 							}
 
-						// rename switch/conf/directory/[domain] (folder/file)
+						//rename switch/conf/directory/[domain] (folder/file)
 							if (isset($_SESSION['switch']['extensions']['dir'])) {
 								if (file_exists($_SESSION['switch']['extensions']['dir']."/".$original_domain_name)) {
 									@rename($_SESSION['switch']['extensions']['dir']."/".$original_domain_name, $_SESSION['switch']['extensions']['dir']."/".$domain_name); // folder
@@ -447,7 +454,7 @@
 								}
 							}
 
-						// rename switch/recordings/[domain] (folder)
+						//rename switch/recordings/[domain] (folder)
 							if (file_exists($_SESSION['switch']['recordings']['dir']."/".$_SESSION['domain_name'])) {
 								$switch_recordings_dir = str_replace("/".$_SESSION["domain_name"], "", $_SESSION['switch']['recordings']['dir']."/".$_SESSION['domain_name']);
 								if (file_exists($switch_recordings_dir."/".$original_domain_name)) {
@@ -455,7 +462,7 @@
 								}
 							}
 
-						// update dialplan, dialplan/public xml files
+						//update dialplan, dialplan/public xml files
 							$dialplan_xml = file_get_contents($_SESSION['switch']['dialplan']['dir']."/".$domain_name.".xml");
 							$dialplan_xml = str_replace($original_domain_name, $domain_name, $dialplan_xml);
 							file_put_contents($_SESSION['switch']['dialplan']['dir']."/".$domain_name.".xml", $dialplan_xml);
@@ -466,20 +473,17 @@
 							file_put_contents($_SESSION['switch']['dialplan']['dir']."/public/".$domain_name.".xml", $dialplan_public_xml);
 							unset($dialplan_public_xml);
 
-						// update session domain name
+						//update session domain name
 							$_SESSION['domains'][$domain_uuid]['domain_name'] = $domain_name;
 
-						// recreate dialplan and extension xml files
-							if (is_readable($_SESSION['switch']['dialplan']['dir'])) {
-								save_dialplan_xml();
-							}
+						//recreate dialplan and extension xml files
 							if (is_readable($_SESSION['switch']['extensions']['dir'])) {
 								require_once $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH."/app/extensions/resources/classes/extension.php";
 								$extension = new extension;
 								$extension->xml();
 							}
 
-						// if single-tenant and variables exist, update variables > domain value to match new domain
+						//if single-tenant and variables exist, update variables > domain value to match new domain
 							if (count($_SESSION['domains']) == 1 && file_exists($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH."/app/vars/")) {
 								$sql = "update v_vars set ";
 								$sql .= "var_value = :var_value ";
@@ -515,13 +519,18 @@
 					message::add($text['message-add']);
 					header("Location: domains.php");
 				}
-				return;
-			} //if ($_POST["persistformvar"] != "true")
-	} //(count($_POST)>0 && strlen($_POST["persistformvar"]) == 0)
+				exit;
+			}
+	}
 
 //pre-populate the form (admin won't have domain_add permissions, but domain_uuid will already be set above)
 	if ((count($_GET) > 0 || (!permission_exists('domain_add') && $domain_uuid != '')) && $_POST["persistformvar"] != "true") {
-		$sql = "select * from v_domains ";
+		$sql = "select ";
+		$sql .= "domain_uuid, ";
+		$sql .= "domain_name, ";
+		$sql .= "cast(domain_enabled as text), ";
+		$sql .= "domain_description ";
+		$sql .= "from v_domains ";
 		$sql .= "where domain_uuid = :domain_uuid ";
 		$parameters['domain_uuid'] = $domain_uuid;
 		$database = new database;
@@ -601,9 +610,13 @@
 	}
 	echo "	</div>\n";
 	echo "	<div class='actions'>\n";
+
 	if (permission_exists('domain_add')) {
 		echo button::create(['type'=>'button','label'=>$text['button-back'],'icon'=>$_SESSION['theme']['button_icon_back'],'id'=>'btn_back','style'=>'margin-right: 15px;','link'=>'domains.php']);
 	}
+	if ($action == "update" && permission_exists('domain_setting_view')) {
+		echo button::create(['type'=>'button','label'=>$text['button-settings'],'icon'=>$_SESSION['theme']['button_icon_settings'],'id'=>'btn_back','style'=>'margin-right: 2px;','link'=>PROJECT_PATH.'/core/domain_settings/domain_settings.php?id='.urlencode($domain_uuid)]);
+	}
 	if (permission_exists('domain_delete') && is_array($_SESSION['domains']) && @sizeof($_SESSION['domains']) > 1 && $domain_uuid != $_SESSION['domain_uuid']) {
 		echo button::create(['type'=>'button','label'=>$text['button-delete'],'icon'=>$_SESSION['theme']['button_icon_delete'],'onclick'=>"modal_open('modal-delete-domain','btn_delete_domain');"]);
 	}
@@ -616,9 +629,9 @@
 		echo "</select>";
 	}
 	if (permission_exists('domain_export')) {
-		echo button::create(['type'=>'button','label'=>$text['button-export'],'icon'=>$_SESSION['theme']['button_icon_export'],'link'=>PROJECT_PATH."/app/domain_export/index.php?id=".escape($domain_uuid)]);
+		echo button::create(['type'=>'button','label'=>$text['button-export'],'icon'=>$_SESSION['theme']['button_icon_export'],'link'=>PROJECT_PATH."/app/domain_export/index.php?id=".urlencode($domain_uuid)]);
 	}
-	echo button::create(['type'=>'submit','label'=>$text['button-save'],'icon'=>$_SESSION['theme']['button_icon_save'],'id'=>'btn_save','style'=>'margin-left: 15px;']);
+	echo button::create(['type'=>'submit','label'=>$text['button-save'],'icon'=>$_SESSION['theme']['button_icon_save'],'id'=>'btn_save','style'=>'margin-left: 3px;']);
 	echo "	</div>\n";
 	echo "	<div style='clear: both;'></div>\n";
 	echo "</div>\n";
@@ -683,12 +696,7 @@
 
 	echo "</form>";
 
-	if ($action == "update" && permission_exists('domain_setting_view')) {
-		require $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH."/core/domain_settings/domain_settings.php";
-		echo "<br /><br />\n";
-	}
-
 //include the footer
 	require_once "resources/footer.php";
 
-?>
+?>

+ 7 - 3
core/domains/domains.php

@@ -17,7 +17,7 @@
 
 	The Initial Developer of the Original Code is
 	Mark J Crane <[email protected]>
-	Portions created by the Initial Developer are Copyright (C) 2018 - 2019
+	Portions created by the Initial Developer are Copyright (C) 2018 - 2020
 	the Initial Developer. All Rights Reserved.
 
 	Contributor(s):
@@ -61,7 +61,7 @@
 
 			//update the domain session variables
 				$domain_uuid = $_GET["domain_uuid"];
-			        $_SESSION["previous_domain_uuid"] = $_SESSION['domain_uuid'];
+				$_SESSION["previous_domain_uuid"] = $_SESSION['domain_uuid'];
 				$_SESSION['domain_uuid'] = $domain_uuid;
 				$_SESSION["domain_name"] = $_SESSION['domains'][$domain_uuid]['domain_name'];
 				$_SESSION['domain']['template']['name'] = $_SESSION['domains'][$domain_uuid]['template_name'];
@@ -164,7 +164,11 @@
 	$offset = $rows_per_page * $page;
 
 //get the list
-	$sql = str_replace('count(domain_uuid)', '*', $sql);
+	$sql = "select domain_uuid, domain_name, cast(domain_enabled as text), domain_description ";
+	$sql .= "from v_domains ";
+	if (isset($sql_search)) {
+		$sql .= "where ".$sql_search;
+	}
 	$sql .= order_by($order_by, $order, 'domain_name', 'asc');
 	$sql .= limit_offset($rows_per_page, $offset);
 	$database = new database;

+ 8 - 0
core/groups/app_config.php

@@ -173,6 +173,14 @@
 		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
 		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
 		$z++;
+		$apps[$x]['db'][$y]['fields'][$z]['name']['text'] = "permission_protected";
+		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
+		$z++;
+		$apps[$x]['db'][$y]['fields'][$z]['name']['text'] = "permission_assigned";
+		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
+		$z++;
 		$apps[$x]['db'][$y]['fields'][$z]['name'] = "group_name";
 		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
 		$apps[$x]['db'][$y]['fields'][$z]['search'] = "true";

+ 5 - 0
core/groups/app_defaults.php

@@ -124,6 +124,11 @@ if ($domains_processed == 1) {
 		$database->execute($sql, null);
 		unset($sql);
 
+	//group permissions 
+		$database = new database;
+		$database->execute("update v_group_permissions set permission_protected = 'false' where permission_protected is null;", null);
+		$database->execute("update v_group_permissions set permission_assigned = 'true' where permission_assigned is null;", null);
+
 }
 
 ?>

+ 21 - 3
core/groups/group_edit.php

@@ -56,6 +56,7 @@
 	if (is_array($_POST)) {
 		$group_uuid = $_POST["group_uuid"];
 		$group_name = $_POST["group_name"];
+		$group_name_previous = $_POST["group_name_previous"];
 		$domain_uuid = $_POST["domain_uuid"];
 		$group_level = $_POST["group_level"];
 		$group_protected = $_POST["group_protected"];
@@ -136,6 +137,22 @@
 			$database->app_uuid = '2caf27b0-540a-43d5-bb9b-c9871a1e4f84';
 			$database->save($array);
 
+		//update group name in group permissions if group name changed
+			if ($group_name != $group_name_previous) {
+				$sql = "update v_group_permissions ";
+				$sql .= "set group_name = :group_name ";
+				$sql .= "where group_name = :group_name_previous ";
+				$sql .= "and group_uuid = :group_uuid ";
+				$parameters['group_name'] = $group_name;
+				$parameters['group_name_previous'] = $group_name_previous;
+				$parameters['group_uuid'] = $group_uuid;
+				$database = new database;
+				$database->app_name = 'Group Manager';
+				$database->app_uuid = '2caf27b0-540a-43d5-bb9b-c9871a1e4f84';
+				$database->execute($sql, $parameters);
+				unset($sql, $parameters, $database);
+			}
+
 		//redirect the user
 			if (isset($action)) {
 				if ($action == "add") {
@@ -147,7 +164,7 @@
 				header('Location: group_edit.php?id='.urlencode($group_uuid));
 				return;
 			}
-	} //(is_array($_POST) && strlen($_POST["persistformvar"]) == 0)
+	}
 
 //pre-populate the form
 	if (is_array($_GET) && $_POST["persistformvar"] != "true") {
@@ -192,7 +209,7 @@
 		unset($button_margin);
 	}
 	if (permission_exists('group_member_view')) {
-		echo button::create(['type'=>'button','label'=>$text['button-members'],'icon'=>'users','style'=>$button_margin,'link'=>'groupmembers.php?group_uuid='.urlencode($group_uuid)]);
+		echo button::create(['type'=>'button','label'=>$text['button-members'],'icon'=>'users','style'=>$button_margin,'link'=>'group_members.php?group_uuid='.urlencode($group_uuid)]);
 		unset($button_margin);
 	}
 	$button_margin = 'margin-left: 15px;';
@@ -227,6 +244,7 @@
 	echo "</td>\n";
 	echo "<td width='70%' class='vtable' style='position: relative;' align='left'>\n";
 	echo "	<input class='formfld' type='text' name='group_name' maxlength='255' value='".escape($group_name)."'>\n";
+	echo "	<input type='hidden' name='group_name_previous' value='".escape($group_name)."'>\n";
 	echo "<br />\n";
 	echo $text['description-group_name']."\n";
 	echo "</td>\n";
@@ -311,4 +329,4 @@
 //include the footer
 	require_once "resources/footer.php";
 
-?>
+?>

+ 30 - 38
core/groups/groupmembers.php → core/groups/group_members.php

@@ -67,7 +67,7 @@
 				break;
 		}
 
-		header('Location: groupmembers.php?group_uuid='.urlencode($group_uuid));
+		header('Location: group_members.php?group_uuid='.urlencode($group_uuid));
 		exit;
 	}
 
@@ -84,23 +84,6 @@
 	}
 	unset($sql, $parameters, $row);
 
-//define the if group members function
-	function is_group_member($group_uuid, $user_uuid) {
-		global $domain_uuid;
-		$sql = "select count(*) from v_user_groups ";
-		$sql .= "where user_uuid = :user_uuid ";
-		$sql .= "and group_uuid = :group_uuid ";
-		$sql .= "and domain_uuid = :domain_uuid ";
-		$parameters['user_uuid'] = $user_uuid;
-		$parameters['group_uuid'] = $group_uuid;
-		$parameters['domain_uuid'] = is_uuid($domain_uuid) ? $domain_uuid : $_SESSION['domain_uuid'];
-		$database = new database;
-		$num_rows = $database->select($sql, $parameters, 'column');
-		return $num_rows == 0 ? true : false;
-		unset($sql, $parameters, $num_rows);
-	}
-	//$exampledatareturned = example("apples", 1);
-
 //get the the users array
 	if (permission_exists('group_member_add')) {
 		$sql = "select * from v_users where ";
@@ -129,10 +112,21 @@
 	$sql .= "order by d.domain_name asc, u.username asc ";
 	$parameters['group_uuid'] = $group_uuid;
 	$database = new database;
-	$result = $database->select($sql, $parameters, 'all');
-	$num_rows = is_array($result) && @sizeof($result) != 0 ? sizeof($result) : 0;
+	$user_groups = $database->select($sql, $parameters, 'all');
+	$num_rows = is_array($user_groups) && @sizeof($user_groups) != 0 ? sizeof($user_groups) : 0;
 	unset($sql, $parameters);
 
+//add group_member to the users array
+	foreach ($users as &$field) {
+		$field['group_member'] = 'false';
+		foreach($user_groups as $row) {
+			if ($row['user_uuid'] == $field['user_uuid']) {
+				$field['group_member'] = 'true';
+				break;
+			}
+		}
+	}
+
 //create token
 	$object = new token;
 	$token = $object->create($_SERVER['PHP_SELF']);
@@ -149,32 +143,32 @@
 	if (permission_exists('group_permission_view')) {
 		echo button::create(['type'=>'button','label'=>$text['button-permissions'],'icon'=>'key','style'=>'margin-right: 15px;','link'=>'group_permissions.php?group_uuid='.urlencode($group_uuid)]);
 	}
+
 	if (permission_exists('group_member_add')) {
 		echo 	"<form class='inline' method='post' action='groupmemberadd.php'>\n";
 		echo "	<select name='user_uuid' class='formfld'>\n";
 		echo "		<option value=''>".$text['label-select']."...</option>\n";
-		foreach ($users as $field) {
-			if (is_group_member($group_uuid, $field['user_uuid'])) {
-				echo "<option value='".escape($field['user_uuid'])."'>".escape($field['username'])."</option>\n";
+		foreach ($users as $row) {
+			if ($row['group_member'] === 'false') {
+				echo "<option value='".escape($row['user_uuid'])."'>".escape($row['username'])."</option>\n";
 			}
 		}
-		unset($sql, $users);
-		echo "	</select>";
-		echo 	"<input type='hidden' name='domain_uuid' value='".(is_uuid($domain_uuid) ? escape($domain_uuid) : $_SESSION['domain_uuid'])."'>";
-		echo 	"<input type='hidden' name='group_uuid' value='".escape($group_uuid)."'>";
-		echo 	"<input type='hidden' name='group_name' value='".escape($group_name)."'>";
-		echo 	"<input type='hidden' name='".$token['name']."' value='".$token['hash']."'>";
+		echo "	</select>\n";
+		echo 	"<input type='hidden' name='domain_uuid' value='".(is_uuid($domain_uuid) ? escape($domain_uuid) : $_SESSION['domain_uuid'])."'>\n";
+		echo 	"<input type='hidden' name='group_uuid' value='".escape($group_uuid)."'>\n";
+		echo 	"<input type='hidden' name='group_name' value='".escape($group_name)."'>\n";
+		echo 	"<input type='hidden' name='".$token['name']."' value='".$token['hash']."'>\n";
 		echo button::create(['type'=>'submit','label'=>$text['button-add_member'],'icon'=>$_SESSION['theme']['button_icon_add'],'collapse'=>'hide-xs']);
-		echo "	</form>";
+		echo "	</form>\n";
 	}
-	if (permission_exists('group_member_delete') && $result) {
+	if (permission_exists('group_member_delete') && $user_groups) {
 		echo button::create(['type'=>'button','label'=>$text['button-delete'],'icon'=>$_SESSION['theme']['button_icon_delete'],'name'=>'btn_delete','collapse'=>'hide-xs','onclick'=>"modal_open('modal-delete','btn_delete');"]);
 	}
 	echo "	</div>\n";
 	echo "	<div style='clear: both;'></div>\n";
 	echo "</div>\n";
 
-	if (permission_exists('group_member_delete') && $result) {
+	if (permission_exists('group_member_delete') && $user_groups) {
 		echo modal::create(['id'=>'modal-delete','type'=>'delete','actions'=>button::create(['type'=>'button','label'=>$text['button-continue'],'icon'=>'check','id'=>'btn_delete','style'=>'float: right; margin-left: 15px;','collapse'=>'never','onclick'=>"modal_close(); list_action_set('delete'); list_form_submit('form_list');"])]);
 	}
 
@@ -186,7 +180,7 @@
 	echo "<tr class='list-header'>\n";
 	if (permission_exists('group_member_delete')) {
 		echo "	<th class='checkbox'>\n";
-		echo "		<input type='checkbox' id='checkbox_all' name='checkbox_all' onclick='list_all_toggle();' ".($result ?: "style='visibility: hidden;'").">\n";
+		echo "		<input type='checkbox' id='checkbox_all' name='checkbox_all' onclick='list_all_toggle();' ".($user_groups ?: "style='visibility: hidden;'").">\n";
 		echo "	</th>\n";
 	}
 	if (permission_exists('user_all')) {
@@ -195,9 +189,9 @@
 	echo "	<th>".$text['label-username']."</th>\n";
 	echo "</tr>\n";
 
-	if (is_array($result) && @sizeof($result) != 0) {
+	if (is_array($user_groups) && @sizeof($user_groups) != 0) {
 		$x = 0;
-		foreach ($result as &$row) {
+		foreach ($user_groups as &$row) {
 			echo "<tr class='list-row' href='".$list_row_url."'>";
 			if (permission_exists('group_member_delete')) {
 				echo "	<td class='checkbox'>\n";
@@ -211,8 +205,6 @@
 			echo "<td class='no-wrap' onclick=\"if (document.getElementById('checkbox_".$x."').checked) { document.getElementById('checkbox_".$x."').checked = false; document.getElementById('checkbox_all').checked = false; } else { document.getElementById('checkbox_".$x."').checked = true; }\">".$row["username"]."</td>\n";
 			echo "</tr>\n";
 			$x++;
-
-			$user_groups[] = $row["user_uuid"];
 		}
 	}
 
@@ -224,4 +216,4 @@
 //include the footer
 	require_once "resources/footer.php";
 
-?>
+?>

+ 374 - 323
core/groups/group_permissions.php

@@ -1,323 +1,374 @@
-<?php
-/*
-	FusionPBX
-	Version: MPL 1.1
-
-	The contents of this file are subject to the Mozilla Public License Version
-	1.1 (the "License"); you may not use this file except in compliance with
-	the License. You may obtain a copy of the License at
-	http://www.mozilla.org/MPL/
-
-	Software distributed under the License is distributed on an "AS IS" basis,
-	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-	for the specific language governing rights and limitations under the
-	License.
-
-	The Original Code is FusionPBX
-
-	The Initial Developer of the Original Code is
-	Mark J Crane <[email protected]>
-	Portions created by the Initial Developer are Copyright (C) 2018-2020
-	the Initial Developer. All Rights Reserved.
-
-	Contributor(s):
-	Mark J Crane <[email protected]>
-*/
-
-//includes
-	require_once "root.php";
-	require_once "resources/require.php";
-	require_once "resources/check_auth.php";
-
-//check permissions
-	if (permission_exists('group_permission_view')) {
-		//access granted
-	}
-	else {
-		echo "access denied";
-		exit;
-	}
-
-//action add or update
-	if (is_uuid($_REQUEST["group_uuid"])) {
-		$group_uuid = $_REQUEST["group_uuid"];
-	}
-
-//get the group_name
-	if (is_uuid($group_uuid)) {
-		$sql = "select group_name from v_groups ";
-		$sql .= "where group_uuid = :group_uuid ";
-		$parameters['group_uuid'] = $group_uuid;
-		$database = new database;
-		$group_name = $database->select($sql, $parameters, 'column');
-		unset($sql, $parameters);
-	}
-
-//add multi-lingual support
-	$language = new text;
-	$text = $language->get();
-
-//process permission reload
-	if ($_GET['action'] == 'reload' && is_uuid($_GET['group_uuid'])) {
-		if (is_array($_SESSION["groups"]) && @sizeof($_SESSION["groups"]) != 0) {
-			//clear current permissions
-				unset($_SESSION['permissions'], $_SESSION['user']['permissions']);
-			//get the permissions assigned to the groups that the current user is a member of, set the permissions in session variables
-				$x = 0;
-				$sql = "select distinct(permission_name) from v_group_permissions ";
-				$sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) ";
-				foreach ($_SESSION["groups"] as $field) {
-					if (strlen($field['group_name']) > 0) {
-						$sql_where_or[] = "group_name = :group_name_".$x;
-						$parameters['group_name_'.$x] = $field['group_name'];
-						$x++;
-					}
-				}
-				if (is_array($sql_where_or) && @sizeof($sql_where_or) != 0) {
-					$sql .= "and (".implode(' or ', $sql_where_or).") ";
-				}
-				$parameters['domain_uuid'] = $_SESSION["domain_uuid"];
-				$database = new database;
-				$result = $database->select($sql, $parameters, 'all');
-				if (is_array($result) && @sizeof($result) != 0) {
-					foreach ($result as $row) {
-						$_SESSION['permissions'][$row["permission_name"]] = true;
-						$_SESSION["user"]["permissions"][$row["permission_name"]] = true;
-					}
-				}
-				unset($sql, $parameters, $result, $row);
-			//set message and redirect
-				message::add($text['message-permissions_reloaded'],'positive');
-				header('Location: group_permissions.php?group_uuid='.urlencode($_GET['group_uuid']));
-				exit;
-		}
-	}
-
-//get the http post data
-	if (is_array($_POST['group_permissions'])) {
-		$action = $_POST['action'];
-		$search = $_POST['search'];
-		$group_permissions = $_POST['group_permissions'];
-	}
-
-//process the user data and save it to the database
-	if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
-		//get the list
-			$sql = "select p.*, ";
-			$sql .= "exists(select from v_group_permissions where permission_name = p.permission_name and group_name = :group_name) as permission_assigned ";
-			$sql .= "from v_permissions as p ";
-			$parameters['group_name'] = $group_name;
-			//$sql = "select * from v_group_permissions ";
-			//$sql .= "where group_uuid = :group_uuid ";
-			//$parameters['group_uuid'] = $group_uuid;
-			$database = new database;
-			$group_permissions = $database->select($sql, $parameters, 'all');
-
-		//add or remove permissions from the group
-			$x = 0;
-			if (is_array($_POST['group_permissions'])) {
-				foreach($_POST['group_permissions'] as $row) {
-					//check to see if the group has been assigned the permission
-					$in_database = false;
-					foreach($group_permissions as $field) {
-						if ($field['permission_name'] === $row['permission_name'] && $field['permission_assigned'] === true) {
-							$in_database = true;
-							break;
-						}
-					}
-
-					//add - checked on html form and not in the database
-					if ($row['checked'] === 'true') {
-						if (!$in_database) {
-							if (isset($row['permission_name']) && strlen($row['permission_name']) > 0) {
-								$array['add']['group_permissions'][$x]['group_permission_uuid'] = uuid();
-								$array['add']['group_permissions'][$x]['permission_name'] = $row['permission_name'];
-								$array['add']['group_permissions'][$x]['group_uuid'] = $group_uuid;
-								$array['add']['group_permissions'][$x]['group_name'] = $group_name;
-								//$array['add']['group_permissions'][$x]['permission_uuid'] = $row['uuid'];
-								$x++;
-							}
-						}
-					}
-
-					//delete - unchecked on the form and in the database
-					if ($row['checked'] !== 'true') {
-						if ($in_database) {
-							if (isset($row['permission_name']) && strlen($row['permission_name']) > 0) {
-								$array['delete']['group_permissions'][$x]['permission_name'] = $row['permission_name'];
-								$array['delete']['group_permissions'][$x]['group_uuid'] = $group_uuid;
-								$array['delete']['group_permissions'][$x]['group_name'] = $group_name;
-								//$array['delete'][$x]['permission_uuid'] = $row['uuid'];
-							}
-							$x++;
-						}
-					}
-				}
-			}
-
-		//validate the token
-			$token = new token;
-			if (!$token->validate($_SERVER['PHP_SELF'])) {
-				message::add($text['message-invalid_token'],'negative');
-				header('Location: group_permissions.php?group_uuid='.urlencode($group_uuid).'&search='.urlencode($search));
-				exit;
-			}
-
-		//save to the data
-			if (is_array($array['add']) && @sizeof($array['add']) != 0) {
-				$database = new database;
-				$database->app_name = 'groups';
-				$database->app_uuid = '2caf27b0-540a-43d5-bb9b-c9871a1e4f84';
-				$database->save($array['add']);
-				$message = $database->message;
-			}
-
-		//delete the permissions
-			if (is_array($array['delete']) && @sizeof($array['delete']) != 0) {
-				if (permission_exists('group_permission_delete')) {
-					$database = new database;
-					$database->app_name = 'groups';
-					$database->app_uuid = '2caf27b0-540a-43d5-bb9b-c9871a1e4f84';
-					$database->delete($array['delete']);
-				}
-			}
-
-		//set the message
-			message::add($text['message-update']);
-
-		//redirect
-			header('Location: group_permissions.php?group_uuid='.urlencode($group_uuid));
-			exit;
-	}
-
-//get order and order by
-	//$order_by = $_GET["order_by"];
-	//$order = $_GET["order"];
-
-//add the search string
-	if (isset($_REQUEST["search"])) {
-		$search =  strtolower($_REQUEST["search"]);
-		$sql_search = " (";
-		$sql_search .= "	lower(p.permission_name) like :search ";
-		//$sql_search .= "	or lower(p.group_name) like :search ";
-		$sql_search .= ") ";
-		$parameters['search'] = '%'.$search.'%';
-	}
-
-//get the count
-	/*
-	$sql = "select count(group_permission_uuid) from v_group_permissions ";
-	$sql .= "where group_uuid = :group_uuid ";
-	$parameters['group_uuid'] = $group_uuid;
-	if (isset($sql_search)) {
-		$sql .= "where ".$sql_search;
-	}
-	$database = new database;
-	$num_rows = $database->select($sql, $parameters, 'column');
-	*/
-
-//get the list
-	$sql = "select p.*, ";
-	$sql .= "exists(select from v_group_permissions where permission_name = p.permission_name and group_name = :group_name) as permission_assigned ";
-	$sql .= "from v_permissions as p ";
-	$parameters['group_name'] = $group_name;
-	if (isset($sql_search)) {
-		$sql .= "where ".$sql_search;
-	}
-	$sql .= "order by application_name asc, permission_name asc ";
-	$database = new database;
-	$group_permissions = $database->select($sql, $parameters, 'all');
-	unset($sql, $parameters);
-
-//create token
-	$object = new token;
-	$token = $object->create($_SERVER['PHP_SELF']);
-
-//include the header
-	$document['title'] = $text['title-group_permissions'];
-	require_once "resources/header.php";
-
-//show the content
-	echo "<div class='action_bar' id='action_bar'>\n";
-	echo "	<div class='heading'><b>".$text['title-group_permissions']." (".escape($group_name).")</b></div>\n";
-	echo "	<div class='actions'>\n";
-	echo button::create(['type'=>'button','label'=>$text['button-back'],'icon'=>$_SESSION['theme']['button_icon_back'],'id'=>'btn_back','style'=>'margin-right: 15px;','collapse'=>'hide-sm-dn','link'=>'groups.php']);
-	echo button::create(['type'=>'button','label'=>$text['button-reload'],'icon'=>'key','link'=>'?group_uuid='.urlencode($group_uuid).'&action=reload']);
-	if (permission_exists('group_member_view')) {
-		echo button::create(['type'=>'button','label'=>$text['button-members'],'icon'=>'users','link'=>'groupmembers.php?group_uuid='.urlencode($group_uuid)]);
-	}
-	echo 		"<form id='form_search' class='inline' method='get'>\n";
-	echo 		"<input type='hidden' name='group_uuid' value='".escape($group_uuid)."'>\n";
-	echo 		"<input type='text' class='txt list-search' name='search' id='search' value=\"".escape($search)."\" placeholder=\"".$text['label-search']."\" onkeydown='list_search_reset();'>";
-	echo button::create(['label'=>$text['button-search'],'icon'=>$_SESSION['theme']['button_icon_search'],'type'=>'submit','id'=>'btn_search','collapse'=>'hide-sm-dn','style'=>($search != '' ? 'display: none;' : null)]);
-	echo button::create(['label'=>$text['button-reset'],'icon'=>$_SESSION['theme']['button_icon_reset'],'type'=>'button','id'=>'btn_reset','collapse'=>'hide-sm-dn','link'=>'group_permissions.php?group_uuid='.urlencode($group_uuid),'style'=>($search == '' ? 'display: none;' : null)]);
-	if (permission_exists('group_permission_edit')) {
-		echo button::create(['type'=>'button','label'=>$text['button-save'],'icon'=>$_SESSION['theme']['button_icon_save'],'id'=>'btn_save','collapse'=>'hide-sm-dn','style'=>'margin-left: 15px;','onclick'=>"document.getElementById('form_list').submit();"]);
-	}
-	echo "		</form>\n";
-	echo "	</div>\n";
-	echo "	<div style='clear: both;'></div>\n";
-	echo "</div>\n";
-
-	echo $text['description-group_permissions']."\n";
-	echo "<br /><br />\n";
-
-	echo "<form id='form_list' method='post'>\n";
-	echo "<input type='hidden' name='".$token['name']."' value='".$token['hash']."'>\n";
-	echo "<input type='hidden' name='group_uuid' value='".escape($group_uuid)."'>\n";
-	echo "<input type='hidden' name='search' value=\"".escape($search)."\">\n";
-	echo "<table class='list' style='margin-bottom: 25px;'>\n";
-	if (is_array($group_permissions) && @sizeof($group_permissions) != 0) {
-		$x = 0;
-		foreach ($group_permissions as $row) {
-			$checked = ($row['permission_assigned'] === true) ? " checked=\"checked\"" : $checked = '';
-			$application_name = strtolower($row['application_name']);
-			$label_application_name = ucwords(str_replace(['_','-'], " ", $row['application_name']));
-
-			$label_application_name = ucwords($label_application_name);
-
-			if ($previous_application_name !== $row['application_name']) {
-				echo "		<tr>";
-				echo "			<td align='left' colspan='999'>&nbsp;</td>\n";
-				echo "		</tr>";
-				echo "		<tr>";
-				echo "			<td align='left' colspan='999' nowrap='nowrap'><b>".escape($label_application_name)."</b></td>\n";
-				echo "		</tr>";
-				echo "<tr class='list-header'>\n";
-				if (permission_exists('group_permission_add') || permission_exists('group_permission_edit') || permission_exists('group_permission_delete')) {
-					echo "	<th class='checkbox'>\n";
-					echo "		<input type='checkbox' id='checkbox_all_".$application_name."' name='checkbox_all' onclick=\"list_all_toggle('".$application_name."');\">\n";
-					echo "	</th>\n";
-				}
-				echo th_order_by('group_name', $text['label-group_name'], $order_by, $order);
-				if (permission_exists('group_permission_edit') && $_SESSION['theme']['list_row_edit_button']['boolean'] == 'true') {
-					echo "	<td class='action-button'>&nbsp;</td>\n";
-				}
-				echo "</tr>\n";
-
-			}
-			echo "<tr class='list-row'>\n";
-			if (permission_exists('group_permission_add') || permission_exists('group_permission_edit') || permission_exists('group_permission_delete')) {
-				echo "	<td class='checkbox'>\n";
-				echo "		<input type='checkbox' name='group_permissions[$x][checked]' id='checkbox_".$x."' class='checkbox_".$application_name."' value='true' ".$checked." onclick=\"if (!this.checked) { document.getElementById('checkbox_all_".$application_name."').checked = false; }\">\n";
-				echo "		<input type='hidden' name='group_permissions[$x][permission_uuid]' value='".escape($row['permission_uuid'])."' />\n";
-				echo "		<input type='hidden' name='group_permissions[$x][permission_name]' value='".escape($row['permission_name'])."' />\n";
-				echo "	</td>\n";
-			}
-			echo "	<td  class='no-wrap' onclick=\"if (document.getElementById('checkbox_".$x."').checked) { document.getElementById('checkbox_".$x."').checked = false; document.getElementById('checkbox_all_".$application_name."').checked = false; } else { document.getElementById('checkbox_".$x."').checked = true; }\">".escape($row['permission_name'])."</td>\n";
-			echo "</tr>\n";
-
-			//set the previous category
-			$previous_application_name = $row['application_name'];
-			$x++;
-		}
-		unset($group_permissions);
-	}
-
-	echo "</table>\n";
-	echo "</form>\n";
-
-//include the footer
-	require_once "resources/footer.php";
-
-?>
+<?php
+/*
+	FusionPBX
+	Version: MPL 1.1
+
+	The contents of this file are subject to the Mozilla Public License Version
+	1.1 (the "License"); you may not use this file except in compliance with
+	the License. You may obtain a copy of the License at
+	http://www.mozilla.org/MPL/
+
+	Software distributed under the License is distributed on an "AS IS" basis,
+	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+	for the specific language governing rights and limitations under the
+	License.
+
+	The Original Code is FusionPBX
+
+	The Initial Developer of the Original Code is
+	Mark J Crane <[email protected]>
+	Portions created by the Initial Developer are Copyright (C) 2018-2020
+	the Initial Developer. All Rights Reserved.
+
+	Contributor(s):
+	Mark J Crane <[email protected]>
+*/
+
+//includes
+	require_once "root.php";
+	require_once "resources/require.php";
+	require_once "resources/check_auth.php";
+
+//check permissions
+	if (permission_exists('group_permission_view')) {
+		//access granted
+	}
+	else {
+		echo "access denied";
+		exit;
+	}
+
+//action add or update
+	if (is_uuid($_REQUEST["group_uuid"])) {
+		$group_uuid = $_REQUEST["group_uuid"];
+	}
+
+//get the group_name
+	if (is_uuid($group_uuid)) {
+		$sql = "select group_name from v_groups ";
+		$sql .= "where group_uuid = :group_uuid ";
+		$parameters['group_uuid'] = $group_uuid;
+		$database = new database;
+		$group_name = $database->select($sql, $parameters, 'column');
+		unset($sql, $parameters);
+	}
+
+//add multi-lingual support
+	$language = new text;
+	$text = $language->get();
+
+//process permission reload
+	if ($_GET['action'] == 'reload' && is_uuid($_GET['group_uuid'])) {
+		if (is_array($_SESSION["groups"]) && @sizeof($_SESSION["groups"]) != 0) {
+			//clear current permissions
+				unset($_SESSION['permissions'], $_SESSION['user']['permissions']);
+			//get the permissions assigned to the groups that the current user is a member of, set the permissions in session variables
+				$x = 0;
+				$sql = "select distinct(permission_name) from v_group_permissions ";
+				$sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) ";
+				$sql .= "and permission_assigned = 'true' ";
+				foreach ($_SESSION["groups"] as $field) {
+					if (strlen($field['group_name']) > 0) {
+						$sql_where_or[] = "group_name = :group_name_".$x;
+						$parameters['group_name_'.$x] = $field['group_name'];
+						$x++;
+					}
+				}
+				if (is_array($sql_where_or) && @sizeof($sql_where_or) != 0) {
+					$sql .= "and (".implode(' or ', $sql_where_or).") ";
+				}
+				$parameters['domain_uuid'] = $_SESSION["domain_uuid"];
+				$database = new database;
+				$result = $database->select($sql, $parameters, 'all');
+				if (is_array($result) && @sizeof($result) != 0) {
+					foreach ($result as $row) {
+						$_SESSION['permissions'][$row["permission_name"]] = true;
+						$_SESSION["user"]["permissions"][$row["permission_name"]] = true;
+					}
+				}
+				unset($sql, $parameters, $result, $row);
+			//set message and redirect
+				message::add($text['message-permissions_reloaded'],'positive');
+				header('Location: group_permissions.php?group_uuid='.urlencode($_GET['group_uuid']));
+				exit;
+		}
+	}
+
+//get the http post data
+	if (is_array($_POST['group_permissions'])) {
+		$action = $_POST['action'];
+		$search = $_POST['search'];
+		$group_permissions = $_POST['group_permissions'];
+	}
+
+//add the search string
+	if (isset($_REQUEST["search"])) {
+		$search =  strtolower($_REQUEST["search"]);
+		$sql_search = " (";
+		$sql_search .= "	lower(p.permission_name) like :search \n";
+		$sql_search .= ") ";
+		$parameters['search'] = '%'.$search.'%';
+	}
+
+//get the list
+	$sql = "select "; 
+	$sql .= "	distinct p.permission_name, \n";
+	$sql .= "	p.application_name, \n";
+	$sql .= "	g.permission_protected, \n"; 
+	$sql .= "	g.group_permission_uuid, \n"; 
+	$sql .= "	g.permission_assigned \n";
+	$sql .= "from v_permissions as p \n"; 
+	$sql .= "left join \n"; 
+	$sql .= "	v_group_permissions as g \n"; 
+	$sql .= "	on p.permission_name = g.permission_name \n"; 
+	$sql .= "	and group_name = :group_name \n"; 
+	$sql .= " 	and g.group_uuid = :group_uuid \n";
+	if (isset($sql_search)) {
+		$sql .= "where ".$sql_search;
+	}
+	$sql .= "	order by p.application_name, p.permission_name asc "; 
+	$parameters['group_name'] = $group_name;
+	$parameters['group_uuid'] = $group_uuid;
+	$database = new database;
+	$group_permissions = $database->select($sql, $parameters, 'all');
+
+//process the user data and save it to the database
+	if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
+			$x = 0;
+			if (is_array($_POST['group_permissions'])) {
+				foreach($_POST['group_permissions'] as $row) {
+					//reset values
+						$action = "";
+						$save_permission = false;
+						$delete_permission = false;
+						$save_protected = false;
+						$delete_protected = false;
+						$persist = false;
+
+					//get the action save or delete
+						foreach($group_permissions as $field) {
+							if ($field['permission_name'] === $row['permission_name']) {
+								if ($field['permission_assigned'] == 'true') {
+									if ($row['checked'] == "true") {
+										$persist = true;
+									}
+									else {
+										$delete_permission = true;
+									}
+								}
+								else {
+									
+									if ($row['checked'] == "true") {
+										$save_permission = true;
+									}
+									else {
+										//do nothing
+									}
+								}
+
+								if ($field['permission_protected'] == 'true') {
+									if ($row['permission_protected'] == "true") {
+										$persist = true;
+									}
+									else {
+										$delete_protected = true;
+									}
+								}
+								else {
+									if ($row['permission_protected'] == "true") {
+										$save_protected = true;
+									}
+									else {
+										//do nothing
+									}
+								}
+
+								if ($save_permission || $save_protected) {
+									$action = "save";
+								}
+								elseif ($delete_permission || $delete_protected){
+									if ($persist) {
+										$action = "save";
+									}
+									else {
+										$action = "delete";
+									}
+								}
+								else {
+									$action = "";
+								}
+								$group_permission_uuid = $field['group_permission_uuid'];
+								break;
+							}
+						}
+					
+					//build the array;
+						if ($action == "save") {
+							if (strlen($group_permission_uuid) == 0) {
+								$group_permission_uuid = uuid();
+							}
+							if (isset($row['permission_name']) && strlen($row['permission_name']) > 0) {
+								$array['save']['group_permissions'][$x]['group_permission_uuid'] = $group_permission_uuid;
+								$array['save']['group_permissions'][$x]['permission_name'] = $row['permission_name'];
+								$array['save']['group_permissions'][$x]['permission_protected'] = $row['permission_protected'] == 'true' ? "true" : 'false';
+								$array['save']['group_permissions'][$x]['permission_assigned'] = $row['checked'] != "true" ? "false" : "true";
+								$array['save']['group_permissions'][$x]['group_uuid'] = $group_uuid;
+								$array['save']['group_permissions'][$x]['group_name'] = $group_name;
+								$x++;
+							}
+						}
+
+						if ($action == "delete") {
+							if (isset($row['permission_name']) && strlen($row['permission_name']) > 0) {
+								$array['delete']['group_permissions'][$x]['permission_name'] = $row['permission_name'];
+								$array['delete']['group_permissions'][$x]['group_uuid'] = $group_uuid;
+								$array['delete']['group_permissions'][$x]['group_name'] = $group_name;
+							}
+							$x++;
+						}
+				}
+			}
+			
+		//validate the token
+			$token = new token;
+			if (!$token->validate($_SERVER['PHP_SELF'])) {
+				message::add($text['message-invalid_token'],'negative');
+				header('Location: group_permissions.php?group_uuid='.urlencode($group_uuid).'&search='.urlencode($search));
+				exit;
+			}
+
+		//save the save array
+			if (is_array($array['save']) && @sizeof($array['save']) != 0) {
+				$database = new database;
+				$database->app_name = 'groups';
+				$database->app_uuid = '2caf27b0-540a-43d5-bb9b-c9871a1e4f84';
+				$database->save($array['save']);
+				$message = $database->message;
+			}
+
+		//delete the delete array
+			if (is_array($array['delete']) && @sizeof($array['delete']) != 0) {
+				if (permission_exists('group_permission_delete')) {
+					$database = new database;
+					$database->app_name = 'groups';
+					$database->app_uuid = '2caf27b0-540a-43d5-bb9b-c9871a1e4f84';
+					$database->delete($array['delete']);
+				}
+			}
+
+		//set the message
+			message::add($text['message-update']);
+
+		//redirect
+			header('Location: group_permissions.php?group_uuid='.urlencode($group_uuid));
+			exit;
+	}
+
+//get order and order by
+	//$order_by = $_GET["order_by"];
+	//$order = $_GET["order"];
+
+//create token
+	$object = new token;
+	$token = $object->create($_SERVER['PHP_SELF']);
+
+//include the header
+	$document['title'] = $text['title-group_permissions'];
+	require_once "resources/header.php";
+
+//show the content
+	echo "<div class='action_bar' id='action_bar'>\n";
+	echo "	<div class='heading'><b>".$text['title-group_permissions']." (".escape($group_name).")</b></div>\n";
+	echo "	<div class='actions'>\n";
+	echo button::create(['type'=>'button','label'=>$text['button-back'],'icon'=>$_SESSION['theme']['button_icon_back'],'id'=>'btn_back','style'=>'margin-right: 15px;','collapse'=>'hide-sm-dn','link'=>'groups.php']);
+	echo button::create(['type'=>'button','label'=>$text['button-reload'],'icon'=>$_SESSION['theme']['button_icon_reload'],'link'=>'?group_uuid='.urlencode($group_uuid).'&action=reload']);
+	if (permission_exists('group_member_view')) {
+		echo button::create(['type'=>'button','label'=>$text['button-members'],'icon'=>'users','link'=>'group_members.php?group_uuid='.urlencode($group_uuid)]);
+	}
+	echo 		"<form id='form_search' class='inline' method='get'>\n";
+	echo 		"<input type='hidden' name='group_uuid' value='".escape($group_uuid)."'>\n";
+	echo 		"<input type='text' class='txt list-search' name='search' id='search' value=\"".escape($search)."\" placeholder=\"".$text['label-search']."\" onkeydown='list_search_reset();'>";
+	echo button::create(['label'=>$text['button-search'],'icon'=>$_SESSION['theme']['button_icon_search'],'type'=>'submit','id'=>'btn_search','collapse'=>'hide-sm-dn','style'=>($search != '' ? 'display: none;' : null)]);
+	echo button::create(['label'=>$text['button-reset'],'icon'=>$_SESSION['theme']['button_icon_reset'],'type'=>'button','id'=>'btn_reset','collapse'=>'hide-sm-dn','link'=>'group_permissions.php?group_uuid='.urlencode($group_uuid),'style'=>($search == '' ? 'display: none;' : null)]);
+	if (permission_exists('group_permission_edit')) {
+		echo button::create(['type'=>'button','label'=>$text['button-save'],'icon'=>$_SESSION['theme']['button_icon_save'],'id'=>'btn_save','collapse'=>'hide-sm-dn','style'=>'margin-left: 15px;','onclick'=>"document.getElementById('form_list').submit();"]);
+	}
+	echo "		</form>\n";
+	echo "	</div>\n";
+	echo "	<div style='clear: both;'></div>\n";
+	echo "</div>\n";
+
+	echo $text['description-group_permissions']."\n";
+	echo "<br /><br />\n";
+
+	echo "<form id='form_list' method='post'>\n";
+	echo "<input type='hidden' name='".$token['name']."' value='".$token['hash']."'>\n";
+	echo "<input type='hidden' name='group_uuid' value='".escape($group_uuid)."'>\n";
+	echo "<input type='hidden' name='search' value=\"".escape($search)."\">\n";
+	echo "<table class='list' style='margin-bottom: 25px;'>\n";
+	if (is_array($group_permissions) && @sizeof($group_permissions) != 0) {
+		$x = 0;
+		foreach ($group_permissions as $row) {
+			$checked = ($row['permission_assigned'] === 'true') ? " checked=\"checked\"" : $checked = '';
+			$protected = ($row['permission_protected'] === 'true') ? " checked=\"checked\"" : '';
+			$application_name = strtolower($row['application_name']);
+			$label_application_name = ucwords(str_replace(['_','-'], " ", $row['application_name']));
+
+			$label_application_name = ucwords($label_application_name);
+
+			if ($previous_application_name !== $row['application_name']) {
+				echo "		<tr>";
+				echo "			<td align='left' colspan='999'>&nbsp;</td>\n";
+				echo "		</tr>";
+				echo "		<tr>";
+				echo "			<td align='left' colspan='999' nowrap='nowrap'><b>".escape($label_application_name)."</b></td>\n";
+				echo "		</tr>";
+				echo "		<tr class='list-header'>\n";
+				if (permission_exists('group_permission_add') || permission_exists('group_permission_edit') || permission_exists('group_permission_delete')) {
+					echo "		<th class='checkbox'>\n";
+					echo "			<input type='checkbox' id='checkbox_all_".$application_name."' name='checkbox_all' onclick=\"list_all_toggle('".$application_name."');\">\n";
+					echo "		</th>\n";
+				}
+				echo th_order_by('group_name', $text['label-group_name'], $order_by, $order);
+				if (permission_exists('group_permission_add') || permission_exists('group_permission_edit') || permission_exists('group_permission_delete')) {
+					echo th_order_by('group_permission_protected', $text['label-group_protected'], $order_by, $order, null, "style='text-align: right;'");
+					echo "		<th class='checkbox'>\n";
+					echo "			<input type='checkbox' id='checkbox_all_".$application_name."_protected' name='checkbox_protected_all' onclick=\"list_all_toggle('".$application_name."_protected');\">\n";
+					echo "		</th>\n";
+				}
+				echo "		</tr>\n";
+
+			}
+			echo "<tr class='list-row'>\n";
+			if (permission_exists('group_permission_add') || permission_exists('group_permission_edit') || permission_exists('group_permission_delete')) {
+				echo "	<td class='checkbox'>\n";
+				echo "		<input type='checkbox' name='group_permissions[$x][checked]' id='checkbox_".$x."' class='checkbox_".$application_name."' value='true' ".$checked." onclick=\"if (!this.checked) { document.getElementById('checkbox_all_".$application_name."').checked = false; }\">\n";
+				echo "		<input type='hidden' name='group_permissions[$x][permission_uuid]' value='".escape($row['permission_uuid'])."' />\n";
+				echo "		<input type='hidden' name='group_permissions[$x][permission_name]' value='".escape($row['permission_name'])."' />\n";
+				echo "	</td>\n";
+			}
+			echo "	<td class='no-wrap' onclick=\"if (document.getElementById('checkbox_".$x."').checked) { document.getElementById('checkbox_".$x."').checked = false; document.getElementById('checkbox_all_".$application_name."').checked = false; } else { document.getElementById('checkbox_".$x."').checked = true; }\">";
+			echo "		".escape($row['permission_name']);
+			echo "	</td>\n";
+			if (permission_exists('group_permission_add') || permission_exists('group_permission_edit') || permission_exists('group_permission_delete')) {
+				echo "	<td>&nbsp;</td>\n";
+				echo "	<td class='checkbox'>\n";
+				echo "		<input type='checkbox' name='group_permissions[$x][permission_protected]' id='checkbox_protected_".$x."' class='checkbox_".$application_name."_protected' value='true' ".$protected." onclick=\"if (!this.checked) { document.getElementById('checkbox_all_".$application_name."_protected').checked = false; }\">\n";
+				echo "	</td>\n";
+			}
+			echo "</tr>\n";
+
+			//set the previous category
+			$previous_application_name = $row['application_name'];
+			$x++;
+		}
+		unset($group_permissions);
+	}
+
+	echo "</table>\n";
+	echo "</form>\n";
+
+//include the footer
+	require_once "resources/footer.php";
+
+?>

+ 3 - 3
core/groups/groupmemberadd.php

@@ -52,7 +52,7 @@
 
 //validate the token
 	$token = new token;
-	if (!$token->validate('/core/groups/groupmembers.php')) {
+	if (!$token->validate('/core/groups/group_members.php')) {
 		message::add($text['message-invalid_token'],'negative');
 		header('Location: groups.php');
 		exit;
@@ -81,6 +81,6 @@
 	}
 
 //redirect the user
-	header("Location: groupmembers.php?group_uuid=".$group_uuid."&group_name=".$group_name);
+	header("Location: group_members.php?group_uuid=".urlencode($group_uuid)."&group_name=".urlencode($group_name));
 
-?>
+?>

+ 1 - 1
core/groups/groupmemberdelete.php

@@ -65,6 +65,6 @@
 
 //redirect the user
 	message::add($text['message-delete']);
-	header("Location: groupmembers.php?group_uuid=".$group_uuid."&group_name=".$group_name);
+	header("Location: group_members.php?group_uuid=".$group_uuid."&group_name=".$group_name);
 
 ?>

+ 3 - 16
core/groups/groups.php

@@ -125,19 +125,6 @@
 	$groups = $database->select($sql, $parameters, 'all');
 	unset($sql, $parameters);
 
-//get permission counts for each group
-	if (is_array($groups) && @sizeof($groups) != 0) {
-		$sql = "select group_uuid, count(group_permission_uuid) as permission_count from v_group_permissions group by group_uuid";
-		$database = new database;
-		$result = $database->select($sql, null, 'all');
-		if (is_array($result) && @sizeof($result) != 0) {
-			foreach ($result as $row) {
-				$group_permissions[$row['group_uuid']] = $row['permission_count'];
-			}
-		}
-		unset($sql);
-	}
-
 //create token
 	$object = new token;
 	$token = $object->create($_SERVER['PHP_SELF']);
@@ -245,8 +232,8 @@
 				echo "	".escape($row['group_name']);
 			}
 			echo "	</td>\n";
-			echo "	<td class='no-link no-wrap pr-15'><a href='group_permissions.php?group_uuid=".urlencode($row['group_uuid'])."'>".$text['label-group_permissions']." (".($group_permissions[$row['group_uuid']] ?: 0).")</a></td>\n";
-			echo "	<td class='no-link no-wrap'><a href='groupmembers.php?group_uuid=".urlencode($row['group_uuid'])."'>".$text['label-group_members']." (".$row['group_members'].")</a></td>\n";
+			echo "	<td class='no-link no-wrap pr-15'><a href='group_permissions.php?group_uuid=".urlencode($row['group_uuid'])."'>".$text['label-group_permissions']." (".$row['group_permissions'].")</a></td>\n";
+			echo "	<td class='no-link no-wrap'><a href='group_members.php?group_uuid=".urlencode($row['group_uuid'])."'>".$text['label-group_members']." (".$row['group_members'].")</a></td>\n";
 			echo "	<td class='center'>".escape($row['group_level'])."</td>\n";
 			if (permission_exists('group_edit')) {
 				echo "	<td class='no-link center'>\n";
@@ -278,4 +265,4 @@
 //include the footer
 	require_once "resources/footer.php";
 
-?>
+?>

+ 4 - 2
core/groups/resources/classes/groups.php

@@ -127,7 +127,7 @@ if (!class_exists('groups')) {
 			//assign the variables
 				$this->name = 'group_member';
 				$this->table = 'user_groups';
-				$this->location = 'groupmembers.php?group_uuid='.$this->group_uuid;
+				$this->location = 'group_members.php?group_uuid='.$this->group_uuid;
 
 			if (permission_exists($this->name.'_delete')) {
 
@@ -445,6 +445,8 @@ if (!class_exists('groups')) {
 								$array['group_permissions'][$x]['group_permission_uuid'] = uuid();
 								$array['group_permissions'][$x]['domain_uuid'] = null;
 								$array['group_permissions'][$x]['permission_name'] = $row['name'];
+								$array['group_permissions'][$x]['permission_protected'] = 'false';
+								$array['group_permissions'][$x]['permission_assigned'] = 'true';
 								$array['group_permissions'][$x]['group_name'] = $group;
 								$array['group_permissions'][$x]['group_uuid'] = $group_uuids[$group];
 							}
@@ -473,4 +475,4 @@ if (!class_exists('groups')) {
 	}
 }
 
-?>
+?>

+ 21 - 15
core/groups/resources/classes/permission.php

@@ -58,14 +58,15 @@
 					}
 					$group_names = "'".implode("','", $group_name_array)."'";
 
-				//delete unprotected system group permissions
+				//delete unprotected permissions
 					$sql = "delete from v_group_permissions as p ";
 					$sql .= "where group_name in ( ";
 					$sql .= "	select group_name ";
 					$sql .= "	from v_groups ";
 					$sql .= "	where group_protected <> 'true' ";
 					$sql .= "	and group_name in (".$group_names.") ";
-					$sql .= ");";
+					$sql .= ")";
+					$sql .= "and (permission_protected <> 'true' or permission_protected is null)";
 					$database = new database;
 					$result = $database->select($sql);
 
@@ -120,6 +121,11 @@
 
 				//delete the group permissions
 					$this->delete();
+					
+				//get the remaining group permissions
+					$sql = "select permission_name, group_name from v_group_permissions ";
+					$database = new database;
+					$database_group_permissions = $database->select($sql, null, 'all');
 
 				//get the $apps array from the installed apps from the core and mod directories
 					$config_list = glob($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH."/*/*/app_config.php");
@@ -149,23 +155,23 @@
 												}
 											}
 										}
-
 										if (!$group_protected) {
-											//if the item uuid is not currently in the db then add it
-											$sql = "select count(*) from v_group_permissions ";
-											$sql .= "where permission_name = :permission_name ";
-											$sql .= "and group_name = :group_name ";
-											$parameters['permission_name'] = $permission['name'];
-											$parameters['group_name'] = $group_name;
-
-											$database = new database;
-											$num_rows = $database->select($sql, $parameters, 'column');
-											unset($sql, $parameters);
-
-											if ($num_rows == 0) {
+											// check if the item is not currently in the database
+											$exists = false;
+											foreach ($database_group_permissions as $i => $group_permission) {
+												if ($group_permission['permission_name'] == $permission['name']) {
+													if ($group_permission['group_name'] == $group_name) {
+														$exists = true;
+														break;
+													}
+												}
+											}
+											if (!$exists) {
 												//build default permissions insert array
 												$array['group_permissions'][$x]['group_permission_uuid'] = uuid();
 												$array['group_permissions'][$x]['permission_name'] = $permission['name'];
+												$array['group_permissions'][$x]['permission_protected'] = 'false';
+												$array['group_permissions'][$x]['permission_assigned'] = 'true';
 												$array['group_permissions'][$x]['group_name'] = $group_name;
 												$array['group_permissions'][$x]['group_uuid'] = $group_uuid;
 												$x++;

+ 0 - 1
core/menu/app_menu.php

@@ -142,7 +142,6 @@
 	$apps[$x]['menu'][$y]['icon'] = "fa-chart-bar";
 	$apps[$x]['menu'][$y]['path'] = "";
 	$apps[$x]['menu'][$y]['order'] = "25";
-	$apps[$x]['menu'][$y]['groups'][] = "user";
 	$apps[$x]['menu'][$y]['groups'][] = "admin";
 	$apps[$x]['menu'][$y]['groups'][] = "superadmin";
 	$y++;

+ 230 - 229
core/menu/menu_edit.php

@@ -1,230 +1,231 @@
-<?php
-/*
-	FusionPBX
-	Version: MPL 1.1
-
-	The contents of this file are subject to the Mozilla Public License Version
-	1.1 (the "License"); you may not use this file except in compliance with
-	the License. You may obtain a copy of the License at
-	http://www.mozilla.org/MPL/
-
-	Software distributed under the License is distributed on an "AS IS" basis,
-	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-	for the specific language governing rights and limitations under the
-	License.
-
-	The Original Code is FusionPBX
-
-	The Initial Developer of the Original Code is
-	Mark J Crane <[email protected]>
-	Portions created by the Initial Developer are Copyright (C) 2008-2020
-	the Initial Developer. All Rights Reserved.
-
-	Contributor(s):
-	Mark J Crane <[email protected]>
-*/
-
-//includes
-	require_once "root.php";
-	require_once "resources/require.php";
-	require_once "resources/check_auth.php";
-
-//check permissions
-	if (permission_exists('menu_add') || permission_exists('menu_edit')) {
-		//access granted
-	}
-	else {
-		echo "access denied";
-		exit;
-	}
-
-//add multi-lingual support
-	$language = new text;
-	$text = $language->get();
-
-//action add or update
-	if (is_uuid($_REQUEST["id"])) {
-		$action = "update";
-		$menu_uuid = $_REQUEST["id"];
-	}
-	else {
-		$action = "add";
-	}
-
-//get http post variables and set them to php variables
-	if (count($_POST) > 0) {
-		$menu_uuid = $_POST["menu_uuid"];
-		$menu_name = $_POST["menu_name"];
-		$menu_language = $_POST["menu_language"];
-		$menu_description = $_POST["menu_description"];
-	}
-
-//process the http post
-	if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
-
-		//validate the token
-			$token = new token;
-			if (!$token->validate($_SERVER['PHP_SELF'])) {
-				message::add($text['message-invalid_token'],'negative');
-				header('Location: menu.php');
-				exit;
-			}
-
-		//check for all required data
-			$msg = '';
-			//if (strlen($menu_name) == 0) { $msg .= $text['message-required'].$text['label-name']."<br>\n"; }
-			//if (strlen($menu_language) == 0) { $msg .= $text['message-required'].$text['label-language']."<br>\n"; }
-			//if (strlen($menu_description) == 0) { $msg .= $text['message-required'].$text['label-description']."<br>\n"; }
-			if (strlen($msg) > 0 && strlen($_POST["persistformvar"]) == 0) {
-				require_once "resources/header.php";
-				require_once "resources/persist_form_var.php";
-				echo "<div align='center'>\n";
-				echo "<table><tr><td>\n";
-				echo $msg."<br />";
-				echo "</td></tr></table>\n";
-				persistformvar($_POST);
-				echo "</div>\n";
-				require_once "resources/footer.php";
-				return;
-			}
-
-		//add or update the database
-		if ($_POST["persistformvar"] != "true") {
-			if ($action == "add") {
-				//create a new unique id
-					$menu_uuid = uuid();
-
-				//start a new menu
-					$array['menus'][0]['menu_uuid'] = $menu_uuid;
-					$array['menus'][0]['menu_name'] = $menu_name;
-					$array['menus'][0]['menu_language'] = $menu_language;
-					$array['menus'][0]['menu_description'] = $menu_description;
-					$database = new database;
-					$database->app_name = 'menu';
-					$database->app_uuid = 'f4b3b3d2-6287-489c-2a00-64529e46f2d7';
-					$database->save($array);
-					unset($array);
-
-				//redirect the user back to the main menu
-					message::add($text['message-add']);
-					header("Location: menu.php");
-					return;
-			} //if ($action == "add")
-
-			if ($action == "update") {
-				//update the menu
-					$array['menus'][0]['menu_uuid'] = $menu_uuid;
-					$array['menus'][0]['menu_name'] = $menu_name;
-					$array['menus'][0]['menu_language'] = $menu_language;
-					$array['menus'][0]['menu_description'] = $menu_description;
-					$database = new database;
-					$database->app_name = 'menu';
-					$database->app_uuid = 'f4b3b3d2-6287-489c-2a00-64529e46f2d7';
-					$database->save($array);
-					unset($array);
-
-				//redirect the user back to the main menu
-					message::add($text['message-update']);
-					header("Location: menu.php");
-					return;
-			}
-		}
-	}
-
-//pre-populate the form
-	if (count($_GET) > 0 && is_uuid($_GET["id"]) && $_POST["persistformvar"] != "true") {
-		$menu_uuid = $_GET["id"];
-		$sql = "select * from v_menus ";
-		$sql .= "where menu_uuid = :menu_uuid ";
-		$parameters['menu_uuid'] = $menu_uuid;
-		$database = new database;
-		$row = $database->select($sql, $parameters, 'row');
-		if (is_array($row) && sizeof($row) != 0) {
-			$menu_uuid = $row["menu_uuid"];
-			$menu_name = $row["menu_name"];
-			$menu_language = $row["menu_language"];
-			$menu_description = $row["menu_description"];
-		}
-		unset($sql, $parameters, $row);
-	}
-
-//create token
-	$object = new token;
-	$token = $object->create($_SERVER['PHP_SELF']);
-
-//show the header
-	$document['title'] = $text['title-menu'];
-	require_once "resources/header.php";
-
-//show the content
-	echo "<form method='post' name='frm' id='frm'>\n";
-
-	echo "<div class='action_bar' id='action_bar'>\n";
-	echo "	<div class='heading'><b>".$text['header-menu']."</b></div>\n";
-	echo "	<div class='actions'>\n";
-	echo button::create(['type'=>'button','label'=>$text['button-back'],'icon'=>$_SESSION['theme']['button_icon_back'],'id'=>'btn_back','collapse'=>'hide-xs','link'=>'menu.php']);
-	if (permission_exists('menu_restore') && $action == "update") {
-		echo button::create(['type'=>'button','label'=>$text['button-restore_default'],'icon'=>$_SESSION['theme']['button_icon_reload'],'collapse'=>'hide-xs','style'=>'margin-left: 15px;','link'=>'menu_restore_default.php?menu_uuid='.urlencode($menu_uuid).'&menu_language='.urlencode($menu_language)]);
-	}
-	echo button::create(['type'=>'submit','label'=>$text['button-save'],'icon'=>$_SESSION['theme']['button_icon_save'],'id'=>'btn_save','collapse'=>'hide-xs','style'=>'margin-left: 15px;']);
-	echo "	</div>\n";
-	echo "	<div style='clear: both;'></div>\n";
-	echo "</div>\n";
-
-	echo $text['description-menu']."\n";
-	echo "<br /><br />\n";
-
-	echo "<table width='100%' border='0' cellpadding='0' cellspacing='0'>\n";
-
-	echo "<tr>\n";
-	echo "<td width='30%' class='vncellreq' valign='top' align='left' nowrap='nowrap'>\n";
-	echo "	".$text['label-name']."\n";
-	echo "</td>\n";
-	echo "<td width='70%' class='vtable' align='left'>\n";
-	echo "	<input class='formfld' type='text' name='menu_name' maxlength='255' value=\"".escape($menu_name)."\">\n";
-	echo "<br />\n";
-	echo "\n";
-	echo $text['description-name']."</td>\n";
-	echo "</tr>\n";
-
-	echo "<tr>\n";
-	echo "<td class='vncellreq' valign='top' align='left' nowrap='nowrap'>\n";
-	echo "	".$text['label-language']."\n";
-	echo "</td>\n";
-	echo "<td class='vtable' align='left'>\n";
-	echo "	<input class='formfld' type='text' name='menu_language' maxlength='255' value=\"".escape($menu_language)."\">\n";
-	echo "<br />\n";
-	echo $text['description-language']."\n";
-	echo "</td>\n";
-	echo "</tr>\n";
-
-	echo "<tr>\n";
-	echo "<td class='vncell' valign='top' align='left' nowrap='nowrap'>\n";
-	echo "	".$text['label-description']."\n";
-	echo "</td>\n";
-	echo "<td class='vtable' align='left'>\n";
-	echo "	<input class='formfld' type='text' name='menu_description' maxlength='255' value=\"".escape($menu_description)."\">\n";
-	echo "<br />\n";
-	echo $text['description-description']."\n";
-	echo "</td>\n";
-	echo "</tr>\n";
-
-	echo "</table>";
-	echo "<br><br>";
-
-	if ($action == "update") {
-		echo "<input type='hidden' name='menu_uuid' value='".escape($menu_uuid)."'>\n";
-	}
-	echo "<input type='hidden' name='".$token['name']."' value='".$token['hash']."'>\n";
-
-	echo "</form>";
-
-//show the menu items
-	if ($action == "update") {
-		require_once "core/menu/menu_item_list.php";
-	}
-
-//include the footer
-	require_once "resources/footer.php";
-
+<?php
+/*
+	FusionPBX
+	Version: MPL 1.1
+
+	The contents of this file are subject to the Mozilla Public License Version
+	1.1 (the "License"); you may not use this file except in compliance with
+	the License. You may obtain a copy of the License at
+	http://www.mozilla.org/MPL/
+
+	Software distributed under the License is distributed on an "AS IS" basis,
+	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+	for the specific language governing rights and limitations under the
+	License.
+
+	The Original Code is FusionPBX
+
+	The Initial Developer of the Original Code is
+	Mark J Crane <[email protected]>
+	Portions created by the Initial Developer are Copyright (C) 2008-2020
+	the Initial Developer. All Rights Reserved.
+
+	Contributor(s):
+	Mark J Crane <[email protected]>
+*/
+
+//includes
+	require_once "root.php";
+	require_once "resources/require.php";
+	require_once "resources/check_auth.php";
+
+//check permissions
+	if (permission_exists('menu_add') || permission_exists('menu_edit')) {
+		//access granted
+	}
+	else {
+		echo "access denied";
+		exit;
+	}
+
+//add multi-lingual support
+	$language = new text;
+	$text = $language->get();
+
+//action add or update
+	if (is_uuid($_REQUEST["id"])) {
+		$action = "update";
+		$menu_uuid = $_REQUEST["id"];
+	}
+	else {
+		$action = "add";
+	}
+
+//get http post variables and set them to php variables
+	if (count($_POST) > 0) {
+		$menu_uuid = $_POST["menu_uuid"];
+		$menu_name = $_POST["menu_name"];
+		$menu_language = $_POST["menu_language"];
+		$menu_description = $_POST["menu_description"];
+	}
+
+//process the http post
+	if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
+
+		//validate the token
+			$token = new token;
+			if (!$token->validate($_SERVER['PHP_SELF'])) {
+				message::add($text['message-invalid_token'],'negative');
+				header('Location: menu.php');
+				exit;
+			}
+
+		//check for all required data
+			$msg = '';
+			//if (strlen($menu_name) == 0) { $msg .= $text['message-required'].$text['label-name']."<br>\n"; }
+			//if (strlen($menu_language) == 0) { $msg .= $text['message-required'].$text['label-language']."<br>\n"; }
+			//if (strlen($menu_description) == 0) { $msg .= $text['message-required'].$text['label-description']."<br>\n"; }
+			if (strlen($msg) > 0 && strlen($_POST["persistformvar"]) == 0) {
+				require_once "resources/header.php";
+				require_once "resources/persist_form_var.php";
+				echo "<div align='center'>\n";
+				echo "<table><tr><td>\n";
+				echo $msg."<br />";
+				echo "</td></tr></table>\n";
+				persistformvar($_POST);
+				echo "</div>\n";
+				require_once "resources/footer.php";
+				return;
+			}
+
+		//add or update the database
+		if ($_POST["persistformvar"] != "true") {
+			if ($action == "add") {
+				//create a new unique id
+					$menu_uuid = uuid();
+
+				//start a new menu
+					$array['menus'][0]['menu_uuid'] = $menu_uuid;
+					$array['menus'][0]['menu_name'] = $menu_name;
+					$array['menus'][0]['menu_language'] = $menu_language;
+					$array['menus'][0]['menu_description'] = $menu_description;
+					$database = new database;
+					$database->app_name = 'menu';
+					$database->app_uuid = 'f4b3b3d2-6287-489c-2a00-64529e46f2d7';
+					$database->save($array);
+					unset($array);
+
+				//redirect the user back to the main menu
+					message::add($text['message-add']);
+					header("Location: menu.php");
+					return;
+			} //if ($action == "add")
+
+			if ($action == "update") {
+				//update the menu
+					$array['menus'][0]['menu_uuid'] = $menu_uuid;
+					$array['menus'][0]['menu_name'] = $menu_name;
+					$array['menus'][0]['menu_language'] = $menu_language;
+					$array['menus'][0]['menu_description'] = $menu_description;
+					$database = new database;
+					$database->app_name = 'menu';
+					$database->app_uuid = 'f4b3b3d2-6287-489c-2a00-64529e46f2d7';
+					$database->save($array);
+					unset($array);
+
+				//redirect the user back to the main menu
+					message::add($text['message-update']);
+					header("Location: menu.php");
+					return;
+			}
+		}
+	}
+
+//pre-populate the form
+	if (count($_GET) > 0 && is_uuid($_GET["id"]) && $_POST["persistformvar"] != "true") {
+		$menu_uuid = $_GET["id"];
+		$sql = "select * from v_menus ";
+		$sql .= "where menu_uuid = :menu_uuid ";
+		$parameters['menu_uuid'] = $menu_uuid;
+		$database = new database;
+		$row = $database->select($sql, $parameters, 'row');
+		if (is_array($row) && sizeof($row) != 0) {
+			$menu_uuid = $row["menu_uuid"];
+			$menu_name = $row["menu_name"];
+			$menu_language = $row["menu_language"];
+			$menu_description = $row["menu_description"];
+		}
+		unset($sql, $parameters, $row);
+	}
+
+//create token
+	$object = new token;
+	$token = $object->create($_SERVER['PHP_SELF']);
+
+//show the header
+	$document['title'] = $text['title-menu'];
+	require_once "resources/header.php";
+
+//show the content
+	echo "<form method='post' name='frm' id='frm'>\n";
+
+	echo "<div class='action_bar' id='action_bar'>\n";
+	echo "	<div class='heading'><b>".$text['header-menu']."</b></div>\n";
+	echo "	<div class='actions'>\n";
+	echo button::create(['type'=>'button','label'=>$text['button-back'],'icon'=>$_SESSION['theme']['button_icon_back'],'id'=>'btn_back','collapse'=>'hide-xs','link'=>'menu.php']);
+	echo button::create(['type'=>'button','label'=>$text['button-reload'],'icon'=>$_SESSION['theme']['button_icon_reload'],'collapse'=>'hide-xs','style'=>'margin-left: 15px;','link'=>'menu_reload.php?menu_uuid='.urlencode($menu_uuid).'&menu_language='.urlencode($menu_language)]);
+	if (permission_exists('menu_restore') && $action == "update") {
+		echo button::create(['type'=>'button','label'=>$text['button-restore_default'],'icon'=>'key','collapse'=>'hide-xs','link'=>'menu_restore_default.php?menu_uuid='.urlencode($menu_uuid).'&menu_language='.urlencode($menu_language)]);
+	}
+	echo button::create(['type'=>'submit','label'=>$text['button-save'],'icon'=>$_SESSION['theme']['button_icon_save'],'id'=>'btn_save','collapse'=>'hide-xs']);
+	echo "	</div>\n";
+	echo "	<div style='clear: both;'></div>\n";
+	echo "</div>\n";
+
+	echo $text['description-menu']."\n";
+	echo "<br /><br />\n";
+
+	echo "<table width='100%' border='0' cellpadding='0' cellspacing='0'>\n";
+
+	echo "<tr>\n";
+	echo "<td width='30%' class='vncellreq' valign='top' align='left' nowrap='nowrap'>\n";
+	echo "	".$text['label-name']."\n";
+	echo "</td>\n";
+	echo "<td width='70%' class='vtable' align='left'>\n";
+	echo "	<input class='formfld' type='text' name='menu_name' maxlength='255' value=\"".escape($menu_name)."\">\n";
+	echo "<br />\n";
+	echo "\n";
+	echo $text['description-name']."</td>\n";
+	echo "</tr>\n";
+
+	echo "<tr>\n";
+	echo "<td class='vncellreq' valign='top' align='left' nowrap='nowrap'>\n";
+	echo "	".$text['label-language']."\n";
+	echo "</td>\n";
+	echo "<td class='vtable' align='left'>\n";
+	echo "	<input class='formfld' type='text' name='menu_language' maxlength='255' value=\"".escape($menu_language)."\">\n";
+	echo "<br />\n";
+	echo $text['description-language']."\n";
+	echo "</td>\n";
+	echo "</tr>\n";
+
+	echo "<tr>\n";
+	echo "<td class='vncell' valign='top' align='left' nowrap='nowrap'>\n";
+	echo "	".$text['label-description']."\n";
+	echo "</td>\n";
+	echo "<td class='vtable' align='left'>\n";
+	echo "	<input class='formfld' type='text' name='menu_description' maxlength='255' value=\"".escape($menu_description)."\">\n";
+	echo "<br />\n";
+	echo $text['description-description']."\n";
+	echo "</td>\n";
+	echo "</tr>\n";
+
+	echo "</table>";
+	echo "<br><br>";
+
+	if ($action == "update") {
+		echo "<input type='hidden' name='menu_uuid' value='".escape($menu_uuid)."'>\n";
+	}
+	echo "<input type='hidden' name='".$token['name']."' value='".$token['hash']."'>\n";
+
+	echo "</form>";
+
+//show the menu items
+	if ($action == "update") {
+		require_once "core/menu/menu_item_list.php";
+	}
+
+//include the footer
+	require_once "resources/footer.php";
+
 ?>

+ 62 - 0
core/menu/menu_reload.php

@@ -0,0 +1,62 @@
+<?php
+/*
+	FusionPBX
+	Version: MPL 1.1
+
+	The contents of this file are subject to the Mozilla Public License Version
+	1.1 (the "License"); you may not use this file except in compliance with
+	the License. You may obtain a copy of the License at
+	http://www.mozilla.org/MPL/
+
+	Software distributed under the License is distributed on an "AS IS" basis,
+	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+	for the specific language governing rights and limitations under the
+	License.
+
+	The Original Code is FusionPBX
+
+	The Initial Developer of the Original Code is
+	Mark J Crane <[email protected]>
+	Portions created by the Initial Developer are Copyright (C) 2020
+	the Initial Developer. All Rights Reserved.
+
+	Contributor(s):
+	Mark J Crane <[email protected]>
+*/
+
+//includes
+	include "root.php";
+	require_once "resources/require.php";
+	require_once "resources/check_auth.php";
+	
+//check permissions
+	if (permission_exists('menu_add') || permission_exists('menu_edit')) {
+		//access granted
+	}
+	else {
+		echo "access denied";
+		return;
+	}
+
+//add multi-lingual support
+	$language = new text;
+	$text = $language->get();
+
+//get the http value and set as a php variable
+	$menu_uuid = $_REQUEST["menu_uuid"];
+
+//unset the sesssion menu array
+	unset($_SESSION['menu']['array']);
+
+//get the menu array and save it to the session
+	$menu = new menu;
+	$menu->menu_uuid = $_SESSION['domain']['menu']['uuid'];
+	$_SESSION['menu']['array'] = $menu->menu_array();
+	unset($menu);
+
+//redirect the user
+	message::add($text['message-reload']);
+	header("Location: ".PROJECT_PATH."/core/menu/menu_edit.php?id=".urlencode($menu_uuid));
+	return;
+
+?>

+ 12 - 1
core/software/app_defaults.php

@@ -17,7 +17,7 @@
 
 	The Initial Developer of the Original Code is
 	Mark J Crane <[email protected]>
-	Portions created by the Initial Developer are Copyright (C) 2008-2019
+	Portions created by the Initial Developer are Copyright (C) 2008-2020
 	the Initial Developer. All Rights Reserved.
 
 	Contributor(s):
@@ -45,12 +45,23 @@ if ($domains_processed == 1) {
 			$array['software'][0]['software_uuid'] = '7de057e7-333b-4ebf-9466-315ae7d44efd';
 			$array['software'][0]['software_version'] = software::version();
 		}
+
+		//add the temporary permission
+		$p = new permissions;
+		$p->add("software_add", 'temp');
+		$p->add("software_edit", 'temp');
+
+		//save the data
 		$database = new database;
 		$database->app_name = 'software';
 		$database->app_uuid = 'b88c795f-7dea-4fc8-9ab7-edd555242cff';
 		$database->save($array);
 		unset($array);
 
+		//remove the temporary permission
+		$p->delete("software_add", 'temp');
+		$p->delete("software_edit", 'temp');
+
 }
 
 ?>

+ 2 - 2
core/software/resources/classes/software.php

@@ -12,14 +12,14 @@ if (!class_exists('software')) {
 		 * version
 		 */
 		public static function version() {
-			return '4.5.13';
+			return '4.5.18';
 		}
 
 		/**
 		 * numeric_version
 		 */
 		public static function numeric_version() {
-			$v = explode('.', $this->version());
+			$v = explode('.', software::version());
 			$n = ($v[0] * 10000 + $v[1] * 100 + $v[2]);
 			return $n;
 		}

+ 1 - 1
core/upgrade/app_defaults.php

@@ -52,7 +52,7 @@ if ($domains_processed == 1) {
 			$sql .= "'login', ";
 			$sql .= "'message', ";
 			$sql .= "'text', ";
-			$sql .= "':default_setting_value, ";
+			$sql .= ":default_setting_value, ";
 			$sql .= "'true', ";
 			$sql .= "'' ";
 			$sql .= ")";

+ 2 - 1
core/upgrade/index.php

@@ -182,7 +182,7 @@
 		echo "<table width='100%' border='0' cellpadding='0' cellspacing='0'>\n";
 		echo "<tr>\n";
 		echo "	<td width='30%' class='vncell' style='vertical-align:middle;'>\n";
-		echo "		<div style='".$step_container_style."'><span style='".$step_number_style."'>".$step++."</span></div>";
+		echo "		<div style='".$step_container_style."'><span style='".$step_number_style."'>".$step."</span></div>";
 		echo "		".$text['label-upgrade_schema'];
 		echo "	</td>\n";
 		echo "	<td width='70%' class='vtable' style='height: 50px;'>\n";
@@ -195,6 +195,7 @@
 		echo "<table width='100%' border='0' cellpadding='0' cellspacing='0'>\n";
 		echo "<tr>\n";
 		echo "	<td width='30%' class='vncell' style='vertical-align:middle;'>\n";
+		echo "		<div style='".$step_container_style."'><span style='".$step_number_style." letter-spacing: -0.06em;'>".$step++."B</span></div>";
 		echo "		".$text['label-upgrade_data_types'];
 		echo "	</td>\n";
 		echo "	<td width='70%' class='vtable' style='height: 50px;'>\n";

+ 4 - 1
core/user_settings/app_config.php

@@ -103,7 +103,10 @@
 		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
 		$z++;
 		$apps[$x]['db'][$y]['fields'][$z]['name'] = "user_setting_enabled";
-		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['pgsql'] = "boolean";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['sqlite'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['mysql'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['toggle'] = ['true','false'];
 		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
 		$z++;
 		$apps[$x]['db'][$y]['fields'][$z]['name'] = "user_setting_description";

+ 0 - 34
core/user_settings/user_dashboard.php

@@ -993,40 +993,6 @@
 				$hud[$n]['html'] .= "</tr>\n";
 				$c = ($c) ? 0 : 1;
 
-			$fp = event_socket_create($_SESSION['event_socket_ip_address'], $_SESSION['event_socket_port'], $_SESSION['event_socket_password']);
-			if ($fp) {
-				//switch version
-					$switch_version = event_socket_request($fp, 'api version');
-					preg_match("/FreeSWITCH Version (\d+\.\d+\.\d+(?:\.\d+)?).*\(.*?(\d+\w+)\s*\)/", $switch_version, $matches);
-					$switch_version = $matches[1];
-					$switch_bits = $matches[2];
-					if ($switch_version != '' && $switch_bits != '') {
-						$hud[$n]['html'] .= "<tr class='tr_link_void'>\n";
-						$hud[$n]['html'] .= "<td valign='top' class='".$row_style[$c]." hud_text'>".$text['label-switch']."</td>\n";
-						$hud[$n]['html'] .= "<td valign='top' class='".$row_style[$c]." hud_text' style='text-align: right;'>".$switch_version." (".$switch_bits.")</td>\n";
-						$hud[$n]['html'] .= "</tr>\n";
-						$c = ($c) ? 0 : 1;
-					}
-
-				//switch uptime
-					$tmp = event_socket_request($fp, 'api status');
-					$tmp = explode("\n", $tmp);
-					$tmp = $tmp[0];
-					$tmp = explode(' ', $tmp);
-					$uptime = (($tmp[1]) ? $tmp[1].'y ' : null);
-					$uptime .= (($tmp[3]) ? $tmp[3].'d ' : null);
-					$uptime .= (($tmp[5]) ? $tmp[5].'h ' : null);
-					$uptime .= (($tmp[7]) ? $tmp[7].'m ' : null);
-					$uptime .= (($tmp[9]) ? $tmp[9].'s' : null);
-					if ($uptime != '') {
-						$hud[$n]['html'] .= "<tr class='tr_link_void'>\n";
-						$hud[$n]['html'] .= "<td valign='top' class='".$row_style[$c]." hud_text'>".$text['label-switch_uptime']."</td>\n";
-						$hud[$n]['html'] .= "<td valign='top' class='".$row_style[$c]." hud_text' style='text-align: right;'>".$uptime."</td>\n";
-						$hud[$n]['html'] .= "</tr>\n";
-						$c = ($c) ? 0 : 1;
-					}
-			}
-
 			//os uptime
 				if (stristr(PHP_OS, 'Linux')) {
 					unset($tmp);

+ 36 - 7
core/user_settings/user_setting_edit.php

@@ -317,13 +317,14 @@ if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
 }
 
 //pre-populate the form
-	if (is_uuid($_GET["id"]) && count($_GET)>0 && $_POST["persistformvar"] != "true") {
+	if (is_uuid($_GET["id"]) && count($_GET) > 0 && $_POST["persistformvar"] != "true") {
 		$user_setting_uuid = $_GET["id"];
-		$sql = "select * from v_user_settings ";
-		$sql .= "where user_uuid = :user_uuid ";
-		$sql .= "and user_setting_uuid = :user_setting_uuid ";
-		$parameters['user_uuid'] = $user_uuid;
+		$sql = "select user_setting_category, user_setting_subcategory, user_setting_name, user_setting_value, cast(user_setting_enabled as text), user_setting_description ";
+		$sql .= "from v_user_settings ";
+		$sql .= "where user_setting_uuid = :user_setting_uuid ";
+		$sql .= "and user_uuid = :user_uuid ";
 		$parameters['user_setting_uuid'] = $user_setting_uuid;
+		$parameters['user_uuid'] = $user_uuid;
 		$database = new database;
 		$row = $database->select($sql, $parameters, 'row');
 		if (is_array($row) && sizeof($row) != 0) {
@@ -605,6 +606,7 @@ if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
 		echo "    <select class='formfld' id='user_setting_value' name='user_setting_value'>\n";
 		echo "    	<option value='image' ".(($user_setting_value == "image") ? "selected='selected'" : null).">".$text['label-image']."</option>\n";
 		echo "    	<option value='text' ".(($user_setting_value == "text") ? "selected='selected'" : null).">".$text['label-text']."</option>\n";
+		echo "    	<option value='image_text' ".(($user_setting_value == "image_text") ? "selected='selected'" : null).">".$text['label-image_text']."</option>\n";
 		echo "    	<option value='none' ".(($user_setting_value == "none") ? "selected='selected'" : null).">".$text['label-none']."</option>\n";
 		echo "    </select>\n";
 	}
@@ -628,6 +630,33 @@ if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
 		echo "    	<option value='right' ".(($user_setting_value == "right") ? "selected='selected'" : null).">".$text['label-right']."</option>\n";
 		echo "    </select>\n";
 	}
+	elseif ($user_setting_category == "theme" && $user_setting_subcategory == "menu_side_state" && $user_setting_name == "text" ) {
+		echo "    <select class='formfld' id='user_setting_value' name='user_setting_value'>\n";
+		echo "    	<option value='expanded'>".$text['option-expanded']."</option>\n";
+		echo "    	<option value='contracted' ".($user_setting_value == "contracted" ? "selected='selected'" : null).">".$text['option-contracted']."</option>\n";
+		echo "    	<option value='hidden' ".($user_setting_value == "hidden" ? "selected='selected'" : null).">".$text['option-hidden']."</option>\n";
+		echo "    </select>\n";
+	}
+	elseif ($user_setting_category == "theme" && $user_setting_subcategory == "menu_side_toggle" && $user_setting_name == "text" ) {
+		echo "    <select class='formfld' id='user_setting_value' name='user_setting_value'>\n";
+		echo "    	<option value='hover'>".$text['option-hover']."</option>\n";
+		echo "    	<option value='click' ".($user_setting_value == "click" ? "selected='selected'" : null).">".$text['option-click']."</option>\n";
+		echo "    </select>\n";
+	}
+	elseif ($user_setting_category == "theme" && $user_setting_subcategory == "menu_side_toggle_body_width" && $user_setting_name == "text" ) {
+		echo "    <select class='formfld' id='user_setting_value' name='user_setting_value'>\n";
+		echo "    	<option value='shrink'>".$text['option-shrink']."</option>\n";
+		echo "    	<option value='fixed' ".($user_setting_value == "fixed" ? "selected='selected'" : null).">".$text['option-fixed']."</option>\n";
+		echo "    </select>\n";
+	}
+	else if ($user_setting_category == "theme" && $user_setting_subcategory == "body_header_brand_type" && $user_setting_name == "text" ) {
+		echo "    <select class='formfld' id='user_setting_value' name='user_setting_value'>\n";
+		echo "    	<option value='image' ".(($user_setting_value == "image") ? "selected='selected'" : null).">".$text['label-image']."</option>\n";
+		echo "    	<option value='text' ".(($user_setting_value == "text") ? "selected='selected'" : null).">".$text['label-text']."</option>\n";
+		echo "    	<option value='image_text' ".(($user_setting_value == "image_text") ? "selected='selected'" : null).">".$text['label-image_text']."</option>\n";
+		echo "    	<option value='none' ".(($user_setting_value == "none") ? "selected='selected'" : null).">".$text['label-none']."</option>\n";
+		echo "    </select>\n";
+	}
 	else {
 		echo "	<input class='formfld' type='text' id='user_setting_value' name='user_setting_value' maxlength='255' value=\"".escape($user_setting_value)."\">\n";
 	}
@@ -700,7 +729,7 @@ if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
 	echo "	".$text['label-description']."\n";
 	echo "</td>\n";
 	echo "<td class='vtable' align='left'>\n";
-	echo "	<input class='formfld' type='text' name='user_setting_description' maxlength='255' value=\"".escape($user_setting_description)."\">\n";
+	echo "	<input class='formfld' type='text' name='user_setting_description' style='width: 80%; max-width: 600px; min-width: 167px;' maxlength='255' value=\"".escape($user_setting_description)."\">\n";
 	echo "<br />\n";
 	echo $text['description-description']."\n";
 	echo "</td>\n";
@@ -736,4 +765,4 @@ if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
 //include the footer
 	require_once "resources/footer.php";
 
-?>
+?>

+ 160 - 0
core/user_settings/user_setting_set.php

@@ -0,0 +1,160 @@
+<?php
+/*
+FusionPBX
+Version: MPL 1.1
+
+The contents of this file are subject to the Mozilla Public License Version
+1.1 (the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is FusionPBX
+
+The Initial Developer of the Original Code is
+Mark J Crane <[email protected]>
+Portions created by the Initial Developer are Copyright (C) 2020
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+Mark J Crane <[email protected]>
+*/
+
+//includes
+	require_once "root.php";
+	require_once "resources/require.php";
+  	require_once "resources/check_auth.php";
+
+//add multi-lingual support
+	$language = new text;
+	$text = $language->get();
+
+//get http post variables and set them to php variables
+	if (is_array($_GET) && @sizeof($_GET) != 0) {
+		$user_setting_category = strtolower($_GET['category']);
+		$user_setting_subcategory = strtolower($_GET['subcategory']);
+		$user_setting_name = strtolower($_GET['name']);
+		$submitted_value = $_GET['value'];
+		//$submitted_order = is_numeric($_GET['order']) ? $_GET['order'] : null;
+		$submitted_enabled = strtolower($_GET['enabled']);
+	}
+
+//validate allowed user setting
+	switch ($user_setting_category) {
+		case 'theme':
+			switch ($user_setting_subcategory) {
+				case 'menu_side_state':
+					if ($submitted_value == 'delete') {
+						$user_setting_value = 'delete';
+						$user_setting_enabled = 'delete';
+					}
+					else if ($submitted_value == 'expanded' || $submitted_value == 'contracted') {
+						$user_setting_value = $submitted_value;
+						$user_setting_enabled = 'true';
+					}
+					break 2;
+				default:
+					//setting not allowed
+					echo 'false';
+					exit;
+			}
+			break;
+		default:
+			//setting not allowed
+			echo 'false';
+			exit;
+	}
+
+//add/update user setting
+	if (isset($user_setting_value) && isset($user_setting_enabled)) {
+
+		//get existing user setting uuid, if exists
+			$sql = "select user_setting_uuid from v_user_settings ";
+			$sql .= "where user_uuid = :user_uuid ";
+			$sql .= "and domain_uuid = :domain_uuid ";
+			$sql .= "and user_setting_category = :user_setting_category ";
+			$sql .= "and user_setting_subcategory = :user_setting_subcategory ";
+			$sql .= "and user_setting_name = :user_setting_name ";
+			$parameters['user_uuid'] = $_SESSION['user_uuid'];
+			$parameters['domain_uuid'] = $_SESSION['domain_uuid'];
+			$parameters['user_setting_category'] = $user_setting_category;
+			$parameters['user_setting_subcategory'] = $user_setting_subcategory;
+			$parameters['user_setting_name'] = $user_setting_name;
+			$database = new database;
+			$user_setting_uuid = $database->select($sql, $parameters, 'column');
+			unset($sql, $parameters);
+
+		//delete user setting
+			if ($user_setting_value == 'delete' && $user_setting_enabled == 'delete') {
+				if (is_uuid($user_setting_uuid)) {
+					//create data array
+						$array['user_settings'][0]['user_setting_uuid'] = $user_setting_uuid;
+						$array['user_settings'][0]['user_uuid'] = $_SESSION['user_uuid'];
+						$array['user_settings'][0]['domain_uuid'] = $_SESSION['domain_uuid'];
+					//grant temporary permissions
+						$p = new permissions;
+						$p->add('user_setting_delete', 'temp');
+					//execute
+						$database = new database;
+						$database->app_name = 'user_settings';
+						$database->app_uuid = '3a3337f7-78d1-23e3-0cfd-f14499b8ed97';
+						$database->delete($array);
+						unset($array);
+					//revoke temporary permissions
+						$p->delete('user_setting_delete', 'temp');
+					//reset session variables to default
+						require "resources/classes/domains.php";
+						$domain = new domains();
+						$domain->db = $db;
+						$domain->set();
+				}
+
+				//set response
+					echo 'deleted';
+
+			}
+
+		//insert or update user setting
+			else {
+
+				//create data array
+					$array['user_settings'][0]['user_setting_uuid'] = is_uuid($user_setting_uuid) ? $user_setting_uuid : uuid();
+					$array['user_settings'][0]['user_uuid'] = $_SESSION['user_uuid'];
+					$array['user_settings'][0]['domain_uuid'] = $_SESSION['domain_uuid'];
+					$array['user_settings'][0]['user_setting_category'] = $user_setting_category;
+					$array['user_settings'][0]['user_setting_subcategory'] = $user_setting_subcategory;
+					$array['user_settings'][0]['user_setting_name'] = $user_setting_name;
+					$array['user_settings'][0]['user_setting_value'] = $user_setting_value;
+					//$array['user_settings'][0]['user_setting_order'] = $user_setting_order;
+					$array['user_settings'][0]['user_setting_enabled'] = $user_setting_enabled;
+
+				//grant temporary permissions
+					$p = new permissions;
+					$p->add('user_setting_add', 'temp');
+					$p->add('user_setting_edit', 'temp');
+
+				//execute
+					$database = new database;
+					$database->app_name = 'user_settings';
+					$database->app_uuid = '3a3337f7-78d1-23e3-0cfd-f14499b8ed97';
+					$database->save($array);
+					unset($array);
+
+				//revoke temporary permissions
+					$p->delete('user_setting_add', 'temp');
+					$p->delete('user_setting_edit', 'temp');
+
+				//update session variable
+					$_SESSION[$user_setting_category][$user_setting_subcategory][$user_setting_name] = $user_setting_value;
+
+				//set response
+					echo 'true';
+
+			}
+	}
+
+?>

+ 16 - 4
core/user_settings/user_settings.php

@@ -128,8 +128,10 @@
 		list($paging_controls, $rows_per_page) = paging($num_rows, $param, $rows_per_page);
 		$offset = $rows_per_page * $page;
 	}
+
 //get the list
-	$sql = "select * from v_user_settings ";
+	$sql = "select user_setting_uuid, user_uuid, user_setting_category, user_setting_subcategory, user_setting_name, user_setting_value, cast(user_setting_enabled as text), user_setting_description ";
+	$sql .= "from v_user_settings ";
 	$sql .= $sql_where;
 	if ($order_by == '') {
 		$sql .= "order by user_setting_category, user_setting_subcategory, user_setting_order asc ";
@@ -272,6 +274,7 @@
 				( $category == "theme" && $subcategory == "menu_brand_type" && $name == "text" ) ||
 				( $category == "theme" && $subcategory == "menu_style" && $name == "text" ) ||
 				( $category == "theme" && $subcategory == "menu_position" && $name == "text" ) ||
+				( $category == "theme" && $subcategory == "body_header_brand_type" && $name == "text" ) ||
 				( $category == "theme" && $subcategory == "logo_align" && $name == "text" )
 				) {
 				echo "		".$text['label-'.escape($row['user_setting_value'])];
@@ -280,14 +283,23 @@
 				echo "		".str_repeat('*', strlen(escape($row['user_setting_value'])));
 			}
 			else if ($category == 'theme' && $subcategory == 'button_icons' && $name == 'text') {
-				echo "		".$text['option-button_icons_'.$row['domain_setting_value']]."\n";
+				echo "		".$text['option-button_icons_'.$row['user_setting_value']]."\n";
+			}
+			else if ($category == 'theme' && $subcategory == 'menu_side_state' && $name == 'text') {
+				echo "		".$text['option-'.$row['user_setting_value']]."\n";
+			}
+			else if ($category == 'theme' && $subcategory == 'menu_side_toggle' && $name == 'text') {
+				echo "		".$text['option-'.$row['user_setting_value']]."\n";
+			}
+			else if ($category == 'theme' && $subcategory == 'menu_side_toggle_body_width' && $name == 'text') {
+				echo "		".$text['option-'.$row['user_setting_value']]."\n";
 			}
 			else if ($category == "theme" && substr_count($subcategory, "_color") > 0 && ($name == "text" || $name == 'array')) {
 				echo "		".(img_spacer('15px', '15px', 'background: '.escape($row['user_setting_value']).'; margin-right: 4px; vertical-align: middle; border: 1px solid '.(color_adjust($row['user_setting_value'], -0.18)).'; padding: -1px;'));
 				echo "<span style=\"font-family: 'Courier New'; line-height: 6pt;\">".escape($row['user_setting_value'])."</span>\n";
 			}
 			else if ($category == 'recordings' && $subcategory == 'storage_type' && $name == 'text') {
-				echo "		".$text['label-'.$row['domain_setting_value']]."\n";
+				echo "		".$text['label-'.$row['user_setting_value']]."\n";
 			}
 			else {
 				echo "		".escape($row['user_setting_value'])."\n";
@@ -340,4 +352,4 @@
 
 	echo "</script>\n";
 
-?>
+?>

+ 5 - 1
core/users/app_config.php

@@ -220,6 +220,7 @@
 		$z++;
 		$apps[$x]['db'][$y]['fields'][$z]['name'] = "user_enabled";
 		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['toggle'] = ['true','false'];
 		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
 		$z++;
 		$apps[$x]['db'][$y]['fields'][$z]['name'] = "add_user";
@@ -346,7 +347,10 @@
 		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
 		$z++;
 		$apps[$x]['db'][$y]['fields'][$z]['name'] = "user_setting_enabled";
-		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['pgsql'] = "boolean";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['sqlite'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['mysql'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['toggle'] = ['true','false'];
 		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
 		$z++;
 		$apps[$x]['db'][$y]['fields'][$z]['name'] = "user_setting_description";

+ 7 - 7
core/users/app_languages.php

@@ -1263,16 +1263,16 @@ $text['label-company_name']['ru-ru'] = "Название компании";
 $text['label-company_name']['sv-se'] = "Företags Namn";
 $text['label-company_name']['uk-ua'] = "Назва компанії";
 
-$text['label-characters']['en-us'] = "Characters";
-$text['label-characters']['en-gb'] = "Characters";
+$text['label-characters']['en-us'] = "Invalid Password Length";
+$text['label-characters']['en-gb'] = "Invalid Password Length";
 $text['label-characters']['ar-eg'] = "الشخصيات";
 $text['label-characters']['de-at'] = "Zeichen"; //copied from de-de
 $text['label-characters']['de-ch'] = "Zeichen"; //copied from de-de
 $text['label-characters']['de-de'] = "Zeichen";
-$text['label-characters']['es-cl'] = "Caracteres";
-$text['label-characters']['es-mx'] = "Caracteres"; //copied from es-cl
-$text['label-characters']['fr-ca'] = "Personnages"; //copied from fr-fr
-$text['label-characters']['fr-fr'] = "Personnages";
+$text['label-characters']['es-cl'] = "Longitud de contraseña inválida";
+$text['label-characters']['es-mx'] = "Longitud de contraseña inválida"; //copied from es-cl
+$text['label-characters']['fr-ca'] = "Longueur de mot de passe non valide"; //copied from fr-fr
+$text['label-characters']['fr-fr'] = "Longueur de mot de passe non valide";
 $text['label-characters']['he-il'] = "דמויות";
 $text['label-characters']['it-it'] = "Caratteri";
 $text['label-characters']['nl-nl'] = "";
@@ -2045,4 +2045,4 @@ $text['button-permissions']['ru-ru'] = "Права";
 $text['button-permissions']['sv-se'] = "Rättigheter";
 $text['button-permissions']['uk-ua'] = "Привілеї";
 
-?>
+?>

+ 3 - 1
core/users/user_edit.php

@@ -569,7 +569,9 @@
 	else {
 		//populate the form with values from db
 			if ($action == 'edit') {
-				$sql = "select * from v_users where user_uuid = :user_uuid ";
+				$sql = "select domain_uuid, user_uuid, username, user_email, api_key, user_enabled, contact_uuid, cast(user_enabled as text), user_status ";
+				$sql .= "from v_users ";
+				$sql .= "where user_uuid = :user_uuid ";
 				if (!permission_exists('user_all')) {
 					$sql .= "and domain_uuid = :domain_uuid ";
 					$parameters['domain_uuid'] = $domain_uuid;

+ 1 - 1
core/users/user_imports.php

@@ -433,7 +433,7 @@
 	echo "</td>\n";
 	echo "<td class='vtable' align='left'>\n";
 	echo "		<select class='formfld' name='from_row'>\n";
-	$i=1;
+	$i=2;
 	while($i<=99) {
 		$selected = ($i == $from_row) ? "selected" : null;
 		echo "			<option value='$i' ".$selected.">$i</option>\n";

+ 5 - 3
core/users/users.php

@@ -17,7 +17,7 @@
 
 	The Initial Developer of the Original Code is
 	Mark J Crane <[email protected]>
-	Portions created by the Initial Developer are Copyright (C) 2008 - 2019
+	Portions created by the Initial Developer are Copyright (C) 2008 - 2020
 	the Initial Developer. All Rights Reserved.
 
 	Contributor(s):
@@ -129,7 +129,9 @@
 	$offset = $rows_per_page * $page;
 
 //get the list
-	$sql = "select * from view_users ";
+	$sql = "select domain_name, domain_uuid, user_uuid, username, groups, ";
+	$sql .= "contact_organization,contact_name, cast(user_enabled as text) ";
+	$sql .= "from view_users ";
 	if ($_GET['show'] == "all" && permission_exists('user_all')) {
 		if (isset($sql_search)) {
 			$sql .= "where ".$sql_search;
@@ -303,4 +305,4 @@
 //include the footer
 	require_once "resources/footer.php";
 
-?>
+?>

+ 229 - 0
resources/app_languages.php

@@ -2900,6 +2900,29 @@ $text['label-global']['sv-se'] = "Global";
 $text['label-global']['uk-ua'] = "Global";
 $text['label-global']['tr-tr'] = "Global";
 
+$text['label-settings']['en-us'] = "Settings";
+$text['label-settings']['en-gb'] = "Settings";
+$text['label-settings']['ar-eg'] = "Global";
+$text['label-settings']['de-at'] = "Einstellungen"; //copied from de-de
+$text['label-settings']['de-ch'] = "Global"; //copied from de-de
+$text['label-settings']['de-de'] = "Einstellungen";
+$text['label-settings']['el-gr'] = "Global";
+$text['label-settings']['es-cl'] = "Global";
+$text['label-settings']['es-mx'] = "Global"; //copied from es-cl
+$text['label-settings']['fr-ca'] = "Global"; //copied from fr-fr
+$text['label-settings']['fr-fr'] = "Configuration";
+$text['label-settings']['he-il'] = "Global";
+$text['label-settings']['it-it'] = "Parametri";
+$text['label-settings']['nl-nl'] = "Instellingen";
+$text['label-settings']['pl-pl'] = "Ustawienia";
+$text['label-settings']['pt-br'] = "Definições"; //copied from pt-pt
+$text['label-settings']['pt-pt'] = "Definições";
+$text['label-settings']['ro-ro'] = "Global";
+$text['label-settings']['ru-ru'] = "Конфигурация";
+$text['label-settings']['sv-se'] = "Inställningar";
+$text['label-settings']['uk-ua'] = "Налаштування";
+$text['label-settings']['tr-tr'] = "Global";
+
 $text['label-none']['en-us'] = "None";
 $text['label-none']['en-gb'] = "None";
 $text['label-none']['ar-eg'] = "";
@@ -3083,6 +3106,28 @@ $text['label-actions']['ru-ru'] = "Действия";
 $text['label-actions']['sv-se'] = "Åtgärder";
 $text['label-actions']['uk-ua'] = "Дії";
 
+$text['label-action']['en-us'] = "Action";
+$text['label-action']['en-gb'] = "Action";
+$text['label-action']['ar-eg'] = "الأفعال";
+$text['label-action']['de-at'] = "Aktionen"; //copied from de-de
+$text['label-action']['de-ch'] = "Aktionen"; //copied from de-de
+$text['label-action']['de-de'] = "Aktionen";
+$text['label-action']['el-gr'] = "Ενέργειες";
+$text['label-action']['es-cl'] = "Acción";
+$text['label-action']['es-mx'] = "Acción"; //copied from es-cl
+$text['label-action']['fr-ca'] = "Action"; //copied from fr-fr
+$text['label-action']['fr-fr'] = "Action";
+$text['label-action']['he-il'] = "פעולות";
+$text['label-action']['it-it'] = "Azioni";
+$text['label-action']['nl-nl'] = "";
+$text['label-action']['pl-pl'] = "Operacje (gdzie przesłać rozmowę).";
+$text['label-action']['pt-br'] = "Açõe"; //copied from pt-pt
+$text['label-action']['pt-pt'] = "Açõe";
+$text['label-action']['ro-ro'] = "";
+$text['label-action']['ru-ru'] = "Действия";
+$text['label-action']['sv-se'] = "Åtgärder";
+$text['label-action']['uk-ua'] = "Дії";
+
 $text['label-context']['en-us'] = "Context";
 $text['label-context']['en-gb'] = "Context";
 $text['label-context']['ar-eg'] = "";
@@ -4154,6 +4199,29 @@ $text['button-cdr']['ru-ru'] = "";
 $text['button-cdr']['sv-se'] = "";
 $text['button-cdr']['uk-ua'] = "";
 
+$text['button-settings']['en-us'] = "Settings";
+$text['button-settings']['en-gb'] = "Settings";
+$text['button-settings']['ar-eg'] = "Global";
+$text['button-settings']['de-at'] = "Einstellungen"; //copied from de-de
+$text['button-settings']['de-ch'] = "Global"; //copied from de-de
+$text['button-settings']['de-de'] = "Einstellungen";
+$text['button-settings']['el-gr'] = "Global";
+$text['button-settings']['es-cl'] = "Global";
+$text['button-settings']['es-mx'] = "Global"; //copied from es-cl
+$text['button-settings']['fr-ca'] = "Global"; //copied from fr-fr
+$text['button-settings']['fr-fr'] = "Configuration";
+$text['button-settings']['he-il'] = "Global";
+$text['button-settings']['it-it'] = "Parametri";
+$text['button-settings']['nl-nl'] = "Instellingen";
+$text['button-settings']['pl-pl'] = "Ustawienia";
+$text['button-settings']['pt-br'] = "Definições"; //copied from pt-pt
+$text['button-settings']['pt-pt'] = "Definições";
+$text['button-settings']['ro-ro'] = "Global";
+$text['button-settings']['ru-ru'] = "Конфигурация";
+$text['button-settings']['sv-se'] = "Inställningar";
+$text['button-settings']['uk-ua'] = "Налаштування";
+$text['button-settings']['tr-tr'] = "Global";
+
 $text['description-greeting']['en-us'] = "Select the desired Greeting.";
 $text['description-greeting']['en-gb'] = "Select the desired Greeting.";
 $text['description-greeting']['ar-eg'] = "";
@@ -4403,4 +4471,165 @@ $text['title-login']['sv-se'] = "Logga In";
 $text['title-login']['uk-ua'] = "Логін";
 $text['title-login']['tr-tr'] = "Giriş Yap";
 
+$text['option-expanded']['en-us'] = "Expanded";
+$text['option-expanded']['en-gb'] = "Expanded";
+$text['option-expanded']['ar-eg'] = "Expanded";
+$text['option-expanded']['de-at'] = "Expanded";
+$text['option-expanded']['de-ch'] = "Expanded";
+$text['option-expanded']['de-de'] = "Expanded";
+$text['option-expanded']['el-gr'] = "Expanded";
+$text['option-expanded']['es-cl'] = "Expanded";
+$text['option-expanded']['es-mx'] = "Expanded";
+$text['option-expanded']['fr-ca'] = "Expanded";
+$text['option-expanded']['fr-fr'] = "Expanded";
+$text['option-expanded']['he-il'] = "Expanded";
+$text['option-expanded']['it-it'] = "Expanded";
+$text['option-expanded']['nl-nl'] = "Expanded";
+$text['option-expanded']['pl-pl'] = "Expanded";
+$text['option-expanded']['pt-br'] = "Expanded";
+$text['option-expanded']['pt-pt'] = "Expanded";
+$text['option-expanded']['ro-ro'] = "Expanded";
+$text['option-expanded']['ru-ru'] = "Expanded";
+$text['option-expanded']['sv-se'] = "Expanded";
+$text['option-expanded']['uk-ua'] = "Expanded";
+$text['option-expanded']['tr-tr'] = "Expanded";
+
+$text['option-contracted']['en-us'] = "Contracted";
+$text['option-contracted']['en-gb'] = "Contracted";
+$text['option-contracted']['ar-eg'] = "Contracted";
+$text['option-contracted']['de-at'] = "Contracted";
+$text['option-contracted']['de-ch'] = "Contracted";
+$text['option-contracted']['de-de'] = "Contracted";
+$text['option-contracted']['el-gr'] = "Contracted";
+$text['option-contracted']['es-cl'] = "Contracted";
+$text['option-contracted']['es-mx'] = "Contracted";
+$text['option-contracted']['fr-ca'] = "Contracted";
+$text['option-contracted']['fr-fr'] = "Contracted";
+$text['option-contracted']['he-il'] = "Contracted";
+$text['option-contracted']['it-it'] = "Contracted";
+$text['option-contracted']['nl-nl'] = "Contracted";
+$text['option-contracted']['pl-pl'] = "Contracted";
+$text['option-contracted']['pt-br'] = "Contracted";
+$text['option-contracted']['pt-pt'] = "Contracted";
+$text['option-contracted']['ro-ro'] = "Contracted";
+$text['option-contracted']['ru-ru'] = "Contracted";
+$text['option-contracted']['sv-se'] = "Contracted";
+$text['option-contracted']['uk-ua'] = "Contracted";
+$text['option-contracted']['tr-tr'] = "Contracted";
+
+$text['option-hidden']['en-us'] = "Hidden";
+$text['option-hidden']['en-gb'] = "Hidden";
+$text['option-hidden']['ar-eg'] = "Hidden";
+$text['option-hidden']['de-at'] = "Hidden";
+$text['option-hidden']['de-ch'] = "Hidden";
+$text['option-hidden']['de-de'] = "Hidden";
+$text['option-hidden']['el-gr'] = "Hidden";
+$text['option-hidden']['es-cl'] = "Hidden";
+$text['option-hidden']['es-mx'] = "Hidden";
+$text['option-hidden']['fr-ca'] = "Hidden";
+$text['option-hidden']['fr-fr'] = "Hidden";
+$text['option-hidden']['he-il'] = "Hidden";
+$text['option-hidden']['it-it'] = "Hidden";
+$text['option-hidden']['nl-nl'] = "Hidden";
+$text['option-hidden']['pl-pl'] = "Hidden";
+$text['option-hidden']['pt-br'] = "Hidden";
+$text['option-hidden']['pt-pt'] = "Hidden";
+$text['option-hidden']['ro-ro'] = "Hidden";
+$text['option-hidden']['ru-ru'] = "Hidden";
+$text['option-hidden']['sv-se'] = "Hidden";
+$text['option-hidden']['uk-ua'] = "Hidden";
+$text['option-hidden']['tr-tr'] = "Hidden";
+
+$text['option-hover']['en-us'] = "Hover";
+$text['option-hover']['en-gb'] = "Hover";
+$text['option-hover']['ar-eg'] = "Hover";
+$text['option-hover']['de-at'] = "Hover";
+$text['option-hover']['de-ch'] = "Hover";
+$text['option-hover']['de-de'] = "Hover";
+$text['option-hover']['el-gr'] = "Hover";
+$text['option-hover']['es-cl'] = "Hover";
+$text['option-hover']['es-mx'] = "Hover";
+$text['option-hover']['fr-ca'] = "Hover";
+$text['option-hover']['fr-fr'] = "Hover";
+$text['option-hover']['he-il'] = "Hover";
+$text['option-hover']['it-it'] = "Hover";
+$text['option-hover']['nl-nl'] = "Hover";
+$text['option-hover']['pl-pl'] = "Hover";
+$text['option-hover']['pt-br'] = "Hover";
+$text['option-hover']['pt-pt'] = "Hover";
+$text['option-hover']['ro-ro'] = "Hover";
+$text['option-hover']['ru-ru'] = "Hover";
+$text['option-hover']['sv-se'] = "Hover";
+$text['option-hover']['uk-ua'] = "Hover";
+$text['option-hover']['tr-tr'] = "Hover";
+
+$text['option-click']['en-us'] = "Click";
+$text['option-click']['en-gb'] = "Click";
+$text['option-click']['ar-eg'] = "Click";
+$text['option-click']['de-at'] = "Click";
+$text['option-click']['de-ch'] = "Click";
+$text['option-click']['de-de'] = "Click";
+$text['option-click']['el-gr'] = "Click";
+$text['option-click']['es-cl'] = "Click";
+$text['option-click']['es-mx'] = "Click";
+$text['option-click']['fr-ca'] = "Click";
+$text['option-click']['fr-fr'] = "Click";
+$text['option-click']['he-il'] = "Click";
+$text['option-click']['it-it'] = "Click";
+$text['option-click']['nl-nl'] = "Click";
+$text['option-click']['pl-pl'] = "Click";
+$text['option-click']['pt-br'] = "Click";
+$text['option-click']['pt-pt'] = "Click";
+$text['option-click']['ro-ro'] = "Click";
+$text['option-click']['ru-ru'] = "Click";
+$text['option-click']['sv-se'] = "Click";
+$text['option-click']['uk-ua'] = "Click";
+$text['option-click']['tr-tr'] = "Click";
+
+$text['option-shrink']['en-us'] = "Shrink";
+$text['option-shrink']['en-gb'] = "Shrink";
+$text['option-shrink']['ar-eg'] = "Shrink";
+$text['option-shrink']['de-at'] = "Shrink";
+$text['option-shrink']['de-ch'] = "Shrink";
+$text['option-shrink']['de-de'] = "Shrink";
+$text['option-shrink']['el-gr'] = "Shrink";
+$text['option-shrink']['es-cl'] = "Shrink";
+$text['option-shrink']['es-mx'] = "Shrink";
+$text['option-shrink']['fr-ca'] = "Shrink";
+$text['option-shrink']['fr-fr'] = "Shrink";
+$text['option-shrink']['he-il'] = "Shrink";
+$text['option-shrink']['it-it'] = "Shrink";
+$text['option-shrink']['nl-nl'] = "Shrink";
+$text['option-shrink']['pl-pl'] = "Shrink";
+$text['option-shrink']['pt-br'] = "Shrink";
+$text['option-shrink']['pt-pt'] = "Shrink";
+$text['option-shrink']['ro-ro'] = "Shrink";
+$text['option-shrink']['ru-ru'] = "Shrink";
+$text['option-shrink']['sv-se'] = "Shrink";
+$text['option-shrink']['uk-ua'] = "Shrink";
+$text['option-shrink']['tr-tr'] = "Shrink";
+
+$text['option-fixed']['en-us'] = "Fixed";
+$text['option-fixed']['en-gb'] = "Fixed";
+$text['option-fixed']['ar-eg'] = "Fixed";
+$text['option-fixed']['de-at'] = "Fixed";
+$text['option-fixed']['de-ch'] = "Fixed";
+$text['option-fixed']['de-de'] = "Fixed";
+$text['option-fixed']['el-gr'] = "Fixed";
+$text['option-fixed']['es-cl'] = "Fixed";
+$text['option-fixed']['es-mx'] = "Fixed";
+$text['option-fixed']['fr-ca'] = "Fixed";
+$text['option-fixed']['fr-fr'] = "Fixed";
+$text['option-fixed']['he-il'] = "Fixed";
+$text['option-fixed']['it-it'] = "Fixed";
+$text['option-fixed']['nl-nl'] = "Fixed";
+$text['option-fixed']['pl-pl'] = "Fixed";
+$text['option-fixed']['pt-br'] = "Fixed";
+$text['option-fixed']['pt-pt'] = "Fixed";
+$text['option-fixed']['ro-ro'] = "Fixed";
+$text['option-fixed']['ru-ru'] = "Fixed";
+$text['option-fixed']['sv-se'] = "Fixed";
+$text['option-fixed']['uk-ua'] = "Fixed";
+$text['option-fixed']['tr-tr'] = "Fixed";
+
 ?>

BIN
resources/captcha/fonts/hanshand.ttf


+ 24 - 27
resources/check_auth.php

@@ -23,6 +23,7 @@
 	Contributor(s):
 	Mark J Crane <[email protected]>
 */
+
 //includes
 	require_once "resources/require.php";
 
@@ -157,6 +158,11 @@
 				unset($sql, $parameters, $result, $row);
 			}
 
+		//get the domains
+			if (file_exists($_SERVER["PROJECT_ROOT"]."/app/domains/app_config.php") && !is_cli()){
+				require_once "app/domains/resources/domains.php";
+			}
+
 		//get the user settings
 			$sql = "select * from v_user_settings ";
 			$sql .= "where domain_uuid = :domain_uuid ";
@@ -197,13 +203,8 @@
 
 		//get the extensions that are assigned to this user
 			if (file_exists($_SERVER["PROJECT_ROOT"]."/app/extensions/app_config.php")) {
-				if (
-					isset($_SESSION["user"]) &&
-					is_uuid($_SESSION["user_uuid"]) &&
-					is_uuid($_SESSION["domain_uuid"]) &&
-					!isset($_SESSION['user']['extension'])
-					) {
-					//get the user extension list
+				if (isset($_SESSION["user"]) && is_uuid($_SESSION["user_uuid"]) && is_uuid($_SESSION["domain_uuid"]) && !isset($_SESSION['user']['extension'])) {
+						//get the user extension list
 						$_SESSION['user']['extension'] = null;
 						$sql = "select ";
 						$sql .= "e.extension_uuid, ";
@@ -230,22 +231,24 @@
 						if (is_array($result) && @sizeof($result) != 0) {
 							foreach($result as $x => $row) {
 								//set the destination
-									$destination = $row['extension'];
-									if (strlen($row['number_alias']) > 0) {
-										$destination = $row['number_alias'];
-									}
+								$destination = $row['extension'];
+								if (strlen($row['number_alias']) > 0) {
+									$destination = $row['number_alias'];
+								}
+
 								//build the user array
-									$_SESSION['user']['extension'][$x]['user'] = $row['extension'];
-									$_SESSION['user']['extension'][$x]['number_alias'] = $row['number_alias'];
-									$_SESSION['user']['extension'][$x]['destination'] = $destination;
-									$_SESSION['user']['extension'][$x]['extension_uuid'] = $row['extension_uuid'];
-									$_SESSION['user']['extension'][$x]['outbound_caller_id_name'] = $row['outbound_caller_id_name'];
-									$_SESSION['user']['extension'][$x]['outbound_caller_id_number'] = $row['outbound_caller_id_number'];
-									$_SESSION['user']['extension'][$x]['user_context'] = $row['user_context'];
-									$_SESSION['user']['extension'][$x]['description'] = $row['description'];
+								$_SESSION['user']['extension'][$x]['user'] = $row['extension'];
+								$_SESSION['user']['extension'][$x]['number_alias'] = $row['number_alias'];
+								$_SESSION['user']['extension'][$x]['destination'] = $destination;
+								$_SESSION['user']['extension'][$x]['extension_uuid'] = $row['extension_uuid'];
+								$_SESSION['user']['extension'][$x]['outbound_caller_id_name'] = $row['outbound_caller_id_name'];
+								$_SESSION['user']['extension'][$x]['outbound_caller_id_number'] = $row['outbound_caller_id_number'];
+								$_SESSION['user']['extension'][$x]['user_context'] = $row['user_context'];
+								$_SESSION['user']['extension'][$x]['description'] = $row['description'];
+
 								//set the user context
-									$_SESSION['user']['user_context'] = $row["user_context"];
-									$_SESSION['user_context'] = $row["user_context"];
+								$_SESSION['user']['user_context'] = $row["user_context"];
+								$_SESSION['user_context'] = $row["user_context"];
 							}
 						}
 						unset($sql, $parameters, $result, $row);
@@ -260,12 +263,6 @@
 					exit();
 				}
 			}
-
-		//get the domains
-			if (file_exists($_SERVER["PROJECT_ROOT"]."/app/domains/app_config.php") && !is_cli()){
-				require_once "app/domains/resources/domains.php";
-			}
-
 	}
 
 //set the time zone

+ 605 - 36
resources/classes/database.php

@@ -66,7 +66,7 @@ include "root.php";
 					$this->domain_uuid = $_SESSION['domain_uuid'];
 				}
 			}
-		
+
 			/**
 			 * Called when there are no references to a particular object
 			 * unset the variables used in the class
@@ -76,7 +76,7 @@ include "root.php";
 					unset($this->$key);
 				}
 			}
-		
+
 			/**
 			 * Connect to the database
 			 */
@@ -683,7 +683,10 @@ include "root.php";
 					unset($sql);
 			}
 
-			public function delete($delete_array) {
+			public function delete($array) {
+
+				//return the array
+					if (!is_array($array)) { echo "not an array"; return false; }
 
 				//connect to the database if needed
 					if (!$this->db) {
@@ -710,38 +713,178 @@ include "root.php";
 					//echo "</pre>\n";
 					//exit;
 
+				//set the message id
+					$m = 0;
+
+				//loop through the array
+					$checked = false;
+					if (is_array($array)) {
+
+						$x = 0;
+						foreach ($array as $parent_name => $tables) {
+							if (is_array($tables)) {
+								foreach ($tables as $id => $row) {
+
+									//prepare the variables
+										$parent_name = preg_replace('#[^a-zA-Z0-9_\-]#', '', $parent_name);
+										$parent_key_name = $this->singular($parent_name)."_uuid";
+
+									//build the delete array
+										if ($row['checked'] == 'true') {
+											//set checked to true
+											$checked = true;
+
+											//delete the child data
+											if (isset($row[$parent_key_name])) {
+												$new_array[$parent_name][$x][$parent_key_name] = $row[$parent_key_name];
+											}
+
+											//remove the row from the main array
+											unset($array[$parent_name][$x]);
+										}
+
+									//loop through the fields
+										foreach($row as $field_name => $field_value) {
+
+											//find the child tables
+											$y = 0;
+											if (is_array($field_value)) {
+												//prepare the variables
+												$child_name = preg_replace('#[^a-zA-Z0-9_\-]#', '', $field_name);
+												$child_key_name = $this->singular($child_name)."_uuid";
+
+												//loop through the child rows
+												foreach ($field_value as $sub_row) {
+
+													//build the delete array
+													if ($row['checked'] == 'true') {
+														//set checked to true
+														$checked = true;
+
+														//delete the child data
+														$new_array[$child_name][][$child_key_name] = $sub_row[$child_key_name];
+
+														//remove the row from the main array
+														unset($array[$parent_name][$x][$child_name][$y]);
+													}
+
+													//increment the value
+													$y++;
+												}
+											}
+										}
+
+									//increment the value
+										$x++;
+
+								}
+							}
+						}
+					}
+
+				//if not checked then copy the array to delete array
+					if (!$checked) {
+						$new_array = $array;
+					}
+
 				//get the current data
-					if (is_array($delete_array)) {
-						foreach($delete_array as $table_name => $rows) {
+					if (is_array($new_array) && count($new_array) > 0) {
+						//build an array of tables, fields, and values
+						foreach($new_array as $table_name => $rows) {
 							foreach($rows as $row) {
-								$i = 0;
+								foreach($row as $field_name => $field_value) {
+									$keys[$table_name][$field_name][] = $field_value;
+								}
+							}
+						}
+
+						//use the array to get a copy of the parent data before deleting it
+						foreach($new_array as $table_name => $rows) {
+							foreach($rows as $row) {
+								$table_name = preg_replace('#[^a-zA-Z0-9_\-]#', '', $table_name);
 								$sql = "select * from ".$table_prefix.$table_name." ";
+								$i = 0;
 								foreach($row as $field_name => $field_value) {
 									if ($i == 0) { $sql .= "where "; } else { $sql .= "and "; }
-									$sql .= $field_name." = :".$field_name." ";
-									$parameters[$field_name] = $field_value;
-									$i++;
-								}
-								if (strlen($field_value) > 0) {
-									$results = $this->execute($sql, $parameters, 'all');
-									if (is_array($results)) {
-										$array[$table_name] = $results;
+									$sql .= $field_name." in ( ";
+									$i = 0;
+									foreach($keys[$table_name][$field_name] as $field_value) {
+										$field_name = preg_replace('#[^a-zA-Z0-9_\-]#', '', $field_name);
+										if ($i > 0) { $sql .= " ,"; }
+										$sql .= " :".$field_name."_".$i." ";
+										$i++;
+									}
+									$sql .= ") ";
+									$i = 0;
+									foreach($keys[$table_name][$field_name] as $field_value) {
+										$parameters[$field_name.'_'.$i] = $field_value;
+										$i++;
 									}
 								}
+							}
+							if (strlen($field_value) > 0) {
+								$results = $this->execute($sql, $parameters, 'all');
 								unset($parameters);
+								if (is_array($results)) {
+									$old_array[$table_name] = $results;
+								}
 							}
 						}
-					}
 
-				//save the array
-					$old_array = &$array;
+						//get relations array
+						$relations = $this->get_relations($parent_name);
+
+						//add child data to the old array
+						foreach($old_array as $parent_name => $rows) {
+							//get relations array
+							$relations = $this->get_relations($parent_name);
+
+							//loop through the rows
+							$x = 0;
+							foreach($rows as $row) {
+								if (is_array($relations)) {
+									foreach ($relations as $relation) {
+										if ($relation['key']['action']['delete'] == 'cascade') {
+											//set the child table
+											$child_table = $relation['table'];
+
+											//remove the v_ prefix
+											if (substr($child_table, 0, 2) == "v_") {
+												$child_table = substr($child_table, 2);
+											}
+
+											//get the child data
+											$sql = "select * from ".$table_prefix.$child_table." ";
+											$sql .= "where ".$relation['field']." = :".$relation['field'];
+											$parameters[$relation['field']] = $row[$relation['field']];
+											$results = $this->execute($sql, $parameters, 'all');
+											unset($parameters);
+											if (is_array($results) && $parent_name !== $child_table) {
+												$old_array[$parent_name][$x][$child_table] = $results;
+											}
+
+											//delete the child data
+											if (isset($row[$relation['field']]) && strlen($row[$relation['field']]) > 0) {
+												$sql = "delete from ".$table_prefix.$child_table." ";
+												$sql .= "where ".$relation['field']." = :".$relation['field'];
+												$parameters[$relation['field']] = $row[$relation['field']];
+//												$this->execute($sql, $parameters);
+											}
+											unset($parameters);
+										}
+									}
+								}
+								$x++;
+							}
+						}
+					}
 
 				//start the atomic transaction
 					$this->db->beginTransaction();
 
 				//delete the current data
-					if (is_array($delete_array)) {
-						foreach($delete_array as $table_name => $rows) {
+					if (is_array($new_array)) {
+						foreach($new_array as $table_name => $rows) {
 							//echo "table: ".$table_name."\n";
 							foreach($rows as $row) {
 								if (permission_exists($this->singular($table_name).'_delete')) {
@@ -1143,6 +1286,339 @@ include "root.php";
 				return $this;
 			}
 
+			public function copy($array) {
+
+				//return the array
+					if (!is_array($array)) { echo "not an array"; return false; }
+
+				//set the table prefix
+					$table_prefix = 'v_';
+
+				//set the message id
+					$m = 0;
+
+				//loop through the array
+					if (is_array($array)) {
+						$x = 0;
+						foreach ($array as $parent_name => $tables) {
+							if (is_array($tables)) {
+								foreach ($tables as $id => $row) {
+
+									//prepare the variables
+										$parent_name = preg_replace('#[^a-zA-Z0-9_\-]#', '', $parent_name);
+										$parent_key_name = $this->singular($parent_name)."_uuid";
+
+									//build the copy array
+										if ($row['checked'] == 'true') {
+											//set checked to true
+											$checked = true;
+
+											//copy the child data
+											if (is_uuid($row[$parent_key_name])) {
+												$copy_array[$parent_name][$x][$parent_key_name] = $row[$parent_key_name];
+											}
+
+											//remove the row from the main array
+											unset($array[$parent_name][$x]);
+
+											//loop through the fields
+
+											foreach($row as $field_name => $field_value) {
+												//find the child tables
+												if (is_array($field_value)) {
+
+													//prepare the variables
+													$child_name = preg_replace('#[^a-zA-Z0-9_\-]#', '', $field_name);
+													$child_key_name = $this->singular($child_name)."_uuid";
+
+													//loop through the child rows
+													$y = 0;
+													foreach ($field_value as $sub_row) {
+
+														//delete the child data
+														$copy_array[$child_name][][$child_key_name] = $sub_row[$child_key_name];
+
+														//remove the row from the main array
+														unset($array[$parent_name][$x][$child_name][$y]);
+
+														//increment the value
+														$y++;
+													}
+												}
+											}
+										}
+
+									//increment the value
+										$x++;
+
+								}
+							}
+						}
+					}
+
+				//get the current data
+					if (is_array($copy_array) && count($copy_array) > 0) {
+
+						//build an array of tables, fields, and values
+						foreach($copy_array as $table_name => $rows) {
+							foreach($rows as $row) {
+								foreach($row as $field_name => $field_value) {
+									$keys[$table_name][$field_name][] = $field_value;
+								}
+							}
+						}
+
+						//unset the array
+						unset($array);
+
+						//use the array to get a copy of the paent data before deleting it
+						foreach($copy_array as $table_name => $rows) {
+							foreach($rows as $row) {
+								$table_name = preg_replace('#[^a-zA-Z0-9_\-]#', '', $table_name);
+								$sql = "select * from ".$table_prefix.$table_name." ";
+								$i = 0;
+								foreach($row as $field_name => $field_value) {
+									if ($i == 0) { $sql .= "where "; } else { $sql .= "and "; }
+									$sql .= $field_name." in ( ";
+									$i = 0;
+									foreach($keys[$table_name][$field_name] as $field_value) {
+										$field_name = preg_replace('#[^a-zA-Z0-9_\-]#', '', $field_name);
+										if ($i > 0) { $sql .= " ,"; }
+										$sql .= " :".$field_name."_".$i." ";
+										$i++;
+									}
+									$sql .= ") ";
+									$i = 0;
+									foreach($keys[$table_name][$field_name] as $field_value) {
+										$parameters[$field_name.'_'.$i] = $field_value;
+										$i++;
+									}
+								}
+							}
+
+							$results = $this->execute($sql, $parameters, 'all');
+							unset($parameters);
+							if (is_array($results)) {
+								$array[$table_name] = $results;
+							}
+						}
+
+						//add child data to the old array
+						foreach($copy_array as $parent_name => $rows) {
+							//get relations array
+							$relations = $this->get_relations($parent_name);
+
+							//loop through the rows
+							$x = 0;
+							foreach($rows as $row) {
+								if (is_array($relations)) {
+									foreach ($relations as $relation) {
+										//set the child table
+										$child_table = $relation['table'];
+
+										//remove the v_ prefix
+										if (substr($child_table, 0, 2) == "v_") {
+											$child_table = substr($child_table, 2);
+										}
+
+										//get the child data
+										$sql = "select * from ".$table_prefix.$child_table." ";
+										$sql .= "where ".$relation['field']." = :".$relation['field'];
+										$parameters[$relation['field']] = $row[$relation['field']];
+										$results = $this->execute($sql, $parameters, 'all');
+										unset($parameters);
+										if (is_array($results)) {
+											$array[$parent_name][$x][$child_table] = $results;
+										}
+									}
+								}
+								$x++;
+							}
+						}
+					}
+
+				//update the parent and child keys
+					$checked = false;
+					if (is_array($array)) {
+						$x = 0;
+						foreach ($array as $parent_name => $tables) {
+							if (is_array($tables)) {
+								foreach ($tables as $id => $row) {
+
+									//prepare the variables
+										$parent_name = preg_replace('#[^a-zA-Z0-9_\-]#', '', $parent_name);
+										$parent_key_name = $this->singular($parent_name)."_uuid";
+										$parent_key_value = uuid();
+
+									//update the parent key id
+										$array[$parent_name][$x][$parent_key_name] = $parent_key_value;
+
+									//add copy to the description 
+										if (isset($array[$parent_name][$x][$this->singular($parent_name).'_description'])) {
+											$array[$parent_name][$x][$this->singular($parent_name).'_description'] = '(Copy) '.$array[$parent_name][$x][$this->singular($parent_name).'_description'];
+										}
+
+									//loop through the fields
+										foreach($row as $field_name => $field_value) {
+
+											//find the child tables
+											$y = 0;
+											if (is_array($field_value)) {
+												//prepare the variables
+												$child_name = preg_replace('#[^a-zA-Z0-9_\-]#', '', $field_name);
+												$child_key_name = $this->singular($child_name)."_uuid";
+
+												//loop through the child rows
+												foreach ($field_value as $sub_row) {
+													//update the parent key id
+													$array[$parent_name][$x][$child_name][$y][$parent_key_name] = $parent_key_value;
+
+													//udpate the child key id
+													$array[$parent_name][$x][$child_name][$y][$child_key_name] = uuid();
+
+													//increment the value
+													$y++;
+												}
+											}
+										}
+
+									//increment the value
+										$x++;
+
+								}
+							}
+						}
+					}
+
+				//save the copy of the data
+					if (is_array($array) && count($array) > 0) {
+						$this->save($array);
+						unset($array);
+					}
+
+			} //end function copy
+
+
+			public function toggle($array) {
+
+				//return the array
+					if (!is_array($array)) { echo "not an array"; return false; }
+
+				//set the message id
+					$m = 0;
+
+				//loop through the array
+					if (is_array($array)) {
+						$x = 0;
+						foreach ($array as $parent_name => $tables) {
+							if (is_array($tables)) {
+								foreach ($tables as $id => $row) {
+
+									//prepare the variables
+										$parent_name = preg_replace('#[^a-zA-Z0-9_\-]#', '', $parent_name);
+										$parent_key_name = $this->singular($parent_name)."_uuid";
+
+									//build the toggle array
+										if ($row['checked'] == 'true') {
+											//toggle the field value
+											//$toggle_array[$parent_name][$x][$parent_key_name] = $row[$parent_key_name];
+											$toggle_array[$parent_name][$x] = $row;
+
+											//remove the row from the main array
+											unset($array[$parent_name][$x]);
+										}
+
+									//loop through the fields
+										foreach($row as $field_name => $field_value) {
+
+											//find the child tables
+											$y = 0;
+											if (is_array($field_value)) {
+												//prepare the variables
+												$child_name = preg_replace('#[^a-zA-Z0-9_\-]#', '', $field_name);
+												$child_key_name = $this->singular($child_name)."_uuid";
+
+												//loop through the child rows
+												foreach ($field_value as $sub_row) {
+
+													//build the delete array
+													if ($action == 'delete' && $sub_row['checked'] == 'true') {
+														//delete the child data
+														$delete_array[$child_name][$y][$child_key_name] = $sub_row[$child_key_name];
+
+														//remove the row from the main array
+														unset($array[$parent_name][$x][$child_name][$y]);
+													}
+
+													//increment the value
+													$y++;
+												}
+											}
+										}
+
+									//increment the value
+										$x++;
+
+								}
+							}
+						}
+					}
+
+					//unset the original array
+					unset($array);
+
+					//get the $apps array from the installed apps from the core and mod directories
+					if (!is_array($_SESSION['apps'])) {
+						$this->get_apps();
+					}
+
+					//search through all fields to see if toggle field exists
+					if (is_array($_SESSION['apps'])) {
+						foreach ($_SESSION['apps'] as $x => $app) {
+							if (is_array($app['db'])) {
+								foreach ($app['db'] as $y => $row) {
+									if (is_array($row['table']['name'])) {
+										$table_name = $row['table']['name']['text'];
+									}
+									else {
+										$table_name = $row['table']['name'];
+									}
+									if ($table_name === 'v_'.$parent_name) {
+										if (is_array($row['fields'])) {
+											foreach ($row['fields'] as $field) {
+												if (isset($field['toggle'])) {
+													$toggle_field = $field['name'];
+													$toggle_values = $field['toggle'];
+												}
+											}
+										}
+									}
+								}
+							}
+						}
+					}
+
+					//get the current values from the database
+					foreach ($toggle_array as $table_name => $table) {
+						$x = 0;
+						foreach($table as $row) {
+							$child_name = preg_replace('#[^a-zA-Z0-9_\-]#', '', $table_name);
+							$child_key_name = $this->singular($child_name)."_uuid";
+
+							$array[$table_name][$x][$child_key_name] = $row[$child_key_name];
+							$array[$table_name][$x][$toggle_field] = ($row[$toggle_field] === $toggle_values[0]) ? $toggle_values[1] : $toggle_values[0];
+							$x++;
+						}
+					}
+					unset($toggle_array);
+
+					//save the array
+					$this->save($array);
+					//view_array($this->message);
+
+			} //end function toggle
+
+
 			public function save($array) {
 
 				//return the array
@@ -1156,18 +1632,18 @@ include "root.php";
 						$this->app_name = $this->name;
 					}
 
-				//normalize the array structure
-					//$new_array = $this->normalize_array($array, $this->name);
-					//unset($array);
-					$new_array = $array;
+				//debug sql
+					$this->debug["sql"] = true;
 
 				//connect to the database if needed
 					if (!$this->db) {
 						$this->connect();
 					}
 
-				//debug sql
-					$this->debug["sql"] = true;
+				//normalize the array structure
+					//$new_array = $this->normalize_array($array, $this->name);
+					//unset($array);
+					$new_array = $array;
 
 				//start the atomic transaction
 					$this->db->beginTransaction();
@@ -1263,9 +1739,6 @@ include "root.php";
 											if (!$parent_key_exists) {
 												$sql .= $parent_key_name.", ";
 											}
-											//foreach ($parent_field_names as $field_name) {
-											//		$sql .= check_str($field_name).", ";
-											//}
 											if (is_array($array)) {
 												foreach ($array as $array_key => $array_value) {
 													if (!is_array($array_value)) {
@@ -1289,8 +1762,15 @@ include "root.php";
 														elseif ($array_value === "now()") {
 															$sql .= "now(), ";
 														}
+														elseif ($array_value === "user_uuid()") {
+															$sql .= ':'.$array_key.", ";
+															$params[$array_key] = $_SESSION['user_uuid'];
+														}
+														elseif ($array_value === "remote_address()") {
+															$sql .= ':'.$array_key.", ";
+															$params[$array_key] = $_SERVER['REMOTE_ADDR'];
+														}
 														else {
-															//$sql .= "'".check_str($array_value)."', ";
 															$sql .= ':'.$array_key.", ";
 															$params[$array_key] = trim($array_value);
 														}
@@ -1370,8 +1850,15 @@ include "root.php";
 														elseif ($array_value === "now()") {
 															$sql .= $array_key." = now(), ";
 														}
+														elseif ($array_value === "user_uuid()") {
+															$sql .= $array_key." = :".$array_key.", ";
+															$params[$array_key] = $_SESSION['user_uuid'];
+														}
+														elseif ($array_value === "remote_address()") {
+															$sql .= $array_key." = :".$array_key.", ";
+															$params[$array_key] = $_SERVER['REMOTE_ADDR'];
+														}
 														else {
-															//$sql .= $array_key." = '".check_str($array_value)."', ";
 															$sql .= $array_key." = :".$array_key.", ";
 															$params[$array_key] = trim($array_value);
 														}
@@ -1474,7 +1961,7 @@ include "root.php";
 														$child_field_names = array();
 														if (is_array($row)) {
 															foreach ($row as $k => $v) {
-																if (!is_array($v)) {
+																if (!is_array($v) && $k !== 'checked') {
 																	$child_field_names[] = preg_replace('#[^a-zA-Z0-9_\-]#', '', $k);
 																}
 															}
@@ -1489,6 +1976,7 @@ include "root.php";
 																//get the data
 																	$prep_statement->execute();
 																	$child_array = $prep_statement->fetch(PDO::FETCH_ASSOC);
+
 																//set the action
 																	if (is_array($child_array)) {
 																		$action = "update";
@@ -1496,6 +1984,7 @@ include "root.php";
 																	else {
 																		$action = "add";
 																	}
+
 																//add to the parent array
 																	if (is_array($child_array)) {
 																		$old_array[$schema_name][$schema_id][$key][] = $child_array;
@@ -1521,8 +2010,15 @@ include "root.php";
 																			elseif ($v === "now()") {
 																				$sql .= $k." = now(), ";
 																			}
+																			elseif ($v === "user_uuid()") {
+																				$sql .= $k." = :".$k.", ";
+																				$params[$k] = $_SESSION['user_uuid'];
+																			}
+																			elseif ($v === "remote_address()") {
+																				$sql .= $k." = :".$k.", ";
+																				$params[$k] = $_SERVER['REMOTE_ADDR'];
+																			}
 																			else {
-																				//$sql .= "$k = '".check_str($v)."', ";
 																				$sql .= $k." = :".$k.", ";
 																				$params[$k] = trim($v);
 																			}
@@ -1639,9 +2135,16 @@ include "root.php";
 																		elseif ($v === "now()") {
 																			$sql .= "now(), ";
 																		}
+																		elseif ($v === "user_uuid()") {
+																			$sql .= ':'.$k.", ";
+																			$params[$k] = $_SESSION['user_uuid'];
+																		}
+																		elseif ($v === "remote_address()") {
+																			$sql .= ':'.$k.", ";
+																			$params[$k] = $_SERVER['REMOTE_ADDR'];
+																		}
 																		else {
 																			$k = preg_replace('#[^a-zA-Z0-9_\-]#', '', $k);
-																			//$sql .= "'".check_str($v)."', ";
 																			$sql .= ':'.$k.", ";
 																			$params[$k] = trim($v);
 																		}
@@ -1652,7 +2155,6 @@ include "root.php";
 															$sql = str_replace(", )", ")", $sql);
 															$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 															try {
-																//$this->db->query(check_sql($sql));
 																$prep_statement = $this->db->prepare($sql);
 																$prep_statement->execute($params);
 																unset($prep_statement);
@@ -1907,15 +2409,22 @@ include "root.php";
 					if (!is_array($_SESSION['apps'])) {
 						$this->get_apps();
 					}
+
 				//search through all fields to see if domain_uuid exists
 					$apps = $_SESSION['apps'];
 					if (is_array($apps)) {
 						foreach ($apps as $x => &$app) {
 							if (is_array($app['db'])) {
 								foreach ($app['db'] as $y => &$row) {
-									if ($row['table'] == $name) {
+									if (is_array($row['table']['name'])) {
+										$table_name = $row['table']['name']['text'];
+									}
+									else {
+										$table_name = $row['table']['name'];
+									}
+									if ($table_name === 'v_'.$name) {
 										if (is_array($row['fields'])) {
-											foreach ($row['fields'] as $z => $field) {
+											foreach ($row['fields'] as $field) {
 												if ($field['name'] == "domain_uuid") {
 													return true;
 												}
@@ -1926,10 +2435,70 @@ include "root.php";
 							} //is array
 						} //foreach
 					} //is array
+
 				//not found
 					return false;
 			}
 
+			public function get_relations($schema) {
+
+				//remove the v_ prefix
+					if (substr($schema, 0, 2) == "v_") {
+						$schema = substr($schema, 2);
+					}
+
+				//sanitize the values
+					$schema = preg_replace('#[^a-zA-Z0-9_\-]#', '', $schema);
+
+				//get the apps array
+					$config_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/{core,app}/{".$schema.",".$this->singular($schema)."}/app_config.php", GLOB_BRACE);
+					foreach ($config_list as &$config_path) {
+						include($config_path);
+					}
+
+				//search through all fields to find relations
+					if (is_array($apps)) {
+						foreach ($apps as $x => &$app) {
+							foreach ($app['db'] as $y => &$row) {
+								foreach ($row['fields'] as $z => $field) {
+									if ($field['deprecated'] != "true") {
+										if ($field['key']['type'] == "foreign") {
+											if ($row['table']['name'] == "v_".$schema || $field['key']['reference']['table'] == "v_".$schema) {
+												//get the field name
+													if (is_array($field['name'])) {
+														$field_name = trim($field['name']['text']);
+													}
+													else {
+														$field_name = trim($field['name']);
+													}
+												//build the array
+													$array[$i]['table'] = $row['table']['name'];
+													$array[$i]['field'] = $field_name;
+													$array[$i]['key']['type'] = $field['key']['type'];
+													$array[$i]['key']['table'] = $field['key']['reference']['table'];
+													$array[$i]['key']['field'] = $field['key']['reference']['field'];
+													if (isset($field['key']['reference']['action'])) {
+														$array[$i]['key']['action'] = $field['key']['reference']['action'];
+													}
+												//increment the value
+													$i++;
+											}
+										}
+									}
+									unset($field_name);
+								}
+							}
+						}
+					}
+
+				//return the array
+					if (is_array($array)) {
+						return $array;
+					} else {
+						return false;
+					}
+			}
+
 		} //class database
 	} //!class_exists
 

+ 0 - 5
resources/classes/domains.php

@@ -769,11 +769,6 @@ if (!class_exists('domains')) {
 						$domains_processed++;
 				}
 
-			//synchronize the dialplan
-				if (function_exists('save_dialplan_xml')) {
-					save_dialplan_xml();
-				}
-
 			//update config.lua
 				if (file_exists($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/app/scripts/resources/classes/scripts.php')) {
 					$obj = new scripts;

+ 59 - 48
resources/classes/menu.php

@@ -17,7 +17,7 @@
 
 	The Initial Developer of the Original Code is
 	Mark J Crane <[email protected]>
-	Copyright (C) 2010 - 2019
+	Copyright (C) 2010 - 2020
 	All Rights Reserved.
 
 	Contributor(s):
@@ -951,7 +951,7 @@ if (!class_exists('menu')) {
 						$menu_brand_text = ($_SESSION['theme']['menu_brand_text']['text'] != '') ? escape($_SESSION['theme']['menu_brand_text']['text']) : "FusionPBX";
 						switch ($_SESSION['theme']['menu_brand_type']['text']) {
 							case 'text':
-								$html .= "			<a class='navbar-brand-text'  href='".PROJECT_PATH."/'>".$menu_brand_text."</a>\n";
+								$html .= "			<a class='navbar-brand-text' href='".PROJECT_PATH."/'>".$menu_brand_text."</a>\n";
 								break;
 							case 'image_text':
 								$menu_brand_image = ($_SESSION['theme']['menu_brand_image']['text'] != '') ? escape($_SESSION['theme']['menu_brand_image']['text']) : PROJECT_PATH."/themes/default/images/logo.png";
@@ -1023,6 +1023,7 @@ if (!class_exists('menu')) {
 									$mod_a_2 = '#';
 								}
 								$mod_a_3 = ($menu_sub['menu_item_category'] == 'external') ? "target='_blank' " : null;
+								$menu_sub_icon = null;
 								if ($_SESSION['theme']['menu_sub_icons']['boolean'] != 'false') {
 									if ($menu_sub['menu_item_icon'] != '' && substr_count($menu_sub['menu_item_icon'], 'fa-') > 0) {
 										$menu_sub_icon = "<span class='fas ".escape($menu_sub['menu_item_icon'])."'></span>";
@@ -1077,56 +1078,54 @@ if (!class_exists('menu')) {
 		public function menu_vertical($menu_array) {
 
 			//menu brand image and/or text
+				$html .= "	<div id='menu_side_control_container'>\n";
+				$html .= "		<div class='menu_side_control_state' style='float: right; ".($_SESSION['theme']['menu_side_state']['text'] != 'expanded' ? 'display: none' : null)."'>\n";
+				if ($_SESSION['theme']['menu_brand_type']['text'] != 'none') {
+					$html .= "		<a class='menu_side_item_main menu_side_contract' onclick='menu_side_contract();' style='padding: 8px 15px !important; ".($_SESSION['theme']['menu_side_state']['text'] != 'expanded' ? "display: none;" : null)."'><i class='fas fa-bars fa-fw'></i></a>\n";
+				}
+				if ($_SESSION['theme']['menu_side_pin']['boolean'] == 'true') {
+					$html .= "		<a class='menu_side_item_main' id='menu_side_state_set_expanded' onclick=\"menu_side_state_set('expanded');\" oncontextmenu=\"menu_side_state_set('delete'); return false;\" style='padding: 8px 14px 8px 16px !important; ".($_SESSION['theme']['menu_side_state']['text'] == 'expanded' ? 'display: none' : null)."' title=\"".$this->text['theme-label-pin_menu']."\"><i class='fas fa-toggle-off fa-sm fa-fw'></i></a>\n";
+					$html .= "		<a class='menu_side_item_main' id='menu_side_state_set_contracted' onclick=\"menu_side_state_set('contracted');\" oncontextmenu=\"menu_side_state_set('delete'); return false;\" style='padding: 8px 14px 8px 16px !important; ".($_SESSION['theme']['menu_side_state']['text'] != 'expanded' ? 'display: none' : null)."' title=\"".$this->text['theme-label-unpin_menu']."\"><i class='fas fa-toggle-on fa-sm fa-fw'></i></a>\n";
+				}
+				$html .= "		</div>\n";
 				if ($_SESSION['theme']['menu_brand_type']['text'] == 'none') {
-					$html = "	<div style='height: 75px;'>\n";
-					$html .= 		"<a class='menu_side_item_main menu_side_contract' onclick='menu_side_contract();' style='display: none;'><i class='fas fa-chevron-left' style='z-index: 99800; padding-left: 3px;'></i></a>";
-					$html .= 		"<a class='menu_side_item_main menu_side_expand' onclick='menu_side_expand();'><i class='fas fa-bars' style='z-index: 99800; padding-left: 3px;'></i></a>";
-					$html .= 	"</div>\n";
+					$html .= "		<a class='menu_side_item_main menu_side_contract' onclick='menu_side_contract();' style='".($_SESSION['theme']['menu_side_pin']['boolean'] == 'true' ? "max-width: calc(100% - 50px);" : null)." ".($_SESSION['theme']['menu_side_state']['text'] != 'expanded' ? "display: none;" : null)."' title=\"".$this->text['theme-label-contract_menu']."\"><i class='fas fa-bars fa-fw' style='z-index: 99800; padding-left: 1px;'></i></a>";
 				}
-				else {
-					$html = "	<div id='menu_side_brand_container'>\n";
-					//menu toggle buttons
-						if ($_SESSION['theme']['menu_brand_type']['text'] != 'none') {
-							$html .= "		<div style='float: right; margin-right: -20px; margin-top: -20px;'>\n";
-							$html .= "			<a class='menu_side_item_main menu_side_contract' onclick='menu_side_contract();' style='display: none;'><i class='fas fa-chevron-left'></i></a>\n";
-							$html .= "		</div>\n";
-						}
-					//show the menu brand image and/or text
-						$menu_brand_image_contracted =  $_SESSION['theme']['menu_side_brand_image_contracted']['text'] != '' ? $_SESSION['theme']['menu_side_brand_image_contracted']['text'] : PROJECT_PATH."/themes/default/images/logo_side_contracted.png";
-						$menu_brand_image_expanded =  $_SESSION['theme']['menu_side_brand_image_expanded']['text'] != '' ? $_SESSION['theme']['menu_side_brand_image_expanded']['text'] : PROJECT_PATH."/themes/default/images/logo_side_expanded.png";
-						$menu_brand_text = ($_SESSION['theme']['menu_brand_text']['text'] != '') ? escape($_SESSION['theme']['menu_brand_text']['text']) : "FusionPBX";
-						if ($_SESSION['theme']['menu_brand_type']['text'] == 'image' || $_SESSION['theme']['menu_brand_type']['text'] == '') {
-							$html .= "		<a href='".PROJECT_PATH."/' style='text-decoration: none;'>";
-							$html .= 			"<img id='menu_brand_image_contracted' style='width: 20px; margin-left: -2px; margin-top: -5px;' src='".escape($menu_brand_image_contracted)."' title=\"".escape($menu_brand_text)."\">";
-							$html .= 			"<img id='menu_brand_image_expanded' style='display: none;' src='".escape($menu_brand_image_expanded)."' title=\"".escape($menu_brand_text)."\">";
-							$html .= 		"</a>\n";
-						}
-						else if ($_SESSION['theme']['menu_brand_type']['text'] == 'image_text') {
-							$html .= "		<a href='".PROJECT_PATH."/' style='text-decoration: none;'>";
-							$html .= 			"<img id='menu_brand_image_contracted' style='width: 20px; margin-left: -2px; margin-top: -5px;' src='".escape($menu_brand_image_contracted)."' title=\"".escape($menu_brand_text)."\">";
-							$html .= 			"<span class='menu_brand_text' style='display: none;'>".$menu_brand_text."</span>";
-							$html .= 		"</a>\n";
-						}
-						else if ($_SESSION['theme']['menu_brand_type']['text'] == 'text') {
-							$html .= "		<a class='menu_brand_text' style='display: none;' href='".PROJECT_PATH."/'>".$menu_brand_text."</a>\n";
-						}
-					$html .= "	</div>\n";
+				$menu_brand_text = $_SESSION['theme']['menu_brand_text']['text'] != '' ? escape($_SESSION['theme']['menu_brand_text']['text']) : "FusionPBX";
+				if ($_SESSION['theme']['menu_brand_type']['text'] == 'text') {
+					$html .= "		<a class='menu_brand_text' ".($_SESSION['theme']['menu_side_state']['text'] != 'expanded' ? "style='display: none;'" : null)." href='".PROJECT_PATH."/'>".$menu_brand_text."</a>\n";
+				}
+				if ($_SESSION['theme']['menu_brand_type']['text'] == 'image' || $_SESSION['theme']['menu_brand_type']['text'] == 'image_text' || $_SESSION['theme']['menu_brand_type']['text'] == '') {
+					$menu_brand_image_contracted = $_SESSION['theme']['menu_side_brand_image_contracted']['text'] != '' ? $_SESSION['theme']['menu_side_brand_image_contracted']['text'] : PROJECT_PATH."/themes/default/images/logo_side_contracted.png";
+					$menu_brand_image_expanded = $_SESSION['theme']['menu_side_brand_image_expanded']['text'] != '' ? $_SESSION['theme']['menu_side_brand_image_expanded']['text'] : PROJECT_PATH."/themes/default/images/logo_side_expanded.png";
+					$html .= "		<a class='menu_brand_image' href='".PROJECT_PATH."/'>";
+					$html .= 			"<img id='menu_brand_image_contracted' style='".($_SESSION['theme']['menu_side_state']['text'] == 'expanded' ? "display: none;" : null)."' src='".escape($menu_brand_image_contracted)."' title=\"".escape($menu_brand_text)."\">";
+					$html .= 			"<img id='menu_brand_image_expanded' ".($_SESSION['theme']['menu_side_state']['text'] != 'expanded' ? "style='display: none;'" : null)." src='".escape($menu_brand_image_expanded)."' title=\"".escape($menu_brand_text)."\">";
+					$html .= 		"</a>\n";
 				}
+// 				else {
+// 					$html .= "		<a class='menu_side_item_main menu_side_expand' ".($_SESSION['theme']['menu_side_state']['text'] == 'expanded' ? "style='display: none';" : null)." onclick='menu_side_expand();' title=\"".$this->text['theme-label-expand_menu']."\"><i class='fas fa-bars fa-fw' style='z-index: 99800; padding-left: 1px;'></i></a>";
+// 				}
+				$html .= "	</div>\n";
 			//main menu items
 				if (is_array($menu_array) && sizeof($menu_array) != 0) {
 					foreach ($menu_array as $menu_index_main => $menu_item_main) {
-						$html .= "	<a class='menu_side_item_main' ".($menu_item_main['menu_item_link'] != '' ? "href='".$menu_item_main['menu_item_link']."'" : "onclick=\"menu_side_expand(); $('#sub_".$menu_item_main['menu_item_uuid']."').slideToggle(180, function() { if (!$(this).is(':hidden')) { $('.menu_side_sub').not($(this)).slideUp(180); } });\"")." title=\"".$menu_item_main['menu_language_title']."\">";
+						$menu_target = ($menu_item_main['menu_item_category'] == 'external') ? '_blank' : '';
+						$html .= "	<a class='menu_side_item_main' ".($menu_item_main['menu_item_link'] != '' ? "href='".$menu_item_main['menu_item_link']."' target='".$menu_target."'" : "onclick=\"menu_side_expand(); menu_side_item_toggle('".$menu_item_main['menu_item_uuid']."');\"")." title=\"".$menu_item_main['menu_language_title']."\">";
+						if (is_array($menu_item_main['menu_items']) && sizeof($menu_item_main['menu_items']) != 0 && $_SESSION['theme']['menu_side_item_main_sub_icons']['boolean'] == 'true') {
+							$html .= "	<div class='menu_side_item_main_sub_icons' style='float: right; margin-right: -1px; ".($_SESSION['theme']['menu_side_state']['text'] != 'expanded' ? "display: none;" : null)."'><i id='sub_arrow_".$menu_item_main['menu_item_uuid']."' class='sub_arrows fas fa-".($_SESSION['theme']['menu_side_item_main_sub_icon_expand']['text'] != '' ? $_SESSION['theme']['menu_side_item_main_sub_icon_expand']['text'] : 'chevron-down')." fa-xs'></i></div>\n";
+						}
 						if ($menu_item_main['menu_item_icon'] != '') {
-							$html .= "<i class='fas ".$menu_item_main['menu_item_icon']." fa-fw' style='z-index: 99800; margin-right: 8px;'></i>";
+							$html .= "<i class='menu_side_item_icon fas ".$menu_item_main['menu_item_icon']." fa-fw' style='z-index: 99800; margin-right: 8px;'></i>";
 						}
-						$html .= "<span class='menu_side_item_title' style='display: none;'>".$menu_item_main['menu_language_title']."</span>";
+						$html .= "<span class='menu_side_item_title' ".($_SESSION['theme']['menu_side_state']['text'] != 'expanded' ? "style='display: none;'" : null).">".$menu_item_main['menu_language_title']."</span>";
 						$html .= "</a>\n";
 						//sub menu items
 							if (is_array($menu_item_main['menu_items']) && sizeof($menu_item_main['menu_items']) != 0) {
 								$html .= "	<div id='sub_".$menu_item_main['menu_item_uuid']."' class='menu_side_sub' style='display: none;'>\n";
 								foreach ($menu_item_main['menu_items'] as $menu_index_sub => $menu_item_sub) {
 									$html .= "		<a class='menu_side_item_sub' ".($menu_item_sub['menu_item_category'] == 'external' ? "target='_blank'" : null)." href='".$menu_item_sub['menu_item_link']."'>";
-									$html .= 			"<span class='menu_side_item_title' style='display: none;'>".$menu_item_sub['menu_language_title']."</span>";
+									$html .= 			"<span class='menu_side_item_title' ".($_SESSION['theme']['menu_side_state']['text'] != 'expanded' ? "style='display: none;'" : null).">".$menu_item_sub['menu_language_title']."</span>";
 									$html .= 		"</a>\n";
 								}
 								$html .= "	</div>\n";
@@ -1135,30 +1134,42 @@ if (!class_exists('menu')) {
 					$html .= "	<div style='height: 100px;'></div>\n";
 				}
 			$html .= "</div>\n";
-			$html .= "<div id='content_container' style='padding: 0; width: calc(100% - ".(is_numeric($_SESSION['theme']['menu_side_width_contracted']['text']) ? $_SESSION['theme']['menu_side_width_contracted']['text'] : '55')."px); float: right; padding-top: 0px; text-align: center;'>\n";
-			$html .= "	<div id='content_header'>\n";
+			if ($_SESSION['theme']['menu_side_state']['text'] != 'expanded' && $_SESSION['theme']['menu_side_state']['text'] != 'hidden') {
+				$content_container_onclick = "onclick=\"clearTimeout(menu_side_contract_timer); if ($(window).width() >= 576) { menu_side_contract(); }\"";
+			}
+			$html .= "<div id='content_container' ".$content_container_onclick.">\n";
+			$html .= "	<div id='body_header'>\n";
 			//header: left
 				$html .= "<div class='float-left'>\n";
+				$html .= button::create(['type'=>'button','id'=>'menu_side_state_hidden_button','title'=>$this->text['theme-label-expand_menu'],'icon'=>'bars','class'=>'default '.($_SESSION['theme']['menu_side_state']['text'] != 'hidden' ? 'hide-sm-up ' : null).'float-left','onclick'=>'menu_side_expand();']);
+				$body_header_brand_text = $_SESSION['theme']['body_header_brand_text']['text'] != '' ? escape($_SESSION['theme']['body_header_brand_text']['text']) : "FusionPBX";
+				if ($_SESSION['theme']['body_header_brand_type']['text'] == 'image' || $_SESSION['theme']['body_header_brand_type']['text'] == 'image_text') {
+					$body_header_brand_image = $_SESSION['theme']['body_header_brand_image']['text'] != '' ? $_SESSION['theme']['body_header_brand_image']['text'] : PROJECT_PATH."/themes/default/images/logo_side_expanded.png";
+					$html .= 	"<div id='body_header_brand_image'>";
+					$html .= 		"<a href='".PROJECT_PATH."/'><img id='body_header_brand_image' src='".escape($body_header_brand_image)."' title=\"".escape($body_header_brand_text)."\"></a>";
+					$html .= 	"</div>";
+				}
+				if ($_SESSION['theme']['body_header_brand_type']['text'] == 'text' || $_SESSION['theme']['body_header_brand_type']['text'] == 'image_text') {
+					$html .= 	"<div id='body_header_brand_text'><a href='".PROJECT_PATH."/'>".$body_header_brand_text."</a></div>";
+				}
 				$html .= "</div>\n";
 			//header: right
-				$html .= "<span class='float-right' style='white-space: nowrap;'>";
+				$html .= "<div class='float-right' style='white-space: nowrap;'>";
 				//current user
-					$html .= "<span style='display: inline-block; padding-right: 20px; font-size: 85%;'>\n";
-					$html .= "<strong>".$this->text['theme-label-user']."</strong>: ";
-					$html .= "<a href='".PROJECT_PATH."/core/users/user_edit.php?id=user'>".$_SESSION['username']."</a>";
+					$html .= "<span style='display: inline-block; padding-right: 20px; font-size: 90%;'>\n";
+					$html .= "	<a href='".PROJECT_PATH."/core/users/user_edit.php?id=user' title=\"".$this->text['theme-label-user']."\"><i class='fas fa-".($_SESSION['theme']['body_header_icon_user']['text'] != '' ? $_SESSION['theme']['body_header_icon_user']['text'] : 'user-circle')." fa-lg fa-fw' style='margin-top: 6px; margin-right: 5px;'></i>".$_SESSION['username']."</a>";
 					$html .= "</span>\n";
 				//domain name/selector (sm+)
 					if (isset($_SESSION['username']) && $_SESSION['username'] != '' && permission_exists('domain_select') && count($_SESSION['domains']) > 1 && $_SESSION['theme']['domain_visible']['text'] == 'true') {
-						$html .= "<span style='display: inline-block; padding-right: 10px; font-size: 85%;'>\n";
-						$html .= "<strong>".$this->text['theme-label-domain']."</strong>: ";
-						$html .= "<a href='#' id='header_domain_selector_domain' title='".$this->text['theme-label-open_selector']."'>".escape($_SESSION['domain_name'])."</a>";
+						$html .= "<span style='display: inline-block; padding-right: 10px; font-size: 90%;'>\n";
+						$html .= "	<a href='#' id='header_domain_selector_domain' title='".$this->text['theme-label-open_selector']."'><i class='fas fa-".($_SESSION['theme']['body_header_icon_domain']['text'] != '' ? $_SESSION['theme']['body_header_icon_domain']['text'] : 'globe-americas')." fa-lg fa-fw' style='margin-top: 6px; margin-right: 5px;'></i>".escape($_SESSION['domain_name'])."</a>";
 						$html .= "</span>\n";
 					}
 				//logout icon
 					if (isset($_SESSION['username']) && $_SESSION['username'] != '' && $_SESSION['theme']['logout_icon_visible']['text'] == "true") {
 						$html .= "<a id='header_logout_icon' href='#' title=\"".$this->text['theme-label-logout']."\" onclick=\"modal_open('modal-logout','btn_logout');\"><span class='fas fa-sign-out-alt'></span></a>";
 					}
-				$html .= "</span>";
+				$html .= "</div>";
 			$html .= "	</div>\n";
 
 			//modal for logout icon (above)

+ 4 - 4
resources/classes/modal.php

@@ -57,9 +57,9 @@ if (!class_exists('modal')) {
 				//prefix cancel button to action
 					$array['actions'] = button::create(['type'=>'button','label'=>$text['button-cancel'],'icon'=>$_SESSION['theme']['button_icon_cancel'],'collapse'=>'never','onclick'=>'modal_close(); '.$array['onclose']]).$array['actions'];
 			}
-			$modal .= $array['title'] ? "<span class='modal-title'>".$array['title']."</span>\n" : null;
-			$modal .= $array['message'] ? "<span class='modal-message'>".$array['message']."</span>\n" : null;
-			$modal .= $array['actions'] ? "<span class='modal-actions'>".$array['actions']."</span>\n" : null;
+			$modal .= $array['title'] ? "		<span class='modal-title'>".$array['title']."</span>\n" : null;
+			$modal .= $array['message'] ? "		<span class='modal-message'>".$array['message']."</span>\n" : null;
+			$modal .= $array['actions'] ? "		<span class='modal-actions'>".$array['actions']."</span>\n" : null;
 			$modal .= "	</div>\n";
 			$modal .= "</div>";
 
@@ -71,4 +71,4 @@ if (!class_exists('modal')) {
 	}
 }
 
-?>
+?>

+ 3 - 0
resources/classes/schema.php

@@ -704,6 +704,9 @@ if (!class_exists('schema')) {
 																			case 'timestamptz':
 																				$sql_update .= "ALTER TABLE ".$table_name." ALTER COLUMN ".$field_name." TYPE ".$field_type." USING ".$field_name."::timestamp with time zone;\n";
 																				break;
+																			case 'boolean':
+																				$sql_update .= "ALTER TABLE ".$table_name." ALTER COLUMN ".$field_name." TYPE ".$field_type." USING ".$field_name."::boolean;\n";
+																				break;
 																			default:
 																				//$sql_update .= "-- $db_type, $db_name, $table_name, $field_name ".db_column_data_type ($db_type, $db_name, $table_name, $field_name)."<br>";
 																				$sql_update .= "ALTER TABLE ".$table_name." ALTER COLUMN ".$field_name." TYPE ".$field_type.";\n";

+ 11 - 2
resources/footer.php

@@ -118,7 +118,10 @@
 						//otherwise
 							default:
 								if (isset($setting['text']) && $setting['text'] != '') {
-									$settings['theme'][$subcategory] = escape($setting['text']);
+									$settings['theme'][$subcategory] = str_replace('&lowbar;','_',escape($setting['text']));
+								}
+								else if (isset($setting['numeric']) && is_numeric($setting['numeric'])) {
+									$settings['theme'][$subcategory] = $setting['numeric'];
 								}
 								else if (isset($setting['boolean'])) {
 									$settings['theme'][$subcategory] = $setting['boolean'] == 'true' ? true : false;
@@ -134,6 +137,8 @@
 				$settings['theme']['message_delay'] = is_numeric($settings['theme']['message_delay']) ? 1000 * (float) $settings['theme']['message_delay'] : 3000;
 				$settings['theme']['menu_side_width_contracted'] = is_numeric($settings['theme']['menu_side_width_contracted']) ? $settings['theme']['menu_side_width_contracted'] : '60';
 				$settings['theme']['menu_side_width_expanded'] = is_numeric($settings['theme']['menu_side_width_expanded']) ? $settings['theme']['menu_side_width_expanded'] : '225';
+				$settings['theme']['menu_side_toggle_hover_delay_expand'] = is_numeric($settings['theme']['menu_side_toggle_hover_delay_expand']) ? $settings['theme']['menu_side_toggle_hover_delay_expand'] : '300';
+				$settings['theme']['menu_side_toggle_hover_delay_contract'] = is_numeric($settings['theme']['menu_side_toggle_hover_delay_contract']) ? $settings['theme']['menu_side_toggle_hover_delay_contract'] : '1000';
 				$settings['theme']['menu_style'] = $settings['theme']['menu_style'] != '' ? $settings['theme']['menu_style'] : 'fixed';
 				$settings['theme']['menu_position'] = $settings['theme']['menu_position'] != '' ? $settings['theme']['menu_position'] : 'top';
 				$settings['theme']['footer'] = $settings['theme']['footer'] != '' ? $settings['theme']['footer'] : '&copy; '.$text['theme-label-copyright'].' 2008 - '.date('Y')." <a href='http://www.fusionpbx.com' class='footer' target='_blank'>fusionpbx.com</a> ".$text['theme-label-all_rights_reserved'];
@@ -182,7 +187,11 @@
 		//build menu by style
 			switch ($_SESSION['theme']['menu_style']['text']) {
 				case 'side':
-					$container_open = "<div id='menu_side_container'>\n";
+					$view->assign('menu_side_state', (isset($_SESSION['theme']['menu_side_state']['text']) && $_SESSION['theme']['menu_side_state']['text'] != '' ? $_SESSION['theme']['menu_side_state']['text'] : 'expanded'));
+					if ($_SESSION['theme']['menu_side_state']['text'] != 'hidden') {
+						$menu_side_toggle = $_SESSION['theme']['menu_side_toggle']['text'] == 'hover' ? " onmouseenter=\"clearTimeout(menu_side_contract_timer); if ($('#menu_side_container').width() < 100) { menu_side_expand_start(); }\" onmouseleave=\"clearTimeout(menu_side_expand_timer); if ($('#menu_side_container').width() > 100 && $('#menu_side_state_current').val() != 'expanded') { menu_side_contract_start(); }\"" : null;
+					}
+					$container_open = "<div id='menu_side_container' ".($_SESSION['theme']['menu_side_state']['text'] == 'hidden' ? "style='display: none;'" : "class='hide-xs'").$menu_side_toggle." >\n";
 					$menu = new menu;
 					$menu->text = $text;
 					$menu_html = $menu->menu_vertical($_SESSION['menu']['array']);

+ 34 - 30
resources/functions.php

@@ -106,22 +106,41 @@
 			$uuid = null;
 			if (PHP_OS === 'FreeBSD') {
 				$uuid = trim(shell_exec("uuid -v 4"));
-				if (!is_uuid($uuid)) {
+				if (is_uuid($uuid)) {
+					return $uuid;
+				}
+				else {
 					echo "Please install the following package.\n";
 					echo "pkg install ossp-uuid\n";
 					exit;
 				}
 			}
-			if (PHP_OS === 'Linux' && !is_uuid($uuid)) {
+			if (PHP_OS === 'Linux') {
 				$uuid = trim(file_get_contents('/proc/sys/kernel/random/uuid'));
+				if (is_uuid($uuid)) {
+					return $uuid;
+				}
+				else {
+					$uuid = trim(shell_exec("uuidgen"));
+					if (is_uuid($uuid)) {
+						return $uuid;
+					}
+					else {
+						echo "Please install the uuidgen.\n";
+						exit;
+					}
+				}
 			}
-			if (!is_uuid($uuid)) {
-				$uuid = trim(shell_exec("uuidgen"));
-			}
-			if (function_exists('com_create_guid') === true && PHP_OS === 'Windows') {
+			if ((strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') && function_exists('com_create_guid')) {
 				$uuid = trim(com_create_guid(), '{}');
+				if (is_uuid($uuid)) {
+					return $uuid;
+				}
+				else {
+					echo "The com_create_guid() function failed to create a uuid.\n";
+					exit;
+				}
 			}
-			return $uuid;
 		}
 	}
 
@@ -1029,24 +1048,6 @@ function number_pad($number,$n) {
 		}
 	}
 
-// ellipsis nicely truncate long text
-	if(!function_exists('ellipsis')) {
-		function ellipsis($string, $max_characters, $preserve_word = true) {
-			if ($max_characters+$x >= strlen($string)) { return $string; }
-			if ($preserve_word) {
-				for ($x = 0; $x < strlen($string); $x++) {
-					if ($string{$max_characters+$x} == " ") {
-						return substr($string,0,$max_characters+$x)." ...";
-					}
-					else { continue; }
-				}
-			}
-			else {
-				return substr($string,0,$max_characters)." ...";
-			}
-		}
-	}
-
 //function to convert hexidecimal color value to rgb string/array value
 	if (!function_exists('hex_to_rgb')) {
 		function hex_to_rgb($hex, $delim = '') {
@@ -1708,6 +1709,7 @@ function number_pad($number,$n) {
 //converts a string to a regular expression
 	if (!function_exists('string_to_regex')) {
 		function string_to_regex($string, $prefix='') {
+			$original_string = $string;
 			//escape the plus
 				if (substr($string, 0, 1) == "+") {
 					$string = "^\\+(".substr($string, 1).")$";
@@ -1723,9 +1725,11 @@ function number_pad($number,$n) {
 					}
 				}
 			//convert N,X,Z syntax to regex
-				$string = str_ireplace("N", "[2-9]", $string);
-				$string = str_ireplace("X", "[0-9]", $string);
-				$string = str_ireplace("Z", "[1-9]", $string);
+				if (preg_match('/^[NnXxZz]+$/', $original_string)) {
+					$string = str_ireplace("N", "[2-9]", $string);
+					$string = str_ireplace("X", "[0-9]", $string);
+					$string = str_ireplace("Z", "[1-9]", $string);
+				}
 			//add ^ to the start of the string if missing
 				if (substr($string, 0, 1) != "^") {
 					$string = "^".$string;
@@ -1919,7 +1923,7 @@ function number_pad($number,$n) {
 		//send the mkdir command to freeswitch
 			if ($fp) {
 				//build and send the mkdir command to freeswitch
-					$switch_cmd = "lua mkdir.lua '$dir'";
+					$switch_cmd = "lua mkdir.lua ".escapeshellarg($dir);
 					$switch_result = event_socket_request($fp, 'api '.$switch_cmd);
 					fclose($fp);
 				//check result
@@ -2162,4 +2166,4 @@ function number_pad($number,$n) {
 		}
 	}
 
-?>
+?>

+ 20 - 0
resources/header.php

@@ -118,6 +118,26 @@
 		unset($sql, $parameters, $content_result, $content_row);
 	}
 
+//button css class and styles
+	$button_icon_class = '';
+	$button_icon_style = 'padding: 3px;';
+	$button_label_class = 'button-label';
+	$button_label_style = 'padding-left: 5px; padding-right: 3px;';
+	$button_icons = $_SESSION['theme']['button_icons']['text'];
+	switch ($button_icons) {
+		case 'auto':
+			$button_label_class .= ' hide-md-dn';
+			break;
+		case 'only':
+			$button_label_style .= ' display: none;';
+			break;
+		case 'never':
+			$button_icon_class .= ' display: none;';
+			break;
+		case 'always':
+			break;
+	}
+
 //start the output buffer
 	ob_start();
 

+ 5 - 0
resources/login.php

@@ -234,6 +234,10 @@
 
 	if (!$password_reset) {
 
+		//create token
+			$object = new token;
+			$token = $object->create('login');
+
 		echo "<div id='login_form'>\n";
 		echo "<form name='login' method='post' action='".$_SESSION['login']['destination']['url']."'>\n";
 		echo "<input type='text' class='txt login' style='text-align: center; min-width: 200px; width: 200px; margin-bottom: 8px;' name='username' id='username' placeholder=\"".$text['label-username']."\"><br />\n";
@@ -262,6 +266,7 @@
 			) {
 			echo "<br><br><a class='login_link' onclick=\"toggle_password_reset('login_form','request_form','email');\">".$text['label-reset_password']."</a>";
 		}
+		echo "<input type='hidden' name='".$token['name']."' value='".$token['hash']."'>\n";
 		echo "</form>";
 		echo "<script>$('#username').trigger('focus');</script>";
 		echo "</div>";

+ 5 - 2
resources/paging.php

@@ -77,7 +77,10 @@ function paging($num_rows, $param, $rows_per_page, $mini = false, $result_count
 	if ($num_rows > 0) {
 		$max_page = ceil($num_rows/$rows_per_page);
 	}
-
+	else {
+		$max_page = 1;
+	}
+	
 	//add multi-lingual support
 	$language = new text;
 	$text = $language->get();
@@ -188,4 +191,4 @@ function paging($num_rows, $param, $rows_per_page, $mini = false, $result_count
 
 }
 
-?>
+?>

+ 15 - 33
resources/php.php

@@ -24,41 +24,23 @@
 	Mark J Crane <[email protected]>
 */
 
-	//session handling
-		//start the session
-			if (function_exists('session_start')) { 
-				if (!isset($_SESSION)) {
-					session_start();
-				}
+//session handling
+	//start the session
+		if (function_exists('session_start')) { 
+			if (!isset($_SESSION)) {
+				session_start();
 			}
-		//regenerate sessions to avoid session id attacks such as session fixation
-			if (array_key_exists('security',$_SESSION) && $_SESSION['security']['session_rotate']['boolean'] == "true") {
-				$_SESSION['session']['last_activity'] = time();
-				if (!isset($_SESSION['session']['created'])) {
-					$_SESSION['session']['created'] = time();
-				} else if (time() - $_SESSION['session']['created'] > 28800) {
-					// session started more than 8 hours ago
-					session_regenerate_id(true);    // rotate the session id
-					$_SESSION['session']['created'] = time();  // update creation time
-				}
-			}
-
-	//get the document_root parent directory
-		$document_root_parent = join(array_slice(explode("\\",realpath($_SERVER["DOCUMENT_ROOT"])),0,-1), '/');
-
-	//if magic quotes is enabled remove the slashes
-		if (get_magic_quotes_gpc()) {
-			$in = array(&$_GET, &$_POST, &$_REQUEST, &$_COOKIE);
-			while (list($k,$v) = each($in)) {
-				foreach ($v as $key => $val) {
-					if (!is_array($val)) {
-							$in[$k][$key] = stripslashes($val);
-							continue;
-					}
-					$in[] =& $in[$k][$key];
-				}
+		}
+	//regenerate sessions to avoid session id attacks such as session fixation
+		if (array_key_exists('security',$_SESSION) && $_SESSION['security']['session_rotate']['boolean'] == "true") {
+			$_SESSION['session']['last_activity'] = time();
+			if (!isset($_SESSION['session']['created'])) {
+				$_SESSION['session']['created'] = time();
+			} else if (time() - $_SESSION['session']['created'] > 28800) {
+				// session started more than 8 hours ago
+				session_regenerate_id(true);    // rotate the session id
+				$_SESSION['session']['created'] = time();  // update creation time
 			}
-			unset($in);
 		}
 
 ?>

+ 10 - 10
resources/phpmailer/class.phpmailer.php

@@ -56,7 +56,7 @@ class PHPMailer {
    * Sets the CharSet of the message.
    * @var string
    */
-  public $CharSet           = 'iso-8859-1';
+  public $CharSet           = 'UTF-8';
 
   /**
    * Sets the Content-type of the message.
@@ -69,7 +69,7 @@ class PHPMailer {
    *  "8bit", "7bit", "binary", "base64", and "quoted-printable".
    * @var string
    */
-  public $Encoding          = '8bit';
+  public $Encoding          = 'base64';
 
   /**
    * Holds the most recent mailer error message.
@@ -171,7 +171,7 @@ class PHPMailer {
    * @var boolean
    */
   public $UseSendmailOptions	= true;
-  
+
   /**
    * Path to PHPMailer plugins.  Useful if the SMTP class
    * is in a different directory than the PHP include path.
@@ -264,7 +264,7 @@ class PHPMailer {
    *  @var string
    */
   public $AuthType      = '';
-  
+
   /**
    *  Sets SMTP realm.
    *  @var string
@@ -491,7 +491,7 @@ class PHPMailer {
   const STOP_CONTINUE = 1; // message?, likely ok to continue processing
   const STOP_CRITICAL = 2; // message, plus full stop, critical error reached
   const CRLF = "\r\n";     // SMTP RFC specified EOL
-  
+
   /////////////////////////////////////////////////
   // METHODS, VARIABLES
   /////////////////////////////////////////////////
@@ -1849,7 +1849,7 @@ class PHPMailer {
         if (version_compare(PHP_VERSION, '5.3.0', '<')) {
           set_magic_quotes_runtime(0);
         } else {
-          ini_set('magic_quotes_runtime', 0); 
+          ini_set('magic_quotes_runtime', 0);
         }
       }
       $file_buffer  = file_get_contents($path);
@@ -1858,7 +1858,7 @@ class PHPMailer {
         if (version_compare(PHP_VERSION, '5.3.0', '<')) {
           set_magic_quotes_runtime($magic_quotes);
         } else {
-          ini_set('magic_quotes_runtime', $magic_quotes); 
+          ini_set('magic_quotes_runtime', $magic_quotes);
         }
       }
       return $file_buffer;
@@ -2135,13 +2135,13 @@ class PHPMailer {
         $pattern = '\075\000-\011\013\014\016-\037\077\137\177-\377' . $pattern;
         break;
     }
-    
+
     if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
       foreach (array_unique($matches[0]) as $char) {
         $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
       }
     }
-    
+
     //Replace every spaces to _ (more readable than =20)
     return str_replace(' ', '_', $encoded);
 }
@@ -2814,4 +2814,4 @@ class phpmailerException extends Exception {
     return $errorMsg;
   }
 }
-?>
+?>

+ 2 - 0
robots.txt

@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: /

+ 170 - 2
themes/default/app_config.php

@@ -319,6 +319,30 @@
 		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "false";
 		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set then body background color (and opacity) of the content.";
 		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "9011e469-f94b-4c45-9b08-8991c243292b";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "body_header_background_color";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "#eeeeee";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the background color for the body (content) header bar (Side Menu only).";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "b7ab6ad5-845a-4af6-880e-fa999e229216";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "body_header_icon_user";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "user-circle";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the icon to use next to the current user in the body header (Side Menu only).";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "bcc38e2f-e625-47b1-92da-bf9186975ef6";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "body_header_icon_domain";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "globe-americas";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the icon to use next to the current domain in the body header (Side Menu only).";
+		$y++;
 		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "ce3a2e85-472e-4375-a447-d7937cb6dbb7";
 		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
 		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "body_shadow_color";
@@ -343,6 +367,54 @@
 		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "false";
 		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set whether to cache the theme in the session.";
 		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "a3fcfa28-ca09-4c7a-849c-afdfd9fedc44";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "domain_selector_title_color";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "#000";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "false";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the text color of the domain selector title.";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "95e581f2-3f4e-4e4b-91e6-879d2beb329e";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "domain_selector_title_color_hover";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "#5082ca";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "false";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the text hover color of the domain selector title.";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "4e0309da-4adb-4a05-a321-d0ec6546dceb";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "domain_selector_background_color";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "#fff";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "false";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the background color of the domain selector pane.";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "cd62c333-4f4e-4462-b61c-1baf5fa524cb";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "domain_selector_list_background_color";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "#fff";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "false";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the list background color of the domain selector pane.";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "6a3db80c-5f21-4475-94ae-deac72a28225";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "domain_selector_list_border_color";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "#a4aebf";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "false";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the list border color of the domain selector pane.";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "6170ed6b-cb3e-4e66-831b-5498186b2ca8";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "domain_selector_list_divider_color";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "#c5d1e5";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "false";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the list item divider color of the domain selector pane.";
+		$y++;
 		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "5a401784-b930-46e7-8fb0-6fa0b5a8806e";
 		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
 		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "domain_selector_shadow_color";
@@ -411,10 +483,26 @@
 		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
 		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "menu_main_text_color_hover";
 		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
-		$apps[$x]['default_settings'][$y]['default_setting_value'] = "#69e5ff";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "#fd9c03";
 		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "false";
 		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the text hover color of the main menu items.";
 		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "2833c246-dccd-49c2-87cf-fb40c352b48d";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "menu_main_icon_color";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "#ffffff";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "false";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the icon color of the main menu items.";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "ed6bee7c-7d07-4a06-a94e-75d57231d36f";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "menu_main_icon_color_hover";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "#fd9c03";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "false";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the icon hover color of the main menu items.";
+		$y++;
 		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "aaed6662-d441-4a34-9ac6-874af33e4fd1";
 		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
 		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "menu_main_text_font";
@@ -1703,6 +1791,78 @@
 		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "false";
 		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the expanded brand image path for the Side menu.";
 		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "66d37950-15db-4dd0-888a-17ded7b5c0dc";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "menu_side_state";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "expanded";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the default state of the Side Menu: expanded (pinned) or contracted (unpinned).";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "eaab943f-34d9-44f5-854a-c2288d88dfd0";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "menu_side_pin";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "boolean";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "false";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Enable Side Menu toggle icon allowing users to choose their own preferred menu state (contracted or expanded).";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "8ee8012a-da8c-483a-996d-d81b30a8bbea";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "menu_side_toggle";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "hover";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set whether the Side Menu opens and closes with a 'Click' or with a mouse over/out ('Hover').";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "e7e11d18-0b06-4347-9305-f8f38284730f";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "menu_side_toggle_body_width";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "shrink";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the behavior of the body content when the Side Menu is expanded and contracted.";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "902e6d1b-d019-4d7f-9d83-38bab5db112e";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "menu_side_toggle_hover_delay_expand";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "numeric";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "300";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the delay in milliseconds before the Side Menu expands on mouse over (requires menu_side_toggle be set to 'Hover').";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "8dd2d3be-19c2-4758-9c71-5d2d3cf8af73";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "menu_side_toggle_hover_delay_contract";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "numeric";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "1000";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the delay in milliseconds before the Side Menu contracts on mouse out (requires menu_side_toggle be set to 'Hover').";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "994acf94-09df-42ec-b2c1-c3fc7d665cb9";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "menu_side_item_main_sub_icons";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "boolean";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "true";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set whether to display submenu indicator icons next to main menu items.";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "bf786d83-2e8c-4928-be7c-dfd2cde894d4";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "menu_side_item_main_sub_icon_expand";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "chevron-down";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the submenu indicator icon to use for the expand action (default: chevron-down).";
+		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "fe64a3e8-70af-4d9f-868a-47a739789cd3";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "menu_side_item_main_sub_icon_contract";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "chevron-up";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "Set the submenu indicator icon to use for the contract action (default: chevron-up).";
+		$y++;
 		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "97a620e1-d7b2-4550-8648-726c3029143d";
 		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
 		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "action_bar_border_top";
@@ -2039,6 +2199,14 @@
 		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
 		$apps[$x]['default_settings'][$y]['default_setting_description'] = "";
 		$y++;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "314a7107-7d00-4f61-8442-16323fb7f91d";
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "button_icon_settings";
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = "text";
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = "fas fa-cog";
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = "";
+		$y++;
 		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = "814ed631-a315-4bde-a822-4038432ae2a6";
 		$apps[$x]['default_settings'][$y]['default_setting_category'] = "theme";
 		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "keyboard_shortcut_check_all_enabled";
@@ -2255,4 +2423,4 @@
 		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "false";
 		$apps[$x]['default_settings'][$y]['default_setting_description'] = "";
 
-?>
+?>

+ 162 - 1
themes/default/app_languages.php

@@ -231,4 +231,165 @@ $text['theme-label-domain']['sv-se'] = "Domän";
 $text['theme-label-domain']['uk-ua'] = "Домен";
 $text['theme-label-domain']['tr-tr'] = "Alan Adı";
 
-?>
+$text['theme-label-expand_menu']['en-us'] = "Expand Menu";
+$text['theme-label-expand_menu']['en-gb'] = "Expand Menu";
+$text['theme-label-expand_menu']['ar-eg'] = "Expand Menu";
+$text['theme-label-expand_menu']['de-at'] = "Expand Menu";
+$text['theme-label-expand_menu']['de-ch'] = "Expand Menu";
+$text['theme-label-expand_menu']['de-de'] = "Expand Menu";
+$text['theme-label-expand_menu']['el-gr'] = "Expand Menu";
+$text['theme-label-expand_menu']['es-cl'] = "Expand Menu";
+$text['theme-label-expand_menu']['es-mx'] = "Expand Menu";
+$text['theme-label-expand_menu']['fr-ca'] = "Expand Menu";
+$text['theme-label-expand_menu']['fr-fr'] = "Expand Menu";
+$text['theme-label-expand_menu']['he-il'] = "Expand Menu";
+$text['theme-label-expand_menu']['it-it'] = "Expand Menu";
+$text['theme-label-expand_menu']['nl-nl'] = "Expand Menu";
+$text['theme-label-expand_menu']['pl-pl'] = "Expand Menu";
+$text['theme-label-expand_menu']['pt-br'] = "Expand Menu";
+$text['theme-label-expand_menu']['pt-pt'] = "Expand Menu";
+$text['theme-label-expand_menu']['ro-ro'] = "Expand Menu";
+$text['theme-label-expand_menu']['ru-ru'] = "Expand Menu";
+$text['theme-label-expand_menu']['sv-se'] = "Expand Menu";
+$text['theme-label-expand_menu']['uk-ua'] = "Expand Menu";
+$text['theme-label-expand_menu']['tr-tr'] = "Expand Menu";
+
+$text['theme-label-contract_menu']['en-us'] = "Contract Menu";
+$text['theme-label-contract_menu']['en-gb'] = "Contract Menu";
+$text['theme-label-contract_menu']['ar-eg'] = "Contract Menu";
+$text['theme-label-contract_menu']['de-at'] = "Contract Menu";
+$text['theme-label-contract_menu']['de-ch'] = "Contract Menu";
+$text['theme-label-contract_menu']['de-de'] = "Contract Menu";
+$text['theme-label-contract_menu']['el-gr'] = "Contract Menu";
+$text['theme-label-contract_menu']['es-cl'] = "Contract Menu";
+$text['theme-label-contract_menu']['es-mx'] = "Contract Menu";
+$text['theme-label-contract_menu']['fr-ca'] = "Contract Menu";
+$text['theme-label-contract_menu']['fr-fr'] = "Contract Menu";
+$text['theme-label-contract_menu']['he-il'] = "Contract Menu";
+$text['theme-label-contract_menu']['it-it'] = "Contract Menu";
+$text['theme-label-contract_menu']['nl-nl'] = "Contract Menu";
+$text['theme-label-contract_menu']['pl-pl'] = "Contract Menu";
+$text['theme-label-contract_menu']['pt-br'] = "Contract Menu";
+$text['theme-label-contract_menu']['pt-pt'] = "Contract Menu";
+$text['theme-label-contract_menu']['ro-ro'] = "Contract Menu";
+$text['theme-label-contract_menu']['ru-ru'] = "Contract Menu";
+$text['theme-label-contract_menu']['sv-se'] = "Contract Menu";
+$text['theme-label-contract_menu']['uk-ua'] = "Contract Menu";
+$text['theme-label-contract_menu']['tr-tr'] = "Contract Menu";
+
+$text['theme-label-pin_menu']['en-us'] = "Pin Menu";
+$text['theme-label-pin_menu']['en-gb'] = "Pin Menu";
+$text['theme-label-pin_menu']['ar-eg'] = "Pin Menu";
+$text['theme-label-pin_menu']['de-at'] = "Pin Menu";
+$text['theme-label-pin_menu']['de-ch'] = "Pin Menu";
+$text['theme-label-pin_menu']['de-de'] = "Pin Menu";
+$text['theme-label-pin_menu']['el-gr'] = "Pin Menu";
+$text['theme-label-pin_menu']['es-cl'] = "Pin Menu";
+$text['theme-label-pin_menu']['es-mx'] = "Pin Menu";
+$text['theme-label-pin_menu']['fr-ca'] = "Pin Menu";
+$text['theme-label-pin_menu']['fr-fr'] = "Pin Menu";
+$text['theme-label-pin_menu']['he-il'] = "Pin Menu";
+$text['theme-label-pin_menu']['it-it'] = "Pin Menu";
+$text['theme-label-pin_menu']['nl-nl'] = "Pin Menu";
+$text['theme-label-pin_menu']['pl-pl'] = "Pin Menu";
+$text['theme-label-pin_menu']['pt-br'] = "Pin Menu";
+$text['theme-label-pin_menu']['pt-pt'] = "Pin Menu";
+$text['theme-label-pin_menu']['ro-ro'] = "Pin Menu";
+$text['theme-label-pin_menu']['ru-ru'] = "Pin Menu";
+$text['theme-label-pin_menu']['sv-se'] = "Pin Menu";
+$text['theme-label-pin_menu']['uk-ua'] = "Pin Menu";
+$text['theme-label-pin_menu']['tr-tr'] = "Pin Menu";
+
+$text['theme-label-unpin_menu']['en-us'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['en-gb'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['ar-eg'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['de-at'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['de-ch'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['de-de'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['el-gr'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['es-cl'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['es-mx'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['fr-ca'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['fr-fr'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['he-il'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['it-it'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['nl-nl'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['pl-pl'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['pt-br'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['pt-pt'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['ro-ro'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['ru-ru'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['sv-se'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['uk-ua'] = "Unpin Menu";
+$text['theme-label-unpin_menu']['tr-tr'] = "Unpin Menu";
+
+$text['theme-message-menu_expanded']['en-us'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['en-gb'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['ar-eg'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['de-at'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['de-ch'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['de-de'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['el-gr'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['es-cl'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['es-mx'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['fr-ca'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['fr-fr'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['he-il'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['it-it'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['nl-nl'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['pl-pl'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['pt-br'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['pt-pt'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['ro-ro'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['ru-ru'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['sv-se'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['uk-ua'] = "Menu Pinned";
+$text['theme-message-menu_expanded']['tr-tr'] = "Menu Pinned";
+
+$text['theme-message-menu_contracted']['en-us'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['en-gb'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['ar-eg'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['de-at'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['de-ch'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['de-de'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['el-gr'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['es-cl'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['es-mx'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['fr-ca'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['fr-fr'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['he-il'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['it-it'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['nl-nl'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['pl-pl'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['pt-br'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['pt-pt'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['ro-ro'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['ru-ru'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['sv-se'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['uk-ua'] = "Menu Unpinned";
+$text['theme-message-menu_contracted']['tr-tr'] = "Menu Unpinned";
+
+$text['theme-message-menu_reset']['en-us'] = "Menu State Reset";
+$text['theme-message-menu_reset']['en-gb'] = "Menu State Reset";
+$text['theme-message-menu_reset']['ar-eg'] = "Menu State Reset";
+$text['theme-message-menu_reset']['de-at'] = "Menu State Reset";
+$text['theme-message-menu_reset']['de-ch'] = "Menu State Reset";
+$text['theme-message-menu_reset']['de-de'] = "Menu State Reset";
+$text['theme-message-menu_reset']['el-gr'] = "Menu State Reset";
+$text['theme-message-menu_reset']['es-cl'] = "Menu State Reset";
+$text['theme-message-menu_reset']['es-mx'] = "Menu State Reset";
+$text['theme-message-menu_reset']['fr-ca'] = "Menu State Reset";
+$text['theme-message-menu_reset']['fr-fr'] = "Menu State Reset";
+$text['theme-message-menu_reset']['he-il'] = "Menu State Reset";
+$text['theme-message-menu_reset']['it-it'] = "Menu State Reset";
+$text['theme-message-menu_reset']['nl-nl'] = "Menu State Reset";
+$text['theme-message-menu_reset']['pl-pl'] = "Menu State Reset";
+$text['theme-message-menu_reset']['pt-br'] = "Menu State Reset";
+$text['theme-message-menu_reset']['pt-pt'] = "Menu State Reset";
+$text['theme-message-menu_reset']['ro-ro'] = "Menu State Reset";
+$text['theme-message-menu_reset']['ru-ru'] = "Menu State Reset";
+$text['theme-message-menu_reset']['sv-se'] = "Menu State Reset";
+$text['theme-message-menu_reset']['uk-ua'] = "Menu State Reset";
+$text['theme-message-menu_reset']['tr-tr'] = "Menu State Reset";
+
+?>

+ 209 - 54
themes/default/css.php

@@ -457,7 +457,14 @@ header('Expires: '.gmdate('D, d M Y H:i:s',time()+3600).' GMT');
 		position: fixed;
 		top: 0;
 		left: 0;
-		width: <?php echo is_numeric($_SESSION['theme']['menu_side_width_contracted']['text']) ? $_SESSION['theme']['menu_side_width_contracted']['text'] : '60'; ?>px;
+		<?php
+		if ($_SESSION['theme']['menu_side_state']['text'] == 'expanded' || $_SESSION['theme']['menu_side_state']['text'] == 'hidden') {
+			echo "width: ".(is_numeric($_SESSION['theme']['menu_side_width_expanded']['text']) ? $_SESSION['theme']['menu_side_width_expanded']['text'] : '225')."px;\n";
+		}
+		else {
+			echo "width: ".(is_numeric($_SESSION['theme']['menu_side_width_contracted']['text']) ? $_SESSION['theme']['menu_side_width_contracted']['text'] : '60')."px;\n";
+		}
+		?>
 		height: 100%;
 		overflow: auto;
 		<?php if ($_SESSION['theme']['menu_main_background_image']['text'] != '') { ?>
@@ -481,13 +488,54 @@ header('Expires: '.gmdate('D, d M Y H:i:s',time()+3600).' GMT');
 		border-radius: <?php echo ($_SESSION['theme']['menu_main_border_radius']['text'] != '') ? $_SESSION['theme']['menu_main_border_radius']['text'] : '0'; ?>;
 		}
 
-	/* menu side brand container */
-	div#menu_side_brand_container {
+	/* menu side logo */
+	a.menu_brand_image {
+		display: inline-block;
+		text-align: center;
+		padding: 15px 20px;
+		}
+
+	a.menu_brand_image:hover {
+		text-decoration: none;
+		}
+
+	img#menu_brand_image_contracted {
+		border: none;
+		width: auto;
+		max-height: 20px;
+		max-width: 20px;
+		margin-left: -1px;
+		}
+
+	img#menu_brand_image_expanded {
+		border: none;
+		height: auto;
+		max-width: 145px;
+		max-height: 35px;
+		margin-left: -7px;
+		}
+
+	/* menu brand text */
+	a.menu_brand_text {
+		display: inline-block;
+		padding: 10px 20px;
+		color: <?php echo ($_SESSION['theme']['menu_brand_text_color']['text'] != '') ? $_SESSION['theme']['menu_brand_text_color']['text'] : 'rgba(255,255,255,0.90)'; ?>;
+		font-weight: 600;
+		white-space: nowrap;
+		}
+
+	a.menu_brand_text:hover {
+		color: <?php echo ($_SESSION['theme']['menu_brand_text_color_hover']['text'] != '') ? $_SESSION['theme']['menu_brand_text_color_hover']['text'] : 'rgba(255,255,255,1.0)'; ?>;
+		text-decoration: none;
+		}
+
+	/* menu side control container */
+	div#menu_side_control_container {
 		position: -webkit-sticky;
 		position: sticky;
 		z-index: 99901;
 		top: 0;
-		padding: 20px;
+		padding: 0;
 		min-height: 75px;
 		text-align: left;
 		<?php if ($_SESSION['theme']['menu_main_background_image']['text'] != '') { ?>
@@ -508,39 +556,9 @@ header('Expires: '.gmdate('D, d M Y H:i:s',time()+3600).' GMT');
 		border-radius: <?php echo ($_SESSION['theme']['menu_main_border_radius']['text'] != '') ? $_SESSION['theme']['menu_main_border_radius']['text'] : '0'; ?>;
 		}
 
-	/* menu side logo */
-	img#menu_brand_image_contracted {
-		border: none;
-		width: auto;
-		max-height: 30px;
-		max-width: 30px;
-		margin-right: 10px;
-		}
-
-	img#menu_brand_image_expanded {
-		border: none;
-		height: auto;
-		max-width: 145px;
-		max-height: 35px;
-		margin-top: -3px;
-		margin-left: -6px;
-		}
-
-	/* menu brand text */
-	.menu_brand_text {
-		color: <?php echo ($_SESSION['theme']['menu_brand_text_color']['text'] != '') ? $_SESSION['theme']['menu_brand_text_color']['text'] : 'rgba(255,255,255,0.80)'; ?>;
-		font-weight: 600;
-		white-space: nowrap;
-		}
-
-	.menu_brand_text:hover {
-		color: <?php echo ($_SESSION['theme']['menu_brand_text_color_hover']['text'] != '') ? $_SESSION['theme']['menu_brand_text_color_hover']['text'] : 'rgba(255,255,255,1.0)'; ?>;
-		text-decoration: none;
-		}
-
 	div#menu_side_container > a.menu_side_item_main,
 	div#menu_side_container > div > a.menu_side_item_main,
-	div#menu_side_container > div#menu_side_brand_container > div > a.menu_side_item_main {
+	div#menu_side_container > div#menu_side_control_container a.menu_side_item_main {
 		display: block;
 		width: 100%;
 		padding: 10px 20px;
@@ -552,19 +570,31 @@ header('Expires: '.gmdate('D, d M Y H:i:s',time()+3600).' GMT');
 		}
 
 	div#menu_side_container > a.menu_side_item_main:hover,
-	div#menu_side_container a.menu_side_item_main:focus,
-	div#menu_side_container a.menu_side_item_main:active,
+	div#menu_side_container > a.menu_side_item_main:focus,
+	div#menu_side_container > a.menu_side_item_main:active,
 	div#menu_side_container > div > a.menu_side_item_main:hover,
 	div#menu_side_container > div > a.menu_side_item_main:focus,
 	div#menu_side_container > div > a.menu_side_item_main:active,
-	div#menu_side_container > div#menu_side_brand_container > div > a.menu_side_item_main:hover,
-	div#menu_side_container > div#menu_side_brand_container > div > a.menu_side_item_main:focus,
-	div#menu_side_container > div#menu_side_brand_container > div > a.menu_side_item_main:active {
+	div#menu_side_container > div#menu_side_control_container > div a.menu_side_item_main:hover,
+	div#menu_side_container > div#menu_side_control_container > div a.menu_side_item_main:focus,
+	div#menu_side_container > div#menu_side_control_container > div a.menu_side_item_main:active {
 		color: <?php echo ($_SESSION['theme']['menu_main_text_color_hover']['text'] != '') ? $_SESSION['theme']['menu_main_text_color_hover']['text'] : '#fd9c03'; ?>;
 		background: <?php echo ($_SESSION['theme']['menu_main_background_color_hover']['text'] != '') ? $_SESSION['theme']['menu_main_background_color_hover']['text'] : 'rgba(0,0,0,1.0)'; ?>;
 		text-decoration: none;
 		}
 
+	div#menu_side_container > a.menu_side_item_main > i.menu_side_item_icon,
+	div#menu_side_container > a.menu_side_item_main > i.menu_side_item_icon,
+	div#menu_side_container > a.menu_side_item_main > i.menu_side_item_icon {
+		color: <?php echo ($_SESSION['theme']['menu_main_icon_color']['text'] != '') ? $_SESSION['theme']['menu_main_icon_color']['text'] : '#fd9c03'; ?>;
+	}
+
+	div#menu_side_container > a.menu_side_item_main:hover > i.menu_side_item_icon,
+	div#menu_side_container > a.menu_side_item_main:focus > i.menu_side_item_icon,
+	div#menu_side_container > a.menu_side_item_main:active > i.menu_side_item_icon {
+		color: <?php echo ($_SESSION['theme']['menu_main_icon_color_hover']['text'] != '') ? $_SESSION['theme']['menu_main_icon_color_hover']['text'] : '#fd9c03'; ?>;
+	}
+
 	a.menu_side_item_sub {
 		display: block;
 		width: 100%;
@@ -577,6 +607,12 @@ header('Expires: '.gmdate('D, d M Y H:i:s',time()+3600).' GMT');
 		cursor: pointer;
 		}
 
+	@media (max-width: 575.98px) {
+		a.menu_side_item_sub {
+			padding: 8px 20px 8px 45px;
+			}
+	}
+
 	a.menu_side_item_sub:hover,
 	a.menu_side_item_sub:focus,
 	a.menu_side_item_sub:active {
@@ -590,6 +626,85 @@ header('Expires: '.gmdate('D, d M Y H:i:s',time()+3600).' GMT');
 		cursor: pointer;
 		}
 
+	div#content_container {
+		padding: 0;
+		padding-top: 0px;
+		text-align: center;
+		}
+
+	@media (max-width: 575.98px) {
+		div#content_container {
+			width: 100%;
+			}
+	}
+	@media (min-width: 576px) {
+		div#content_container {
+			<?php
+			if ($_SESSION['theme']['menu_side_state']['text'] == 'expanded') {
+				$content_container_width = is_numeric($_SESSION['theme']['menu_side_width_expanded']['text']) ? $_SESSION['theme']['menu_side_width_expanded']['text'] : '225';
+			}
+			else if ($_SESSION['theme']['menu_side_state']['text'] == 'hidden') {
+				$content_container_width = 0;
+			}
+			else {
+				$content_container_width = is_numeric($_SESSION['theme']['menu_side_width_contracted']['text']) ? $_SESSION['theme']['menu_side_width_contracted']['text'] : '60';
+			}
+			?>
+			width: calc(100% - <?php echo $content_container_width; ?>px);
+			float: right;
+			}
+	}
+
+/* BODY/HEADER BAR *****************************************************************/
+
+	<?php if ($_SESSION['theme']['menu_style']['text'] == 'side') { ?>
+		div#body_header {
+			padding: 10px 10px 15px 10px;
+			height: 50px;
+			<?php echo $_SESSION['theme']['body_header_background_color']['text'] != '' ? 'background-color: '.$_SESSION['theme']['body_header_background_color']['text'].';' : null; ?>
+			}
+	<?php } else { ?>
+		div#body_header {
+			padding: 10px;
+			margin-top: 5px;
+			height: 40px;
+			}
+	<?php } ?>
+
+	div#body_header_brand_image {
+		display: inline-block;
+		margin-left: 10px;
+		}
+
+	div#body_header_brand_image > a:hover {
+		text-decoration: none;
+		}
+
+	img#body_header_brand_image {
+		border: none;
+		margin-top: -4px;
+		height: auto;
+		max-width: 145px;
+		max-height: 35px;
+		}
+
+	div#body_header_brand_text {
+		display: inline-block;
+		margin: 3px 0 0 10px;
+		}
+
+	div#body_header_brand_text > a {
+		color: <?php echo ($_SESSION['theme']['body_header_brand_text_color']['text'] != '') ? $_SESSION['theme']['body_header_brand_text_color']['text'] : 'rgba(0,0,0,0.90)'; ?>;
+		font-size: <?php echo ($_SESSION['theme']['body_header_brand_text_size']['text'] != '') ? $_SESSION['theme']['body_header_brand_text_size']['text'] : '16px'; ?>;
+		font-weight: 600;
+		text-decoration: none;
+		}
+
+	div#body_header_brand_text > a:hover {
+		color: <?php echo ($_SESSION['theme']['body_header_brand_text_color_hover']['text'] != '') ? $_SESSION['theme']['body_header_brand_text_color_hover']['text'] : 'rgba(0,0,0,1.0)'; ?>;
+		text-decoration: none;
+		}
+
 /* BUTTONS ********************************************************************/
 
 	/* buttons */
@@ -951,7 +1066,7 @@ header('Expires: '.gmdate('D, d M Y H:i:s',time()+3600).' GMT');
 		font-family: arial, san-serif;
 		font-size: 10pt;
 		overflow: hidden;
-		background-color: #fff;
+		background: <?php echo ($_SESSION['theme']['domain_selector_background_color']['text'] != '') ? $_SESSION['theme']['domain_selector_background_color']['text'] : '#fff'; ?>;
 		-webkit-box-shadow: <?php echo ($_SESSION['theme']['domain_selector_shadow_color']['text'] != '') ? '0 0 10px '.$_SESSION['theme']['domain_selector_shadow_color']['text'] : 'none'; ?>;
 		-moz-box-shadow: <?php echo ($_SESSION['theme']['domain_selector_shadow_color']['text'] != '') ? '0 0 10px '.$_SESSION['theme']['domain_selector_shadow_color']['text'] : 'none'; ?>;
 		box-shadow: <?php echo ($_SESSION['theme']['domain_selector_shadow_color']['text'] != '') ? '0 0 10px '.$_SESSION['theme']['domain_selector_shadow_color']['text'] : 'none'; ?>;
@@ -965,19 +1080,31 @@ header('Expires: '.gmdate('D, d M Y H:i:s',time()+3600).' GMT');
 		text-align: left;
 		}
 
+	#domains_header > a#domains_title {
+		font-weight: 600;
+		font-size: <?php echo ($_SESSION['theme']['heading_text_size']['text'] != '') ? $_SESSION['theme']['heading_text_size']['text'] : '15px'; ?>;
+		font-family: <?php echo ($_SESSION['theme']['heading_text_font']['text'] != '') ? $_SESSION['theme']['heading_text_font']['text'] : 'arial'; ?>;
+		color: <?php echo ($_SESSION['theme']['domain_selector_title_color']['text'] != '') ? $_SESSION['theme']['domain_selector_title_color']['text'] : '#000'; ?>;
+		}
+
+	#domains_header > a#domains_title:hover {
+		text-decoration: none;
+		color: <?php echo ($_SESSION['theme']['domain_selector_title_color_hover']['text'] != '') ? $_SESSION['theme']['domain_selector_title_color_hover']['text'] : '#5082ca'; ?>;
+		}
+
 	#domains_list {
 		position: relative;
 		overflow: auto;
 		width: 300px;
 		height: 100%;
 		padding: 1px;
-		background-color: #fff;
-		border: 1px solid #a4aebf;
+		background: <?php echo ($_SESSION['theme']['domain_selector_list_background_color']['text'] != '') ? $_SESSION['theme']['domain_selector_list_background_color']['text'] : '#fff'; ?>;
+		border: 1px solid <?php echo ($_SESSION['theme']['domain_selector_list_border_color']['text'] != '') ? $_SESSION['theme']['domain_selector_list_border_color']['text'] : '#a4aebf'; ?>;
 		}
 
 	div.domains_list_item, div.domains_list_item_active, div.domains_list_item_inactive {
 		text-align: left;
-		border-bottom: 1px solid #c5d1e5;
+		border-bottom: 1px solid <?php echo ($_SESSION['theme']['domain_selector_list_divider_color']['text'] != '') ? $_SESSION['theme']['domain_selector_list_divider_color']['text'] : '#c5d1e5'; ?>;
 		padding: 5px 8px 8px 8px;
 		overflow: hidden;
 		white-space: nowrap;
@@ -1070,7 +1197,7 @@ header('Expires: '.gmdate('D, d M Y H:i:s',time()+3600).' GMT');
 	a.login_link:hover {
 		color: <?php echo ($_SESSION['theme']['login_link_text_color_hover']['text'] != '') ? $_SESSION['theme']['login_link_text_color_hover']['text'] : '#5082ca'; ?> !important;
 		cursor: pointer;
-		text-decoration: underline;
+		text-decoration: none;
 		}
 
 	<?php
@@ -1136,12 +1263,6 @@ header('Expires: '.gmdate('D, d M Y H:i:s',time()+3600).' GMT');
 			}
 		}
 
-	div#content_header {
-		padding: 10px;
-		margin-top: 5px;
-		height: 40px;
-	}
-
 /* GENERAL ELEMENTS *****************************************************************/
 
 	img {
@@ -1164,7 +1285,7 @@ header('Expires: '.gmdate('D, d M Y H:i:s',time()+3600).' GMT');
 	a:hover,
 	button.btn.btn-link:hover {
 		color: <?php echo ($_SESSION['theme']['text_link_color_hover']['text'] != '') ? $_SESSION['theme']['text_link_color_hover']['text'] : '#5082ca'; ?>;
-		text-decoration: underline;
+		text-decoration: none;
 		}
 
 	button.btn {
@@ -1554,7 +1675,7 @@ header('Expires: '.gmdate('D, d M Y H:i:s',time()+3600).' GMT');
 
 	th a:hover {
 		color: <?php echo ($_SESSION['theme']['table_heading_text_color']['text'] != '') ? $_SESSION['theme']['table_heading_text_color']['text'] : '#3164ad'; ?>;
-		text-decoration: underline;
+		text-decoration: none;
 		}
 
 	td {
@@ -1829,6 +1950,40 @@ header('Expires: '.gmdate('D, d M Y H:i:s',time()+3600).' GMT');
 		cursor: default;
 		}
 
+	div.off_ext {
+		position: relative;
+		float: left;
+		width: 235px;
+		margin: 0px 8px 8px 0px;
+		padding: 0px;
+		border-style: solid;
+		-moz-border-radius: 5px;
+		-webkit-border-radius: 5px;
+		border-radius: 5px;
+		-webkit-box-shadow: 0 0 3px #e5e9f0;
+		-moz-box-shadow: 0 0 3px #e5e9f0;
+		box-shadow: 0 0 3px #e5e9f0;
+		border-width: 1px 3px;
+		border-color: #b9c5d8 #c5d1e5;
+		background-color: #e5eaf5;
+		cursor: not-allowed;
+		}
+		
+		div.off_ext:after {
+			position: absolute;
+			content: "";
+			z-index: 10;
+			-moz-border-radius: 5px;
+			-webkit-border-radius: 5px;
+			border-radius: 5px;
+			display: block;
+			height: 100%;
+			top: 0;
+			left: 0;
+			right: 0;
+			background: rgba(255, 255, 255, 0.5);
+		}
+
 	div.op_state_active {
 		background-color: #baf4bb;
 		border-width: 1px 3px;
@@ -1841,7 +1996,7 @@ header('Expires: '.gmdate('D, d M Y H:i:s',time()+3600).' GMT');
 		border-color: #41b9eb;
 		}
 
-	table.op_ext {
+	table.op_ext, table.off_ext {
 		width: 100%;
 		height: 70px;
 		-moz-border-radius: 5px;

+ 265 - 58
themes/default/template.php

@@ -12,7 +12,7 @@
 <meta charset='utf-8'>
 <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
 <meta http-equiv='X-UA-Compatible' content='IE=edge'>
-<meta name='viewport' content='width=device-width, initial-scale=1'>
+<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no' />
 
 {*//external css files *}
 	<link rel='stylesheet' type='text/css' href='{$project_path}/resources/bootstrap/css/bootstrap.min.css.php'>
@@ -82,76 +82,190 @@
 
 		{if $settings.theme.menu_style == 'side'}
 			//side menu visibility toggle
+				var menu_side_expand_timer;
+				var menu_side_contract_timer;
+				var menu_side_state_current = '{if $menu_side_state == 'hidden'}expanded{else}{$menu_side_state}{/if}';
 				{literal}
-				var menu_side_state = 'contracted';
+
+				function menu_side_contract_start() {
+					menu_side_contract_timer = setTimeout(function() {
+						menu_side_contract();
+						}, {/literal}{$settings.theme.menu_side_toggle_hover_delay_contract}{literal});
+				}
+
 				function menu_side_contract() {
-					$('.menu_side_sub').slideUp(180);
-					$('.menu_side_item_title').hide();
-					{/literal}
-					{if $settings.theme.menu_brand_type == 'image' || $settings.theme.menu_brand_type == ''}
-						{literal}
-						$('#menu_brand_image_expanded').fadeOut(180, function() {
-							$('#menu_brand_image_contracted').fadeIn(180);
-						});
+					if (menu_side_state_current == 'expanded') {
 						{/literal}
-					{elseif $settings.theme.menu_brand_type == 'image_text'}
-						{literal}
-						$('.menu_brand_text').hide();
-						$('#menu_brand_image_contracted').animate({ width: '20px', 'margin-left': '-2px' }, 250);
-						{/literal}
-					{else if $settings.theme.menu_brand_type == 'text'}
+						{if $menu_side_state == 'hidden'}
+							{literal}
+							$('#menu_side_container').hide();
+							{/literal}
+						{else}
+							{literal}
+							$('.menu_side_sub').slideUp(180);
+							$('.menu_side_item_title').hide();
+							{/literal}
+							{if $settings.theme.menu_brand_type == 'image' || $settings.theme.menu_brand_type == 'image_text' || $settings.theme.menu_brand_type == ''}
+								{literal}
+								$('#menu_brand_image_expanded').fadeOut(180, function() {
+									$('#menu_brand_image_contracted').fadeIn(180);
+								});
+								{/literal}
+							{else if $settings.theme.menu_brand_type == 'text'}
+								{literal}
+								$('.menu_brand_text').hide();
+								{/literal}
+							{/if}
+							{literal}
+							$('.menu_side_control_state').hide();
+							$('.menu_side_item_main_sub_icons').hide();
+							$('.sub_arrows').removeClass('fa-{/literal}{$settings.theme.menu_side_item_main_sub_icon_contract}{literal}').addClass('fa-{/literal}{$settings.theme.menu_side_item_main_sub_icon_expand}{literal}');
+							$('#menu_side_container').animate({ width: '{/literal}{$settings.theme.menu_side_width_contracted}{literal}px' }, 180, function() {
+								menu_side_state_current = 'contracted';
+							});
+							{/literal}
+							{if $settings.theme.menu_side_toggle_body_width == 'shrink' || ($settings.theme.menu_side_state == 'expanded' && $settings.theme.menu_side_toggle_body_width == 'fixed')}
+								{literal}
+								if ($(window).width() >= 576) {
+									$('#content_container').animate({ width: $(window).width() - {/literal}{$settings.theme.menu_side_width_contracted}{literal} }, 250);
+								}
+								{/literal}
+							{/if}
+							{literal}
+							$('.menu_side_contract').hide();
+							$('.menu_side_expand').show();
+							if ($(window).width() < 576) {
+								$('#menu_side_container').hide();
+							}
+							{/literal}
+						{/if}
 						{literal}
-						$('.menu_brand_text').fadeOut(180);
-						{/literal}
-					{/if}
-					{literal}
-					$('#menu_side_container').animate({ width: '{/literal}{$settings.theme.menu_side_width_contracted}{literal}px' }, 250);
-					$('#content_container').animate({ width: $(window).width() - {/literal}{$settings.theme.menu_side_width_contracted}{literal} }, 250, function() {
-						menu_side_state = 'contracted';
-					});
+					}
+				}
 
-					$('.menu_side_contract').hide();
-					$('.menu_side_expand').show();
+				function menu_side_expand_start() {
+					menu_side_expand_timer = setTimeout(function() {
+						menu_side_expand();
+						}, {/literal}{$settings.theme.menu_side_toggle_hover_delay_expand}{literal});
 				}
 
 				function menu_side_expand() {
 					{/literal}
-					{if $settings.theme.menu_brand_type == 'image_text'}
+					{if $menu_side_state == 'hidden'}
 						{literal}
-						$('#menu_brand_image_contracted').animate({ width: '30px', 'margin-left': '0' }, 250);
-						{/literal}
-					{elseif $settings.theme.menu_brand_type == 'image' || $settings.theme.menu_brand_type == ''}
-						{literal}
-						$('#menu_brand_image_contracted').fadeOut(180);
-						{/literal}
-					{/if}
-					{literal}
-					$('#menu_side_container').animate({ width: '{/literal}{$settings.theme.menu_side_width_expanded}{literal}px' }, 250);
-					$('#content_container').animate({ width: $(window).width() - {/literal}{$settings.theme.menu_side_width_expanded}{literal} }, 250, function() {
-						$('.menu_brand_text').fadeIn(180);
-						$('.menu_side_item_title').fadeIn(180);
+						$('.menu_side_contract').show();
 						{/literal}
-						{if $settings.theme.menu_brand_type != 'none'}
+						{if $settings.theme.menu_brand_type == 'image' || $settings.theme.menu_brand_type == 'image_text' || $settings.theme.menu_brand_type == ''}
 							{literal}
-							$('.menu_side_contract').fadeIn(180);
+							$('#menu_brand_image_contracted').hide();
+							$('#menu_brand_image_expanded').show();
 							{/literal}
 						{/if}
-						{if $settings.theme.menu_brand_type == 'image' || $settings.theme.menu_brand_type == ''}
+						{literal}
+						$('.menu_side_control_state').show();
+						$('.menu_brand_text').show();
+						$('.menu_side_item_main_sub_icons').show();
+						$('.menu_side_item_title').show();
+						if ($(window).width() < 576) {
+							$('#menu_side_container').width($(window).width());
+						}
+						$('#menu_side_container').show();
+						{/literal}
+					{else}
+						{if $settings.theme.menu_brand_type == 'image' || $settings.theme.menu_brand_type == 'image_text' ||$settings.theme.menu_brand_type == ''}
 							{literal}
-							$('#menu_brand_image_expanded').fadeIn(180);
+							$('#menu_brand_image_contracted').fadeOut(180);
 							{/literal}
 						{/if}
 						{literal}
-						menu_side_state = 'expanded';
-					});
-					{/literal}
-					{if $settings.theme.menu_brand_type == 'none'}
-						{literal}
+						$('.menu_side_expand').hide();
 						$('.menu_side_contract').show();
+						$('#menu_side_container').show();
+						var menu_side_container_width = $(window).width() < 576 ? $(window).width() : '{/literal}{$settings.theme.menu_side_width_expanded}{literal}px';
+						$('#menu_side_container').animate({ width: menu_side_container_width }, 180, function() {
+							{/literal}
+							{if $settings.theme.menu_brand_type == 'image' || $settings.theme.menu_brand_type == 'image_text' || $settings.theme.menu_brand_type == ''}
+								{literal}
+								$('#menu_brand_image_expanded').fadeIn(180);
+								{/literal}
+							{/if}
+							{literal}
+							$('.menu_side_control_state').fadeIn(180);
+							$('.menu_brand_text').fadeIn(180);
+							$('.menu_side_item_main_sub_icons').fadeIn(180);
+							$('.menu_side_item_title').fadeIn(180, function() {
+								menu_side_state_current = 'expanded';
+							});
+						});
 						{/literal}
+						{if $settings.theme.menu_side_toggle_body_width == 'shrink' || ($settings.theme.menu_side_state == 'expanded' && $settings.theme.menu_side_toggle_body_width == 'fixed')}
+							{literal}
+							if ($(window).width() >= 576) {
+								$('#content_container').animate({ width: $(window).width() - {/literal}{$settings.theme.menu_side_width_expanded}{literal} }, 250);
+							}
+							{/literal}
+						{/if}
 					{/if}
 					{literal}
-					$('.menu_side_expand').hide();
+				}
+
+				function menu_side_item_toggle(item_id) {
+					$('#sub_arrow_'+item_id).toggleClass(['fa-{/literal}{$settings.theme.menu_side_item_main_sub_icon_contract}{literal}','fa-{/literal}{$settings.theme.menu_side_item_main_sub_icon_expand}{literal}']);
+					$('.sub_arrows').not('#sub_arrow_'+item_id).removeClass('fa-{/literal}{$settings.theme.menu_side_item_main_sub_icon_contract}{literal}').addClass('fa-{/literal}{$settings.theme.menu_side_item_main_sub_icon_expand}{literal}');
+					$('#sub_'+item_id).slideToggle(180, function() {
+						if (!$(this).is(':hidden')) {
+							$('.menu_side_sub').not($(this)).slideUp(180);
+						}
+					});
+				}
+
+				function menu_side_state_set(state) {
+					var user_setting_set_path = '{/literal}{$project_path}{literal}/core/user_settings/user_setting_set.php?category=theme&subcategory=menu_side_state&name=text&value='+state;
+					var xhr = new XMLHttpRequest();
+					xhr.open('GET', user_setting_set_path);
+					xhr.send(null);
+					xhr.onreadystatechange = function () {
+						var setting_modified;
+						if (xhr.readyState === 4) {
+							if (xhr.status === 200) {
+								setting_modified = xhr.responseText;
+								if (setting_modified == 'true') {
+									document.getElementById('menu_side_state_set_expanded').style.display = state == 'expanded' ? 'none' : 'block';
+									document.getElementById('menu_side_state_set_contracted').style.display = state == 'contracted' ? 'none' : 'block';
+									{/literal}
+									{if $menu_side_state == 'hidden'}
+										{literal}
+										document.getElementById('menu_side_state_hidden_button').style.display='none';
+										{/literal}
+									{/if}
+									{literal}
+									if (state == 'expanded') {
+										if ($(window).width() >= 576) {
+											$('#content_container').animate({ width: $(window).width() - {/literal}{$settings.theme.menu_side_width_expanded}{literal} }, 250);
+										}
+										else {
+											$('#menu_side_container').animate({ width: $(window).width() }, 180);
+										}
+										document.getElementById('menu_side_state_current').value = 'expanded';
+										display_message("{/literal}{$text.theme_message_menu_expanded}{literal}", 'positive', 1000);
+									}
+									else {
+										menu_side_contract();
+										if ($(window).width() >= 576) {
+											$('#content_container').animate({ width: $(window).width() - {/literal}{$settings.theme.menu_side_width_contracted}{literal} }, 250);
+										}
+										menu_side_state_current = 'contracted';
+										document.getElementById('menu_side_state_current').value = 'contracted';
+										display_message("{/literal}{$text.theme_message_menu_contracted}{literal}", 'positive', 1000);
+									}
+								}
+								else if (setting_modified == 'deleted') {
+									display_message("{/literal}{$text.theme_message_menu_reset}{literal}", 'positive', 1000);
+									document.location.reload();
+								}
+							}
+						}
+					}
 				}
 				{/literal}
 		{/if}
@@ -188,7 +302,7 @@
 					$(document).scrollTop(0);
 					$('#domains_container').show();
 					$('#domains_block').animate({marginRight: '+=300'}, 400, function() {
-						$('#domain_filter').trigger('focus');
+						$('#domains_filter').trigger('focus');
 					});
 				}
 
@@ -196,8 +310,8 @@
 					$('#domains_visible').val(0);
 					$(document).ready(function() {
 						$('#domains_block').animate({marginRight: '-=300'}, 400, function() {
-							$('#domain_filter').val('');
-							domain_search($('#domain_filter').val());
+							$('#domains_filter').val('');
+							domain_search($('#domains_filter').val());
 							$('.navbar').css('margin-right','0'); //restore navbar margin
 							$('#domains_container').css('right','0'); //domain container right position
 							$('#domains_container').hide();
@@ -393,11 +507,27 @@
 					{if $settings.theme.keyboard_shortcut_copy_enabled}
 						{if $browser_name_short == 'Safari'} //emulate with detecting [c] only, as [command] and [control] keys are ignored when captured
 							{literal}
-							if ((e.which == 99 || e.which == 67) && !(e.target.tagName == 'INPUT' && e.target.type == 'text') && e.target.tagName != 'TEXTAREA') {
+							if (
+								(e.which == 99 || e.which == 67) &&
+								!(e.target.tagName == 'INPUT' && e.target.type == 'text') &&
+								!(e.target.tagName == 'INPUT' && e.target.type == 'password') &&
+								e.target.tagName != 'TEXTAREA'
+								) {
 							{/literal}
 						{else}
 							{literal}
-							if ((((e.which == 99 || e.which == 67) && (e.ctrlKey || e.metaKey) && !e.shiftKey) || (e.which == 19)) && !(e.target.tagName == 'INPUT' && e.target.type == 'text') && e.target.tagName != 'TEXTAREA') {
+							if (
+								(
+									(
+										(e.which == 99 || e.which == 67) &&
+										(e.ctrlKey || e.metaKey) &&
+										!e.shiftKey
+									) ||
+									e.which == 19
+								) &&
+								!(e.target.tagName == 'INPUT' && e.target.type == 'text') &&
+								e.target.tagName != 'TEXTAREA'
+								) {
 							{/literal}
 						{/if}
 						{literal}
@@ -540,7 +670,44 @@
 			{if $settings.theme.menu_style == 'side'}
 				{literal}
 				$(window).on('resizeEnd', function() {
-					$('#content_container').animate({ width: $(window).width() - $('#menu_side_container').width() }, 200);
+					if ($(window).width() < 576) {
+						if (menu_side_state_current == 'contracted') {
+							$('#menu_side_container').hide();
+						}
+						if (menu_side_state_current == 'expanded') {
+							{/literal}
+							{if $menu_side_state != 'hidden'}
+								{literal}
+								$('#menu_side_container').show();
+								{/literal}
+							{/if}
+							{literal}
+							$('#menu_side_container').animate({ width: $(window).width() }, 180);
+						}
+						$('#content_container').animate({ width: $(window).width() }, 100);
+					}
+					else {
+						{/literal}
+						{if $menu_side_state == 'hidden'}
+							{literal}
+							$('#menu_side_container').animate({ width: '{/literal}{$settings.theme.menu_side_width_expanded}{literal}px' }, 180);
+							$('#content_container').animate({ width: $(window).width() }, 100);
+							{/literal}
+						{else}
+							{literal}
+							$('#menu_side_container').show();
+							if (menu_side_state_current == 'expanded') {
+								$('#menu_side_container').animate({ width: '{/literal}{$settings.theme.menu_side_width_expanded}{literal}px' }, 180, function() {
+									$('#content_container').animate({ width: $(window).width() - $('#menu_side_container').width() }, 100);
+								});
+							}
+							else {
+								$('#content_container').animate({ width: $(window).width() - $('#menu_side_container').width() }, 100);
+							}
+							{/literal}
+						{/if}
+						{literal}
+					}
 				});
 				{/literal}
 			{/if}
@@ -662,6 +829,45 @@
 		}
 		{/literal}
 
+	//checkbox on change
+		{literal}
+		function checkbox_on_change(checkbox) {
+			checked = false;
+			var inputs = document.getElementsByTagName('input');
+			for (var i = 0, max = inputs.length; i < max; i++) {
+				if (inputs[i].type === 'checkbox' && inputs[i].checked == true) {
+					checked = true;
+					break;
+				}
+			}
+			btn_copy = document.getElementById("btn_copy");
+			btn_toggle = document.getElementById("btn_toggle");
+			btn_delete = document.getElementById("btn_delete");
+			if (checked == true) {
+				if (btn_copy) {
+					btn_copy.style.display = "inline";
+				}
+				if (btn_toggle) {
+					btn_toggle.style.display = "inline";
+				}
+				if (btn_delete) {
+					btn_delete.style.display = "inline";
+				}
+			}
+		 	else {
+				if (btn_copy) {
+					btn_copy.style.display = "none";
+				}
+				if (btn_toggle) {
+					btn_toggle.style.display = "none";
+				}
+				if (btn_delete) {
+					btn_delete.style.display = "none";
+				}
+		 	}
+		}
+		{/literal}
+
 	//list page functions
 		{literal}
 		function list_all_toggle(modifier) {
@@ -821,9 +1027,9 @@
 				<div id='domains_block'>
 					<div id='domains_header'>
 						<input id='domains_hide' type='button' class='btn' style='float: right' value="{$text.theme_button_close}">
-						<a href='{$domains_app_path}'><b style='color: #000;'>{$text.theme_title_domains}</b></a> ({$domain_count})
+						<a id='domains_title' href='{$domains_app_path}'>{$text.theme_title_domains} <span style='font-size: 80%;'>({$domain_count})</span></a>
 						<br><br>
-						<input type='text' id='domain_filter' class='formfld' style='margin-left: 0; min-width: 100%; width: 100%;' placeholder="{$text.theme_label_search}" onkeyup='domain_search(this.value)'>
+						<input type='text' id='domains_filter' class='formfld' style='margin-left: 0; min-width: 100%; width: 100%;' placeholder="{$text.theme_label_search}" onkeyup='domain_search(this.value)'>
 					</div>
 					<div id='domains_list'>
 						{foreach $domains as $row}
@@ -912,6 +1118,7 @@
 				{if $settings.theme.menu_style == 'inline'}{$logo}{/if}
 				{$menu}
 				{if $settings.theme.menu_style == 'inline' || $settings.theme.menu_style == 'static'}<br />{/if}
+				{if $settings.theme.menu_style == 'side'}<input type='hidden' id='menu_side_state_current' value='{if $menu_side_state == 'hidden'}expanded{else}{$menu_side_state}{/if}'>{/if}
 			{else} {*//default: fixed *}
 				{$menu}
 				{$container_open}
@@ -926,4 +1133,4 @@
 		{/if}
 
 </body>
-</html>
+</html>