<?php
/*
AdminFrontend.php, an Admin Frontend for performing administrative tasks.
Copyright (C) 2005 Arend van Beelen, Auton Rijnsburg
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For any questions, comments or whatever, you may mail me at: hide@address.com
*/
require_once('Config.php');
require_once('Decoration.php');
require_once('Forms.php');
require_once('Frontend.php');
require_once('GUI.php');
require_once('JavaScript.php');
require_once('Locale.php');
require_once('Login.php');
require_once('Menus.php');
require_once('Messages.php');
require_once('Navigation.php');
require_once('Output.php');
require_once('String.php');
/**
* @brief The Admin Frontend
*/
class AdminFrontend implements Frontend
{
public function buildGUI()
{
$this->modifyBaseUrl();
Locale::init('plugins/Frontends', Locale::language());
$this->mainWindow = $mainWindow = new MainWindow(i18n('Aukyla Administration Area'));
new Box($mainWindow, 'logo');
$menu = new Menu($mainWindow, 'mainmenu');
$autonEntry = new MenuEntry($menu, i18n('Auton'));
$autonEntry->setLink('http://www.auton.nl/');
$autonEntry->setCssClass('home');
$menu = new Menu($mainWindow, 'submenu');
new MenuHead($menu, i18n('Main Menu'));
$homeEntry = new MenuEntry($menu, i18n('Back'));
$homeEntry->setLink($this->originalBaseURL);
if(String::startsWith(Login::username(), 'anonymous'))
{
$loginEntry = new MenuEntry($menu, i18n('Login'));
$loginEntry->setLink(Config::globals('baseURL').'?view=Login');
}
else
{
$logoutEntry = new MenuEntry($menu, i18n('Logout'));
$logoutEntry->setLink(Config::globals('baseURL').'?action=Logout');
}
$main = new Box($mainWindow, 'main');
new MessagesWidget($main);
// reset the view if the user clicked a cancel button
if(Config::request('button') == i18n('Cancel'))
{
Config::unsetRequest('view');
Config::unsetRequest('action');
Config::unsetRequest('button');
}
$this->handleActions($main);
$this->showView($main);
}
private function modifyBaseUrl()
{
$this->originalBaseURL = Config::globals('baseURL');
if(String::startsWith(Config::globals('secureBaseURL'), 'https://'))
{
Config::setGlobal('baseURL', "https://{$_SERVER['HTTP_HOST']}/admin.php");
Config::setGlobal('secureBaseURL', "https://{$_SERVER['HTTP_HOST']}/admin.php");
}
else
{
Config::setGlobal('baseURL', "http://{$_SERVER['HTTP_HOST']}/admin.php");
Config::setGlobal('secureBaseURL', "http://{$_SERVER['HTTP_HOST']}/admin.php");
}
}
private function handleActions(Container $parent)
{
$action = Config::request('action');
if($action != '' && $action != 'Login')
{
if(Login::isMemberOf('admin') == false)
{
new Paragraph($parent, i18n('You do not have access to the Aukyla Administration Area.'));
return;
}
if($action == 'DeleteUser' || $action == 'DeleteGroup')
{
if(Config::request('userDeleteButton') != i18n('Delete User(s)') &&
Config::request('groupDeleteButton') != i18n('Delete Group(s)'))
{
$action = '';
Config::unsetRequest('action');
}
else
{
Config::unsetRequest('view');
}
}
$config = new Config();
$configChanged = false;
switch($action)
{
case 'SaveDefaults':
$config->setVariable('language', Config::request('language', 'en'));
$config->setVariable('theme', Config::request('theme', 'default'));
$config->setVariable('useDecorations', Config::request('useDecorations') == 'true' ? 'true' : 'false');
$configChanged = true;
break;
case 'SaveServer';
$config->setVariable('loginMethod', Config::request('loginMethod', 'passwd'));
$config->setVariable('output', Config::request('output', 'XHTML'));
$config->setVariable('serverSideXSLT', Config::request('serverSideXSLT') == 'true' ? 'true' : 'false');
$configChanged = true;
break;
case 'AddUser':
$this->addUser();
break;
case 'EditUser':
case 'DeleteUser':
$this->updateUser();
break;
case 'AddGroup':
$this->addGroup();
break;
case 'EditGroup':
case 'DeleteGroup':
$this->updateGroup();
break;
}
if($configChanged == true)
{
$config->saveConfiguration();
Messages::confirm(i18n('Configuration saved.'));
global $Config;
$Config->readConfiguration();
$this->modifyBaseUrl();
}
}
}
private function addUser()
{
if(Config::request('newPassword') == Config::request('newPasswordConfirm'))
{
$password = Config::request('newPassword');
}
else
{
Messages::error(i18n('Passwords don\'t match.'));
return;
}
$username = Config::request('newUsername');
$fullName = Config::request('newFullName');
$userMail = Config::request('newUserMail');
$ipRange = Config::request('newIpRange');
$cryptedPassword = crypt($password);
$output = "$username:$fullName:$userMail:$cryptedPassword";
if($ipRange != '')
{
$output .= ":$ipRange";
}
$output .= "\n";
$this->writePasswdFile($output, true);
$this->updateUserGroups();
Messages::confirm('User added.');
}
private function updateUser()
{
if(($lines = file(AUKYLA_DIR.'/config/passwd')) === false)
{
die('Could not open passwd file!');
}
switch(Config::request('action'))
{
case 'EditUser':
if(Config::request('newPassword') == Config::request('newPasswordConfirm'))
{
$newPassword = Config::request('newPassword');
}
else
{
Messages::error(i18n('Passwords didn\'t match.'));
return;
}
$oldUsername = Config::request('oldUsername');
$newUsername = Config::request('newUsername');
$newFullName = Config::request('newFullName');
$newUserMail = Config::request('newUserMail');
$newIpRange = Config::request('newIpRange');
$newCryptedPassword = crypt($newPassword);
$deleteUsersArray = array();
break;
case 'DeleteUser':
$newPassword = '';
$oldUsername = '';
$newUsername = '';
$newFullName = '';
$newUserMail = '';
$newIpRange = '';
$newCryptedPassword = '';
$deleteUsersArray = explode(',', Config::request('deleteItems'));
break;
}
$output = '';
foreach($lines as $line)
{
list($username, $fullName, $userMail, $cryptedPassword) = explode(':', trim($line), 4);
$ipRange = '';
if(strchr($cryptedPassword, ':'))
{
list($cryptedPassword, $ipRange) = explode(':', $cryptedPassword, 2);
}
if(in_array($username, $deleteUsersArray))
{
continue;
}
if($username == $oldUsername)
{
$username = $newUsername;
$fullName = $newFullName;
$userMail = $newUserMail;
$ipRange = $newIpRange;
if($newPassword != '')
{
$cryptedPassword = $newCryptedPassword;
}
}
$output .= "$username:$fullName:$userMail:$cryptedPassword";
if($ipRange != '')
{
$output .= ":$ipRange";
}
$output .= "\n";
}
$this->writePasswdFile($output);
$this->updateUserGroups();
Messages::confirm('User configuration updated.');
}
private function updateUserGroups()
{
if(($lines = file(AUKYLA_DIR.'/config/group')) === false)
{
die('Could not open group file!');
}
if(Config::request('action') == 'DeleteUser')
{
$oldUsername = explode(',', Config::request('deleteItems'));
}
else
{
$oldUsername = array(Config::request('oldUsername'));
}
$newUsername = Config::request('newUsername');
$groups = explode(',', Config::request('selectedGroups'));
$output = '';
foreach($lines as $line)
{
list($group, $users) = explode(':', trim($line), 2);
$usersArray = explode(',', $users);
$newUsersArray = array();
foreach($usersArray as $user)
{
if(in_array($user, $oldUsername) == false)
{
$newUsersArray[] = $user;
}
}
if(in_array($group, $groups))
{
$newUsersArray[] = $newUsername;
}
$newUsers = implode(',', $newUsersArray);
$output .= "$group:$newUsers\n";
}
$this->writeGroupFile($output);
}
private function addGroup()
{
$groupName = Config::request('editItem');
$output = "$groupName:\n";
$this->writeGroupFile($output, true);
Messages::confirm('Group added.');
}
private function updateGroup()
{
if(($lines = file(AUKYLA_DIR.'/config/group')) === false)
{
die('Could not open group file!');
}
switch(Config::request('action'))
{
case 'EditGroup':
$groupName = Config::request('groupName');
$deleteGroupsArray = array();
break;
case 'DeleteGroup':
$groupName = '';
$deleteGroupsArray = explode(',', Config::request('deleteItems'));
break;
}
$output = '';
foreach($lines as $line)
{
list($group, $users) = explode(':', trim($line), 2);
if(in_array($group, $deleteGroupsArray))
{
continue;
}
if($group == $groupName)
{
$users = Config::request('selectedUsers');
}
$output .= "$group:$users\n";
}
$this->writeGroupFile($output);
Messages::confirm('Group configuration updated.');
}
private function writePasswdFile($output, $append = false)
{
if(($fp = fopen(AUKYLA_DIR.'/config/passwd', $append ? 'a' : 'w')) === false)
{
die('Could not write passwd file!');
}
fwrite($fp, $output, strlen($output));
fclose($fp);
}
private function writeGroupFile($output, $append = false)
{
if(($fp = fopen(AUKYLA_DIR.'/config/group', $append ? 'a' : 'w')) === false)
{
die('Could not write group file!');
}
fwrite($fp, $output, strlen($output));
fclose($fp);
}
private function showView(Container $parent)
{
$view = Config::request('view');
switch($view)
{
case 'Login':
new LoginForm($parent);
break;
default:
if(Login::isMemberOf('admin') == false)
{
new Paragraph($parent, i18n('You do not have access to the Aukyla Administration Area.'));
return;
}
$tabWidget = new TabWidget($parent, 'adminArea');
$this->createDefaultsTab($tabWidget);
$this->createServerTab($tabWidget);
$this->createUsersAndGroupsTab($tabWidget);
}
}
private function createDefaultsTab(TabWidget $tabWidget)
{
if($tabWidget->currentTab() == 'defaults')
{
new PageIcon($this->mainWindow, 'base/icons/settings');
}
$tab = $tabWidget->addTab('defaults', i18n('Defaults'));
new Paragraph($tab, i18n('On this page you can configure the default settings for users. Users can override these settings.'));
$form = new Form($tab, Config::globals('baseURL').'?action=SaveDefaults');
$form->useGridLayout(true);
$languageInput = new SelectInput($form, 'language');
$languageInput->setText(i18n('Language:'));
$languageInput->setOptions(Locale::availableLanguages());
$languageInput->setValue(Config::globals('language'));
$themeInput = new SelectInput($form, 'theme');
$themeInput->setText(i18n('Theme:'));
$themeInput->setOptions(Decoration::availableThemes());
$themeInput->setValue(Config::globals('theme', 'default'));
$decorationsInput = new CheckboxInput($form, 'useDecorations');
$decorationsInput->setText(i18n('Show decoration icons.'));
$decorationsInput->setChecked(Config::globals('useDecorations', 'true') == 'true');
$button = new Button($form, 'button');
$button->setValue(i18n('Apply'));
$button->setConfirm(true);
}
private function createServerTab(TabWidget $tabWidget)
{
if($tabWidget->currentTab() == 'server')
{
new PageIcon($this->mainWindow, 'base/icons/ksysguard');
}
$outputMethods = array();
foreach(glob(AUKYLA_DIR.'/htdocs/resources/base/Output/*.xsl') as $file)
{
$method = String::substringBefore(String::substringAfter($file, AUKYLA_DIR.'/htdocs/resources/base/Output/'), '.xsl');
$outputMethods[$method] = $method;
}
$authenticationResources = array();
foreach(glob(AUKYLA_DIR.'/plugins/LoginHandlers/*_LoginHandler.php') as $file)
{
$resource = String::substringBefore(String::substringAfter($file, AUKYLA_DIR.'/plugins/LoginHandlers/'), '_LoginHandler.php');
$authenticationResources[$resource] = $resource;
}
$tab = $tabWidget->addTab('server', i18n('Server'));
new Paragraph($tab, i18n('On this page you can configure the Aukyla server. Only change these settings if you know what you\'re doing.'));
$form = new Form($tab, Config::globals('baseURL').'?action=SaveServer');
$form->useGridLayout(true);
$authenticationResourceInput = new SelectInput($form, 'loginMethod');
$authenticationResourceInput->setText(i18n('Authentication resource:'));
$authenticationResourceInput->setOptions($authenticationResources);
$authenticationResourceInput->setValue(Config::globals('loginMethod', 'passwd'));
$outputMethodInput = new SelectInput($form, 'output');
$outputMethodInput->setText(i18n('Output format:'));
$outputMethodInput->setOptions($outputMethods);
$outputMethodInput->setValue(Config::globals('output', 'XHTML'));
$serverSideXsltInput = new CheckboxInput($form, 'serverSideXSLT');
$serverSideXsltInput->setText(i18n('Use Server-Side XSLT transformations.'));
$serverSideXsltInput->setChecked(Config::globals('serverSideXSLT', 'true') == 'true');
$button = new Button($form, 'button');
$button->setValue(i18n('Apply'));
$button->setConfirm(true);
$paragraph = new Paragraph($form);
$label = new Label($paragraph, i18n('Warning: '));
$label->addCssStyle('font-weight: bold');
new Label($paragraph, i18n('If you insist on using Internet Explorer, you have to select the HTML output format and enable Server-Side XSLT transformations. However, this will put extra load on your server.'));
}
private function createUsersAndGroupsTab(TabWidget $tabWidget)
{
if(Config::globals('loginMethod', 'passwd') == 'passwd')
{
$tab = $tabWidget->addTab('users', i18n('Users and Groups'));
$view = Config::request('view');
switch($view)
{
case 'EditUser':
if($tabWidget->currentTab() == 'users')
{
new PageIcon($this->mainWindow, 'base/icons/personal');
}
$this->createUserDetailsForm($tab);
break;
case 'EditGroup':
if($tabWidget->currentTab() == 'users')
{
new PageIcon($this->mainWindow, 'base/icons/groups');
}
if(Config::request('groupAddButton') == i18n('Add Group'))
{
$this->createNewGroupForm($tab);
}
else
{
$this->createGroupDetailsForm($tab);
}
break;
default:
if($tabWidget->currentTab() == 'users')
{
new PageIcon($this->mainWindow, 'base/icons/groups');
}
$this->createUserGroupOverview($tab);
break;
}
}
}
private function createUserDetailsForm($parent)
{
if(Config::request('userAddButton') == i18n('Add User'))
{
$action = 'AddUser';
$username = '';
$fullName = '';
$userMail = '';
$ipRange = '';
$memberGroups = array();
$new = true;
new Header($parent, i18n('New User'));
}
else
{
$action = 'EditUser';
$username = Config::request('editItem');
$fullName = Login::fullName($username);
$userMail = Login::userMail($username);
$ipRange = Login::ipRange($username);
$memberGroups = Login::memberGroups($username);
$new = false;
new Header($parent, $username);
}
$groups = Login::groups();
new ExternalJavaScript($parent, 'resources/plugins/Frontends/Admin/adminScripts.js');
new Paragraph($parent, i18n('Please enter some user details.'));
$form = new Form($parent, Config::globals('baseURL')."?action=$action");
$form->setErrorMessage(i18n('Please fill in all required fields.'));
$form->useGridLayout(true);
$form->addJavaScript('onsubmit', 'updateSelectedGroups();');
$oldUsernameInput = new HiddenInput($form, 'oldUsername');
$oldUsernameInput->setValue($username);
$usernameInput = new TextInput($form, 'newUsername');
$usernameInput->setText(i18n('Username:'));
$usernameInput->setValue($username);
$usernameInput->setRequired(true);
$fullNameInput = new TextInput($form, 'newFullName');
$fullNameInput->setText(i18n('Full Name:'));
$fullNameInput->setValue($fullName);
$fullNameInput->setRequired(true);
$passwordInput = new PasswordInput($form, 'newPassword');
$passwordInput->setText(i18n('Password:'));
$passwordConfirmInput = new PasswordInput($form, 'newPasswordConfirm');
$passwordConfirmInput->setText(i18n('Confirm Password:'));
if($new == true)
{
$passwordInput->setRequired(true);
$passwordConfirmInput->setRequired(true);
}
$userMailInput = new TextInput($form, 'newUserMail');
$userMailInput->setText(i18n('E-mail address:'));
$userMailInput->setValue($userMail);
$ipRangeInput = new TextInput($form, 'newIpRange');
$ipRangeInput->setText(i18n('Allowed IP range:'));
$ipRangeInput->setValue($ipRange);
$groupsInput = new SelectInput($form, 'groupsSelect');
$groupsInput->setMultiple(true, 10);
$groupsInput->setText(i18n('Groups:'));
$groupsInput->addCssStyle('width: 15em');
foreach($groups as $group)
{
$groupsInput->addOption($group, $group, in_array($group, $memberGroups));
}
$box = new Box($form);
$box->setOrientation('horizontal');
$button = new Button($box, 'button');
$button->setValue(i18n('OK'));
$button->setConfirm(true);
$button = new Button($box, 'button');
$button->setValue(i18n('Cancel'));
return $form;
}
private function createNewGroupForm($parent)
{
new Header($parent, i18n('New Group'));
new Paragraph($parent, i18n('Please enter the name for the group.'));
$form = new Form($parent, Config::globals('baseURL').'?action=AddGroup&view=EditGroup');
$form->useGridLayout(true);
$nameInput = new TextInput($form, 'editItem');
$nameInput->setText(i18n('Name:'));
$nameInput->setRequired(true);
$box = new Box($form);
$box->setOrientation('horizontal');
$button = new Button($box, 'button');
$button->setValue(i18n('OK'));
$button->setConfirm(true);
$button = new Button($box, 'button');
$button->setValue(i18n('Cancel'));
return $form;
}
private function createGroupDetailsForm($parent)
{
$group = Config::request('editItem');
new Header($parent, $group);
$users = Login::users();
$memberUsers = Login::usersOfGroup($group);
new ExternalJavaScript($parent, 'resources/plugins/Frontends/Admin/adminScripts.js');
new Paragraph($parent, i18n('Select the users which should be a member of this group.'));
$form = new Form($parent, Config::globals('baseURL').'?action=EditGroup');
$form->useGridLayout(true);
$form->addJavaScript('onsubmit', 'updateSelectedUsers();');
$groupNameInput = new HiddenInput($form, 'groupName');
$groupNameInput->setValue($group);
$usersInput = new SelectInput($form, 'usersSelect');
$usersInput->setMultiple(true, 10);
$usersInput->setText(i18n('Users:'));
$usersInput->addCssStyle('width: 15em');
foreach($users as $user)
{
$usersInput->addOption($user, $user, in_array($user, $memberUsers));
}
$box = new Box($form);
$box->setOrientation('horizontal');
$button = new Button($box, 'button');
$button->setValue(i18n('OK'));
$button->setConfirm(true);
$button = new Button($box, 'button');
$button->setValue(i18n('Cancel'));
return $form;
}
private function createUserGroupOverview($parent)
{
$action = Config::request('action');
if($action == 'AddUser' || $action == 'EditUser' || $action == 'DeleteUser' ||
$action == 'AddGroup' || $action == 'EditGroup' || $action == 'DeleteGroup')
{
new JavaScript($parent, 'document.location = \''.Config::globals('baseURL').'\';');
return;
}
$users = array();
foreach(Login::users() as $user)
{
$users[$user] = htmlspecialchars(Login::fullName($user));
}
$groups = array_combine(array_values(Login::groups()), array_values(Login::groups()));
asort($users);
asort($groups);
new ExternalJavaScript($parent, 'resources/plugins/Frontends/Admin/adminScripts.js');
$gridLayout = new GridLayout($parent, 2);
$gridLayout->addCssStyle('width: 75%');
$form = new Form($gridLayout, Config::globals('baseURL').'?view=EditUser&action=DeleteUser');
$form->addCssStyle('width: 50%');
$paragraph = new Paragraph($form, i18n('Users:'));
$paragraph->addCssStyle('font-weight: bold');
$columnLayout = new GridLayout($form, 2);
$usersInput = new SelectInput($columnLayout, 'usersSelect');
$usersInput->setMultiple(true, 10);
$usersInput->setOptions($users);
$usersInput->addJavaScript('onchange', 'updateButtons(\'user\');');
$usersInput->addCssStyle('width: 15em');
$box = new Box($columnLayout);
$box->setOrientation('vertical');
$button = new Button($box, 'userAddButton');
$button->setValue(i18n('Add User'));
$button->addCssStyle('width: 100%; margin-bottom: 4px');
$button = new Button($box, 'userEditButton');
$button->setValue(i18n('Edit User'));
$button->setEnabled(false);
$button->addCssStyle('width: 100%; margin-bottom: 4px');
$button = new Button($box, 'userDeleteButton');
$button->addJavaScript('onclick', 'return confirmDelete(\'user\');');
$button->setValue(i18n('Delete User(s)'));
$button->setEnabled(false);
$button->addCssStyle('width: 100%');
$columnLayout->cell(0, 1)->addCssStyle('vertical-align: top');
$form = new Form($gridLayout, Config::globals('baseURL').'?view=EditGroup&action=DeleteGroup');
$form->addCssStyle('width: 50%');
$paragraph = new Paragraph($form, i18n('Groups:'));
$paragraph->addCssStyle('font-weight: bold');
$columnLayout = new GridLayout($form, 2);
$groupsInput = new SelectInput($columnLayout, 'groupsSelect');
$groupsInput->setMultiple(true, 10);
$groupsInput->setOptions($groups);
$groupsInput->addJavaScript('onchange', 'updateButtons(\'group\');');
$groupsInput->addCssStyle('width: 15em');
$box = new Box($columnLayout);
$box->setOrientation('vertical');
$button = new Button($box, 'groupAddButton');
$button->setValue(i18n('Add Group'));
$button->addCssStyle('width: 100%; margin-bottom: 4px');
$button = new Button($box, 'groupEditButton');
$button->setValue(i18n('Edit Group'));
$button->setEnabled(false);
$button->addCssStyle('width: 100%; margin-bottom: 4px');
$button = new Button($box, 'groupDeleteButton');
$button->addJavaScript('onclick', 'return confirmDelete(\'group\');');
$button->setValue(i18n('Delete Group(s)'));
$button->setEnabled(false);
$button->addCssStyle('width: 100%');
$columnLayout->cell(0, 1)->addCssStyle('vertical-align: top');
return $gridLayout;
}
public function showGUI()
{
$this->mainWindow->show();
}
private $mainWindow;
private $originalBaseURL;
}
?>