Merge pull request #101 from LDAPAccountManager/configImportExport

Config import export
This commit is contained in:
gruberroland 2020-06-17 13:05:01 +02:00 committed by GitHub
commit 55ccddbf1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1986 additions and 193 deletions

View File

@ -4,6 +4,7 @@
"squizlabs/php_codesniffer" : "3.4.0"
},
"require": {
"ext-ldap": "*"
"ext-ldap": "*",
"ext-json": "*"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -1752,6 +1752,16 @@ function getLAMVersionText() {
return $text . ' - ' . LAMVersion();
}
/**
* Returns if the given release is a developer version.
*
* @param string version
* @return bool is developer version
*/
function isDeveloperVersion($version) {
return strpos($version, 'DEV') !== false;
}
/**
* LAM exception with title and message.
*

View File

@ -649,6 +649,78 @@ class LAMConfig {
$this->reload();
}
/**
* Returns the server profile data.
*
* @return array data
*/
public function exportData() {
$data = array();
$settingsToIgnore = array('modules', 'types', 'tools', 'jobs');
foreach ($this->settings as $setting) {
if (in_array($setting, $settingsToIgnore)) {
continue;
}
$data[$setting] = $this->$setting;
}
$data['typeSettings'] = $this->typeSettings;
$data['moduleSettings'] = $this->moduleSettings;
$data['toolSettings'] = $this->toolSettings;
$data['jobSettings'] = $this->jobSettings;
if ($this->jobsDatabase === 'SQLite') {
$dbFileName = __DIR__ . '/../config/' . $this->getName() . '.sqlite';
if (is_file($dbFileName) && is_readable($dbFileName)) {
$file = @fopen($dbFileName, "r");
if ($file) {
$dbData = fread($file, 100000000);
fclose($file);
$data['jobSQLite'] = base64_encode($dbData);
}
}
}
return $data;
}
/**
* Imports server profile data.
*
* @param array $data config data
* @throws LAMException import error
*/
public function importData($data) {
$settingsToIgnore = array('modules', 'types', 'tools', 'jobs', 'typeSettings',
'moduleSettings', 'toolSettings', 'jobSettings', 'jobSQLite');
foreach ($data as $dataKey => $dataValue) {
if (in_array($dataKey, $settingsToIgnore)) {
continue;
}
if (!in_array($dataKey, $this->settings)) {
logNewMessage(LOG_WARNING, 'Ignored setting during import: ' . $dataKey);
continue;
}
if (!(($dataValue === null) || is_array($dataValue) || is_string($dataValue) || is_int($dataValue) || is_bool($dataValue))) {
throw new LAMException('Invalid import data type for ' . htmlspecialchars($dataKey) . ': ' . gettype($dataValue));
}
$this->$dataKey = $dataValue;
}
$typeSettingsData = !empty($data['typeSettings']) && is_array($data['typeSettings']) ? $data['typeSettings'] : array();
$this->typeSettings = $typeSettingsData;
$moduleSettingsData = !empty($data['moduleSettings']) && is_array($data['moduleSettings']) ? $data['moduleSettings'] : array();
$this->moduleSettings = $moduleSettingsData;
$toolSettingsData = !empty($data['toolSettings']) && is_array($data['toolSettings']) ? $data['toolSettings'] : array();
$this->toolSettings = $toolSettingsData;
$jobSettingsData = !empty($data['jobSettings']) && is_array($data['jobSettings']) ? $data['jobSettings'] : array();
$this->jobSettings = $jobSettingsData;
if (!empty($data['jobSQLite'])) {
$dbFileName = __DIR__ . '/../config/' . $this->getName() . '.sqlite';
$file = @fopen($dbFileName, "wb");
if ($file) {
fputs($file, base64_decode($data['jobSQLite']));
fclose($file);
}
}
}
/**
* Reloads preferences from config file
*
@ -759,6 +831,10 @@ class LAMConfig {
/** Saves preferences to config file */
public function save() {
$conffile = $this->getPath();
if (!file_exists($conffile)) {
$newFile = fopen($conffile, 'wb');
fclose($newFile);
}
if (is_file($conffile) && is_readable($conffile)) {
$file = fopen($conffile, "r");
$file_array = array();
@ -1775,7 +1851,7 @@ class LAMConfig {
/**
* Returns a list of active account types.
*
* @return array list of types
* @return string[] list of types
*/
public function get_ActiveTypes() {
if (($this->activeTypes == '') || !isset($this->activeTypes)) {
@ -1789,7 +1865,7 @@ class LAMConfig {
/**
* Sets the list of active types.
*
* @param array list of types
* @param string[] list of types
*/
public function set_ActiveTypes($types) {
$this->activeTypes = implode(",", $types);
@ -2681,6 +2757,83 @@ class LAMCfgMain {
$this->reload();
}
/**
* Exports the configuration data.
*
* @return array config data
*/
public function exportData() {
$data = array();
foreach ($this->settings as $setting) {
$data[$setting] = $this->$setting;
}
return $data;
}
/**
* Imports configuration data.
*
* @param array $data config data
* @throws LAMException import error
*/
public function importData($data) {
foreach ($data as $dataKey => $dataValue) {
if (!in_array($dataKey, $this->settings)) {
logNewMessage(LOG_WARNING, 'Ignored setting during import: ' . $dataKey);
continue;
}
if (!(($dataValue === null) || is_array($dataValue) || is_string($dataValue) || is_int($dataValue) || is_bool($dataValue))) {
throw new LAMException('Invalid import data type for ' . htmlspecialchars($dataKey) . ': ' . gettype($dataValue));
}
$this->$dataKey = $dataValue;
}
}
/**
* Returns the content of the server certificates file
*
* @return null|string certificates
*/
public function exportCertificates() {
$fileName = $this->getSSLCaCertPath();
if ($fileName === null) {
return null;
}
$content = null;
$handle = @fopen($fileName, "r");
if ($handle) {
$content = fread($handle, 10000000);
fclose($handle);
}
return $content;
}
/**
* Imports the server certificates.
*
* @param null|string $certsContent certificates
* @throws LAMException write to file failed
*/
public function importCertificates($certsContent) {
$fileName = $this->getSSLCaCertPath();
if (empty($certsContent)) {
if ($fileName !== null) {
unlink($fileName);
}
return;
}
$fileName = $this->getInternalSSLCaCertFileName();
$handle = @fopen($fileName, "wb");
if ($handle) {
fputs($handle, $certsContent);
fclose($handle);
@chmod($fileName, 0600);
}
else {
throw new LAMException(printf(_('Unable to write file %s.'), $fileName));
}
}
/**
* Reloads preferences from config file config.cfg
*

View File

@ -3082,6 +3082,15 @@ class htmlStatusMessage extends htmlElement {
return array();
}
/**
* Returns the message type.
*
* @return String type
*/
public function getType() {
return $this->type;
}
}
/**
@ -3644,6 +3653,8 @@ class htmlSpan extends htmlElement {
/** htmlElement that generates inner content */
private $content = null;
/** onclick handler */
private $onclick = null;
/**
* Constructor.
@ -3674,13 +3685,27 @@ class htmlSpan extends htmlElement {
if (($this->cssClasses != null) && (sizeof($this->cssClasses) > 0)) {
$classesValue = ' class="' . implode(' ', $this->cssClasses) . '"';
}
echo '<span' . $classesValue . '>';
$onclickHandler = '';
if (!empty($this->onclick)) {
$onclickHandler = ' onclick="' . $this->onclick . '"';
}
echo '<span' . $classesValue . $onclickHandler . '>';
if ($this->content != null) {
$return = $this->content->generateHTML($module, $input, $values, $restricted, $tabindex, $scope);
}
echo '</span>';
return $return;
}
/**
* Sets the onclick event.
*
* @param string $event event handler code
*/
public function setOnclick($event) {
$this->onclick = $event;
}
}
/**
@ -4715,6 +4740,8 @@ class htmlResponsiveInputCheckbox extends htmlInputCheckbox {
private $renderParentHtml = false;
/** long label */
private $longLabel = false;
/** label after checkbox */
private $labelAfterCheckbox = false;
/**
* Constructor.
@ -4751,14 +4778,16 @@ class htmlResponsiveInputCheckbox extends htmlInputCheckbox {
$row = new htmlResponsiveRow();
$tabletColumnsLabel = 6;
$tabletColumnsBox = 6;
$mobileColumnsLabel = 10;
$mobileColumnsBox = 2;
if ($this->longLabel) {
$tabletColumnsLabel = 10;
$tabletColumnsBox = 2;
}
// label text
$labelGroup = new htmlGroup();
$labelGroup->addElement(new htmlOutputText($this->label));
$row->add($labelGroup, 10, $tabletColumnsLabel, $tabletColumnsLabel, 'responsiveLabel');
$text = new htmlSpan(new htmlOutputText($this->label));
$text->setCSSClasses($this->cssClasses);
$text->setOnclick('jQuery(\'#' . $this->name . '\').prop(\'checked\',!jQuery(\'#' . $this->name . '\').prop(\'checked\')); jQuery(\'#' . $this->name . '\').change();');
// input field
$fieldGroup = new htmlGroup();
$fieldGroup->addElement($this);
@ -4767,7 +4796,14 @@ class htmlResponsiveInputCheckbox extends htmlInputCheckbox {
$helpLink->setCSSClasses(array('margin-left5 align-unset-img'));
$fieldGroup->addElement($helpLink);
}
$row->add($fieldGroup, 2, $tabletColumnsBox, $tabletColumnsBox, 'responsiveField nowrap');
if ($this->labelAfterCheckbox) {
$row->add($fieldGroup, $mobileColumnsBox, $tabletColumnsBox, $tabletColumnsBox, 'responsiveLabel nowrap');
$row->add($text, $mobileColumnsLabel, $tabletColumnsLabel, $tabletColumnsLabel, 'responsiveField');
}
else {
$row->add($text, $mobileColumnsLabel, $tabletColumnsLabel, $tabletColumnsLabel, 'responsiveLabel');
$row->add($fieldGroup, $mobileColumnsBox, $tabletColumnsBox, $tabletColumnsBox, 'responsiveField nowrap');
}
return $row->generateHTML($module, $input, $values, $restricted, $tabindex, $scope);
}
@ -4779,6 +4815,15 @@ class htmlResponsiveInputCheckbox extends htmlInputCheckbox {
return '.row';
}
/**
* Sets if the label should be shown after the checkbox instead before it.
*
* @param bool $labelAfterCheckbox show label after box
*/
public function setLabelAfterCheckbox($labelAfterCheckbox = true) {
$this->labelAfterCheckbox = $labelAfterCheckbox;
}
}
/**

View File

@ -759,7 +759,7 @@ class lamList {
$selAccounts[] = $id;
}
// get possible PDF structures
$pdf_structures = \LAM\PDF\getPDFStructures($this->type->getId());
$pdf_structures = \LAM\PDF\getPDFStructures($this->type->getId(), $_SESSION['config']->getName());
$this->printHeader();

View File

@ -1454,7 +1454,7 @@ class accountContainer {
*/
private function loadProfileIfRequested() {
if (isset($_POST['accountContainerLoadProfile']) && isset($_POST['accountContainerSelectLoadProfile'])) {
$profile = \LAM\PROFILES\loadAccountProfile($_POST['accountContainerSelectLoadProfile'], $this->type->getId());
$profile = \LAM\PROFILES\loadAccountProfile($_POST['accountContainerSelectLoadProfile'], $this->type->getId(), $_SESSION['config']->getName());
$this->lastLoadedProfile = $_POST['accountContainerSelectLoadProfile'];
// pass profile to each module
$modules = array_keys($this->module);
@ -1775,7 +1775,7 @@ class accountContainer {
$this->lastLoadedProfile = $cookieProfileName;
}
}
$profile = \LAM\PROFILES\loadAccountProfile($profileName, $this->type->getId());
$profile = \LAM\PROFILES\loadAccountProfile($profileName, $this->type->getId(), $_SESSION['config']->getName());
// pass profile to each module
$modules = array_keys($this->module);
foreach ($modules as $module) $this->module[$module]->load_profile($profile);

View File

@ -61,7 +61,7 @@ include_once('pdfstruct.inc');
function createModulePDF($accounts, $pdf_structure, $font, $returnAsString = false) {
$account_type = $accounts[0]->get_type();
// Get PDF structure from xml file
$reader = new PDFStructureReader();
$reader = new PDFStructureReader($_SESSION['config']->getName());
$structure = $reader->read($account_type->getId(), $pdf_structure);
// get list of PDF keys
$pdfKeys = array();

View File

@ -34,6 +34,11 @@ use \LAM\ImageUtils\ImageManipulationFactory;
/** LAM configuration */
include_once(__DIR__ . "/config.inc");
/**
* Use as server profile name to manage global templates.
*/
const GLOBAL_PROFILE = '__GLOBAL__';
/** LDAP object */
include_once(__DIR__ . "/ldap.inc");
@ -44,18 +49,15 @@ include_once(__DIR__ . "/ldap.inc");
* @param string $typeId the account type
* @param string $profile server profile name
*
* @return array All available PDF structure definitions for the submitted account
* @return string[] All available PDF structure definitions for the submitted account
* scope. Each entry is a string being the filename that may be passed to the
* createModulePDF() function as second argument.
*/
function getPDFStructures($typeId, $profile = null) {
function getPDFStructures($typeId, $profile) {
$return = array();
if (!preg_match('/[a-zA-Z]+/', $typeId)) {
return null;
}
if (!isset($profile)) {
$profile = $_SESSION['config']->getName();
}
$path = dirname(__FILE__) . '/../config/pdf/' . $profile;
if(is_dir($path)) {
$dirHandle = opendir($path);
@ -75,14 +77,14 @@ function getPDFStructures($typeId, $profile = null) {
*
* @param string $typeId account type
* @param string $name Name of definition to delete
*
* @param string $serverProfileName server profile name
* @return boolean True if file was deleted or false if a problem occurred.
*/
function deletePDFStructure($typeId, $name) {
function deletePDFStructure($typeId, $name, $serverProfileName) {
if (!isValidPDFStructureName($name) || !preg_match('/[a-zA-Z]+/',$typeId)) {
return false;
}
$file = dirname(__FILE__) . '/../config/pdf/' . $_SESSION['config']->getName() . '/' . $name . '.' . $typeId . '.xml';
$file = dirname(__FILE__) . '/../config/pdf/' . $serverProfileName . '/' . $name . '.' . $typeId . '.xml';
if(is_file($file) && is_writable($file)) {
return unlink($file);
}
@ -95,11 +97,12 @@ function deletePDFStructure($typeId, $name) {
/**
* This function returns an array with all aviliable logo images.
*
* @return array list of logo files
* @param string $serverProfileName server profile name
* @return array list of logo files (array('filename' => PATH, 'infos' => array(width, height)))
*/
function getAvailableLogos() {
function getAvailableLogos($serverProfileName) {
$return = array();
$dirPath = dirname(__FILE__) . '/../config/pdf/' . $_SESSION['config']->getName() . '/logos/';
$dirPath = dirname(__FILE__) . '/../config/pdf/' . $serverProfileName . '/logos/';
$dirHandle = opendir($dirPath);
while($file = readdir($dirHandle)) {
if(!is_dir($file) && $file != '.' && $file != '..' && preg_match('/\\.(jpg|png)$/i',$file)) {
@ -120,7 +123,7 @@ function getAvailableLogos() {
* @param \LAM\TYPES\ConfiguredType $sourceType source type
* @param string $sourceStructureName structure name
* @param \LAM\TYPES\ConfiguredType $targetType target type
* @throws Exception
* @throws LAMException error during copy
*/
function copyStructure($sourceType, $sourceStructureName, $targetType) {
if (!isValidPDFStructureName($sourceStructureName)) {
@ -165,13 +168,17 @@ function copyStructureToTemplates($sourceType, $sourceName) {
*
* @param String $file full path of temporary file
* @param String $name file name
* @return StatusMessage status message to display
* @param string $serverProfileName server profile name
* @return htmlStatusMessage status message to display
*/
function uploadPDFLogo($file, $name) {
function uploadPDFLogo($file, $name, $serverProfileName) {
if (!preg_match('/[a-zA-Z0-9_-]+\\.(png)|(jpg)/i', $name)) {
return new htmlStatusMessage('ERROR', _('Unable to upload logo file.'), _('The file name must end with ".png" or ".jpg".'));
}
$dirPath = dirname(__FILE__) . '/../config/pdf/' . $_SESSION['config']->getName() . '/logos/';
if ($serverProfileName === GLOBAL_PROFILE) {
$serverProfileName = '../templates/pdf';
}
$dirPath = dirname(__FILE__) . '/../config/pdf/' . $serverProfileName . '/logos/';
$success = copy($file, $dirPath . '/' . $name);
if ($success) {
return new htmlStatusMessage('INFO', _('Uploaded logo file.'), $name);
@ -185,12 +192,13 @@ function uploadPDFLogo($file, $name) {
* Deletes a PDF logo file.
*
* @param String $name file name
* @param string $serverProfileName server profile name
* @return StatusMessage status message to display
*/
function deletePDFLogo($name) {
function deletePDFLogo($name, $serverProfileName) {
// check if valid file
$found = false;
$logos = getAvailableLogos();
$logos = getAvailableLogos($serverProfileName);
foreach ($logos as $logo) {
if ($logo['filename'] === $name) {
$found = true;
@ -203,9 +211,9 @@ function deletePDFLogo($name) {
// check if still in use
$typeManager = new \LAM\TYPES\TypeManager();
$activeTypes = $typeManager->getConfiguredTypes();
$reader = new PDFStructureReader();
$reader = new PDFStructureReader($serverProfileName);
foreach ($activeTypes as $type) {
$structures = getPDFStructures($type->getId());
$structures = getPDFStructures($type->getId(), $serverProfileName);
foreach ($structures as $structure) {
try {
$data = $reader->read($type->getId(), $structure);
@ -220,7 +228,7 @@ function deletePDFLogo($name) {
}
}
// delete file
$dirPath = dirname(__FILE__) . '/../config/pdf/' . $_SESSION['config']->getName() . '/logos/';
$dirPath = dirname(__FILE__) . '/../config/pdf/' . $serverProfileName . '/logos/';
$success = @unlink($dirPath . '/' . $name);
if ($success) {
return new htmlStatusMessage('INFO', _('Logo file deleted.'), $name);
@ -242,21 +250,8 @@ function isValidPDFStructureName($name) {
* Installs template structures to the current server profile.
*/
function installPDFTemplates() {
$templatePath = dirname(__FILE__) . '/../config/templates/pdf';
$templateDir = @dir($templatePath);
$allTemplates = array();
if ($templateDir) {
$entry = $templateDir->read();
while ($entry){
$parts = explode('.', $entry);
if ((strlen($entry) > 3) && (sizeof($parts) == 3)) {
$name = $parts[0];
$scope = $parts[1];
$allTemplates[$scope][] = $name;
}
$entry = $templateDir->read();
}
}
$templatePath = __DIR__ . '/../config/templates/pdf';
$allTemplates = getPdfTemplateNames();
$basePath = dirname(__FILE__) . '/../config/pdf/' . $_SESSION['config']->getName();
if (!file_exists($basePath)) {
mkdir($basePath, 0700, true);
@ -278,20 +273,75 @@ function installPDFTemplates() {
if (!file_exists($basePath . '/logos')) {
mkdir($basePath . '/logos');
}
$templatePath = dirname(__FILE__) . '/../config/templates/pdf/logos';
$logos = getPdfTemplateLogoNames();
foreach ($logos as $logo) {
$path = $basePath . '/logos/' . $logo;
$template = $templatePath . '/logos/' . $logo;
if (!is_file($path)) {
logNewMessage(LOG_DEBUG, 'Copy template ' . $template . ' to ' . $path);
@copy($template, $path);
}
}
}
/**
* Returns all PDF template names.
*
* @return array names (array('user' => array('default')))
*/
function getPdfTemplateNames() {
$templatePath = __DIR__ . '/../config/templates/pdf';
$templateDir = @dir($templatePath);
$allTemplates = array();
if ($templateDir) {
$entry = $templateDir->read();
while ($entry){
$path = $basePath . '/logos/' . $entry;
if ((strpos($entry, '.') !== 0) && !is_file($path)) {
$template = $templatePath . '/' . $entry;
logNewMessage(LOG_DEBUG, 'Copy template ' . $template . ' to ' . $path);
@copy($template, $path);
$parts = explode('.', $entry);
if ((strlen($entry) > 3) && (sizeof($parts) == 3)) {
$name = $parts[0];
$scope = $parts[1];
$allTemplates[$scope][] = $name;
}
$entry = $templateDir->read();
}
}
return $allTemplates;
}
/**
* Returns all PDF template logo names.
*
* @return array names (array('user' => array('default.png')))
*/
function getPdfTemplateLogoNames() {
$templatePath = __DIR__ . '/../config/templates/pdf/logos';
$templateDir = @dir($templatePath);
$logos = array();
if ($templateDir) {
$entry = $templateDir->read();
while ($entry){
if ((strpos($entry, '.') !== 0) && is_file($templatePath . '/' . $entry)) {
$logos[] = $entry;
}
$entry = $templateDir->read();
}
}
return $logos;
}
/**
* Returns the binary data of the PDF template logo.
*
* @param string $name file name (without path)
* @return string binary
*/
function getPdfTemplateLogoBinary($name) {
$templatePath = __DIR__ . '/../config/templates/pdf/logos';
$fileName = $templatePath . '/' . $name;
$handle = fopen($fileName, 'r');
$logoBinary = fread($handle, 100000000);
fclose($handle);
return $logoBinary;
}
/**
@ -301,6 +351,22 @@ function installPDFTemplates() {
*/
class PDFStructureReader {
private $serverProfileName;
/**
* Constructor.
*
* @param $serverProfileName server profile name
*/
public function __construct($serverProfileName) {
if ($serverProfileName === GLOBAL_PROFILE) {
$this->serverProfileName = '../templates/pdf';
}
else {
$this->serverProfileName = $serverProfileName;
}
}
/**
* Reads a PDF structure.
*
@ -324,7 +390,7 @@ class PDFStructureReader {
* @return string file name
*/
protected function getFileName($typeId, $name) {
return dirname(__FILE__) . '/../config/pdf/' . $_SESSION['config']->getName() . '/' . $name . '.' . $typeId . '.xml';
return dirname(__FILE__) . '/../config/pdf/' . $this->serverProfileName . '/' . $name . '.' . $typeId . '.xml';
}
/**
@ -334,6 +400,7 @@ class PDFStructureReader {
* @return PDFStructure structure
*/
private function readPDFFile($file) {
logNewMessage(LOG_DEBUG, $file);
$xml = new \XMLReader();
$xml->open($file);
$structure = new PDFStructure();
@ -411,12 +478,29 @@ class PDFStructureReader {
*/
class PDFStructureWriter {
private $serverProfileName;
/**
* Constructor.
*
* @param string $serverProfileName server profile name
*/
public function __construct($serverProfileName) {
if ($serverProfileName === GLOBAL_PROFILE) {
$this->serverProfileName = '../templates/pdf';
}
else {
$this->serverProfileName = $serverProfileName;
}
}
/**
* Writes the PDF structure to disk.
*
* @param string $typeId type ID
* @param string $name structure name
* @param PDFStructure $structure structure
* @throws LAMException error during write
*/
public function write($typeId, $name, $structure) {
$fileName = $this->getFileName($typeId, $name);
@ -430,16 +514,18 @@ class PDFStructureWriter {
* @param string $typeId type ID
* @param string $name structure name
* @return string file name
* @throws LAMException file not valid or not writable
*/
protected function getFileName($typeId, $name) {
if (!isValidPDFStructureName($name) || !preg_match('/[a-zA-Z]+/', $typeId)) {
throw new \LAMException(_('PDF structure name not valid'),
_('The name for that PDF-structure you submitted is not valid. A valid name must consist of the following characters: \'a-z\',\'A-Z\',\'0-9\',\'_\',\'-\'.'));
}
if(!is_writable(dirname(__FILE__) . '/../config/pdf/' . $_SESSION['config']->getName())) {
throw new \LAMException(_('Could not save PDF structure, access denied.'));
$baseDir = __DIR__ . '/../config/pdf/' . $this->serverProfileName;
if(!is_writable($baseDir)) {
throw new \LAMException(_('Could not save PDF structure, access denied to ' . $baseDir . '.'));
}
return dirname(__FILE__) . '/../config/pdf/' . $_SESSION['config']->getName() . '/' . $name . '.' . $typeId . '.xml';
return $baseDir . '/' . $name . '.' . $typeId . '.xml';
}
/**
@ -488,6 +574,7 @@ class PDFStructureWriter {
*
* @param string $xml XML
* @param string $file file name
* @throws LAMException error during write
*/
protected function writeXML($xml, $file) {
$handle = @fopen($file,'w');
@ -520,6 +607,57 @@ class PDFStructure {
private $sections = array();
/**
* Returns an array representation of the structure.
*
* @return array export data
*/
public function export() {
$data = array();
$data['title'] = $this->title;
$data['foldingMarks'] = $this->foldingMarks;
$data['logo'] = $this->logo;
$data['sections'] = array();
foreach($this->sections as $section) {
$type = ($section instanceof PDFTextSection) ? 'text' : 'entry';
$sectionData = $section->export();
$data['sections'][] = array(
'type' => $type,
'data' => $sectionData
);
}
return $data;
}
/**
* Imports an array representation of the structure.
*
* @param array $data import data
*/
public function import($data) {
if (isset($data['title'])) {
$this->title = $data['title'];
}
if (isset($data['foldingMarks'])) {
$this->foldingMarks = $data['foldingMarks'];
}
if (isset($data['logo'])) {
$this->logo = $data['logo'];
}
if (isset($data['sections'])) {
foreach($data['sections'] as $section) {
if ($section['type'] === 'text') {
$this->sections[] = new PDFTextSection($section['data']);
}
else {
$entrySection = new PDFEntrySection(null);
$entrySection->import($section['data']);
$this->sections[] = $entrySection;
}
}
}
}
/**
* Returns the logo file path.
*
@ -612,6 +750,15 @@ class PDFTextSection {
$this->text = $text;
}
/**
* Exports the section.
*
* @return string text
*/
public function export() {
return $this->getText();
}
/**
* Returns the text.
*
@ -631,7 +778,7 @@ class PDFTextSection {
class PDFEntrySection {
private $title;
private $entries;
private $entries = array();
/**
* Constructor
@ -642,6 +789,37 @@ class PDFEntrySection {
$this->title = $title;
}
/**
* Exports the section.
*
* @return array export data
*/
public function export() {
$data = array();
$data['title'] = $this->title;
$data['entries'] = array();
foreach($this->getEntries() as $entry) {
$data['entries'][] = $entry->getKey();
}
return $data;
}
/**
* Imports the section.
*
* @param array $data import data
*/
public function import($data) {
if (isset($data['title'])) {
$this->title = $data['title'];
}
if ($data['entries']) {
foreach($data['entries'] as $entry) {
$this->entries[] = new PDFSectionEntry($entry);
}
}
}
/**
* Returns if the title is an attribute value.
*

652
lam/lib/persistence.inc Normal file
View File

@ -0,0 +1,652 @@
<?php
namespace LAM\PERSISTENCE;
use LAM\PDF\PDFStructure;
use LAM\PDF\PDFStructureReader;
use LAM\PDF\PDFStructureWriter;
use LAMCfgMain;
use LAMConfig;
use LAMException;
use selfServiceProfile;
use function LAM\PDF\getAvailableLogos;
use function LAM\PDF\getPDFStructures;
use function LAM\PDF\getPdfTemplateLogoBinary;
use function LAM\PDF\getPdfTemplateLogoNames;
use function LAM\PDF\getPdfTemplateNames;
use function LAM\PDF\uploadPDFLogo;
use function LAM\PROFILES\getAccountProfiles;
use function LAM\PROFILES\getProfileTemplateNames;
use function LAM\PROFILES\installTemplateAccountProfile;
use function LAM\PROFILES\loadAccountProfile;
use function LAM\PROFILES\loadTemplateAccountProfile;
use function LAM\PROFILES\saveAccountProfile;
/*
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2020 Roland Gruber
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
*/
/**
* This file includes functions to manage the persistence of LAM's configuration files.
*
* @package configuration
* @author Roland Gruber
*/
include_once __DIR__ . '/config.inc';
include_once __DIR__ . '/profiles.inc';
/**
* Exporter for LAM's configuration data.
*/
class ConfigDataExporter {
/**
* Exports LAM's configuration data in JSON format.
* @throws LAMException error during export
*/
public function exportAsJson() {
$mainCfg = $this->_getMainConfiguration();
$jsonData = array();
$jsonData['mainConfig'] = $this->_getMainConfigData($mainCfg);
$jsonData['certificates'] = $this->_getCertificates($mainCfg);
$serverProfileNames = getConfigProfiles();
$serverProfiles = array();
foreach ($serverProfileNames as $serverProfileName) {
$serverProfiles[$serverProfileName] = new \LAMConfig($serverProfileName);
}
$jsonData['serverProfiles'] = $this->_getServerProfiles($serverProfiles);
$jsonData['accountProfiles'] = $this->_getAccountProfiles($serverProfiles);
$jsonData['accountProfileTemplates'] = $this->_getAccountProfileTemplates();
$jsonData['pdfProfiles'] = $this->_getPdfProfiles($serverProfiles);
$jsonData['pdfProfileTemplates'] = $this->_getPdfProfileTemplates();
$jsonData['selfServiceProfiles'] = $this->_getSelfServiceProfiles();
/**
* TODO
*
* webauthn
*/
return json_encode($jsonData);
}
/**
* Returns the main configuration.
*
* @return LAMCfgMain main config
*/
public function _getMainConfiguration() {
return new LAMCfgMain();
}
/**
* Internal function to read master configuration.
*
* @param LAMCfgMain $mainCfg main config
* @return array data
*/
public function _getMainConfigData($mainCfg) {
return $mainCfg->exportData();
}
/**
* Returns the certificate file content.
*
* @param LAMCfgMain $mainCfg main config
* @return array data
*/
public function _getCertificates($mainCfg) {
return $mainCfg->exportCertificates();
}
/**
* Returns the content of the server profiles.
*
* @param array $serverProfiles list of server profiles (name => object)
* @return array $data
*/
public function _getServerProfiles($serverProfiles) {
$data = array();
foreach ($serverProfiles as $profileName => $serverProfile) {
$data[$profileName] = $serverProfile->exportData();
}
return $data;
}
/**
* Returns the content of the account profiles.
*
* @param array $serverProfiles list of server profiles (name => object)
* @return array $data
*/
public function _getAccountProfiles($serverProfiles) {
$data = array();
foreach ($serverProfiles as $profileName => $serverProfile) {
foreach ($serverProfile->get_ActiveTypes() as $typeId) {
$accountProfileNames = getAccountProfiles($typeId, $profileName);
foreach ($accountProfileNames as $accountProfileName) {
$accountProfile = loadAccountProfile($accountProfileName, $typeId, $profileName);
$data[$profileName][$typeId][$accountProfileName] = $accountProfile;
}
}
}
return $data;
}
/**
* Returns the content of the account profile templates.
*
* @return array $data
* @throws LAMException error reading template
*/
public function _getAccountProfileTemplates() {
$data = array();
$accountProfileTemplateNames = getProfileTemplateNames();
foreach ($accountProfileTemplateNames as $scope => $templateNames) {
foreach ($templateNames as $templateName) {
$accountProfileTemplate = loadTemplateAccountProfile($templateName, $scope);
$data[$scope][$templateName] = $accountProfileTemplate;
}
}
return $data;
}
/**
* Returns the content of the PDF profiles.
*
* @param array $serverProfiles list of server profiles (name => object)
* @return array $data
*/
public function _getPdfProfiles($serverProfiles) {
$data = array();
foreach ($serverProfiles as $profileName => $serverProfile) {
foreach ($serverProfile->get_ActiveTypes() as $typeId) {
$pdfProfileNames = getPDFStructures($typeId, $profileName);
$reader = new PDFStructureReader($profileName);
foreach ($pdfProfileNames as $pdfProfileName) {
$pdfStructure = $reader->read($typeId, $pdfProfileName);
$data[$profileName]['structures'][$typeId][$pdfProfileName] = $pdfStructure->export();
}
}
$logoData = getAvailableLogos($profileName);
foreach ($logoData as $logo) {
$logoFileName = $logo['filename'];
$logoPath = __DIR__ . '/../config/pdf/' . $profileName . '/logos/' . $logoFileName;
$handle = fopen($logoPath, 'r');
$logoBinary = fread($handle, 100000000);
fclose($handle);
$data[$profileName]['logos'][$logoFileName] = base64_encode($logoBinary);
}
}
return $data;
}
/**
* Returns the content of the account profile templates.
*
* @return array $data
* @throws LAMException error reading template
*/
public function _getPdfProfileTemplates() {
$data = array();
$pdfTemplateNames = getPdfTemplateNames();
$reader = new PDFStructureReader(\LAM\PDF\GLOBAL_PROFILE);
foreach ($pdfTemplateNames as $scope => $templateNames) {
foreach ($templateNames as $templateName) {
$pdfStructure = $reader->read($scope, $templateName);
$data['structures'][$scope][$templateName] = $pdfStructure->export();
}
}
$logoNames = getPdfTemplateLogoNames();
foreach ($logoNames as $logoName) {
$data['logos'][$logoName] = base64_encode(getPdfTemplateLogoBinary($logoName));
}
return $data;
}
/**
* Returns the content of the self service profiles.
*
* @return array data
*/
public function _getSelfServiceProfiles() {
$data = array();
$profileTypes = getSelfServiceProfiles();
foreach ($profileTypes as $profileType => $profileNames) {
foreach ($profileNames as $profileName) {
$profile = loadSelfServiceProfile($profileName, $profileType);
if ($profile === false) {
continue;
}
$data[$profileType][$profileName] = $profile->export();
}
}
return $data;
}
}
/**
* Importer for LAM's configuration data.
*/
class ConfigDataImporter {
/**
* Returns a list of possible import objects.
*
* @param string $json JSON data
* @return ImporterStep[] steps
* @throws LAMException if invalid format
*/
public function getPossibleImportSteps($json) {
$data = json_decode($json, true);
if ($data === null) {
throw new LAMException(_('Unable to read import file.'));
}
$steps = array();
foreach ($data as $key => $value) {
switch ($key) {
case 'mainConfig':
$steps[] = new ImporterStep(_('General settings'), 'mainConfig', $value);
break;
case 'certificates':
$steps[] = new ImporterStep(_('SSL certificates'), 'certificates', $value);
break;
case 'serverProfiles':
$mainStep = new ImporterStep(_('Server profiles'), 'serverProfiles', $value);
foreach ($value as $profileName => $profileData) {
$mainStep->addSubStep(new ImporterStep($profileName, 'serverProfile_' . $profileName, $profileData));
}
$steps[] = $mainStep;
break;
case 'accountProfiles':
$mainStep = new ImporterStep(_('Account profiles'), 'accountProfiles', $value);
foreach ($value as $profileName => $profileData) {
$mainStep->addSubStep(new ImporterStep($profileName, 'accountProfile_' . $profileName, $profileData));
}
$steps[] = $mainStep;
break;
case 'accountProfileTemplates':
$steps[] = new ImporterStep(_('Account profiles') . ' - ' . _('Global templates'), 'accountProfileTemplates', $value);
break;
case 'pdfProfiles':
$mainStep = new ImporterStep(_('PDF structures'), 'pdfProfiles', $value);
foreach ($value as $profileName => $profileData) {
$mainStep->addSubStep(new ImporterStep($profileName, 'pdfProfile_' . $profileName, $profileData));
}
$steps[] = $mainStep;
break;
case 'pdfProfileTemplates':
$steps[] = new ImporterStep(_('PDF structures') . ' - ' . _('Global templates'), 'pdfProfileTemplates', $value);
break;
case 'selfServiceProfiles':
$steps[] = new ImporterStep(_('Self service profiles'), 'selfServiceProfiles', $value);
break;
default:
logNewMessage(LOG_WARNING, 'Unknown import type: ' . $key);
}
}
if (empty($steps)) {
throw new LAMException(_('Unable to read import file.'));
}
return $steps;
}
/**
* Runs the actual import.
*
* @param ImporterStep[] $steps import steps
* @throws LAMException if error occurred
*/
public function runImport($steps) {
foreach ($steps as $step) {
if (!$step->isActive()) {
continue;
}
$key = $step->getKey();
switch ($key) {
case 'mainConfig':
$this->importMainConfig($step->getValue());
break;
case 'certificates':
$this->importCertificates($step->getValue());
break;
case 'serverProfiles':
$this->importServerProfiles($step);
break;
case 'accountProfiles':
$this->importAccountProfiles($step);
break;
case 'accountProfileTemplates':
$this->importAccountProfileTemplates($step);
break;
case 'pdfProfiles':
$this->importPdfProfiles($step);
break;
case 'pdfProfileTemplates':
$this->importPdfProfileTemplates($step);
break;
case 'selfServiceProfiles':
$this->importSelfServiceProfiles($step);
break;
default:
logNewMessage(LOG_WARNING, 'Unknown import type: ' . $key);
}
}
}
/**
* Imports the main configuration.
*
* @param array $data main config data
* @throws LAMException error during import
*/
private function importMainConfig($data) {
$cfgMain = new LAMCfgMain();
$cfgMain->importData($data);
$cfgMain->save();
}
/**
* Imports the SSL certificates.
*
* @param null|string $data file content
* @throws LAMException error during import
*/
private function importCertificates($data) {
$cfgMain = new LAMCfgMain();
$cfgMain->importCertificates($data);
}
/**
* Imports the server profiles.
*
* @param ImporterStep $step step
* @throws LAMException error during import
*/
private function importServerProfiles($step) {
$failedProfiles = array();
foreach ($step->getSubSteps() as $profileStep) {
if (!$profileStep->isActive()) {
continue;
}
$data = $profileStep->getValue();
$profileName = str_replace('serverProfile_', '', $profileStep->getKey());
$serverProfile = new LAMConfig($profileName);
$serverProfile->importData($data);
$result = $serverProfile->save();
if ($result === LAMConfig::SAVE_FAIL) {
$failedProfiles[] = $profileName;
}
}
if (!empty($failedProfiles)) {
throw new LAMException(_('Unable to save server profile.'), implode(', ', $failedProfiles));
}
}
/**
* Imports the account profiles.
*
* @param ImporterStep $step step
* @throws LAMException error during import
*/
private function importAccountProfiles($step) {
$failedProfiles = array();
foreach ($step->getSubSteps() as $profileStep) {
if (!$profileStep->isActive()) {
continue;
}
$data = $profileStep->getValue();
$serverProfileName = str_replace('accountProfile_', '', $profileStep->getKey());
$serverProfile = new LAMConfig($serverProfileName);
foreach ($data as $typeId => $accountProfiles) {
foreach ($accountProfiles as $accountProfileName => $accountProfileData) {
$result = saveAccountProfile($accountProfileData, $accountProfileName, $typeId, $serverProfile);
if (!$result) {
$failedProfiles[] = $serverProfileName . ':' . $typeId . ':' . $accountProfileName;
}
}
}
}
if (!empty($failedProfiles)) {
throw new LAMException(_('Unable to save account profile.'), implode(', ', $failedProfiles));
}
}
/**
* Imports the account profile templates.
*
* @param ImporterStep $step step
* @throws LAMException error during import
*/
private function importAccountProfileTemplates($step) {
$data = $step->getValue();
foreach ($data as $typeId => $accountProfileTemplates) {
foreach ($accountProfileTemplates as $accountProfileTemplateName => $accountProfileData) {
installTemplateAccountProfile($typeId, $accountProfileTemplateName, $accountProfileData);
}
}
}
/**
* Imports the PDF profiles.
*
* @param ImporterStep $step step
* @throws LAMException error during import
*/
private function importPdfProfiles($step) {
$failedProfiles = array();
foreach ($step->getSubSteps() as $profileStep) {
if (!$profileStep->isActive()) {
continue;
}
$data = $profileStep->getValue();
$serverProfileName = str_replace('pdfProfile_', '', $profileStep->getKey());
if (isset($data['structures'])) {
$writer = new PDFStructureWriter($serverProfileName);
foreach ($data['structures'] as $typeId => $pdfProfiles) {
foreach ($pdfProfiles as $pdfProfileName => $pdfProfileData) {
$structure = new PDFStructure();
$structure->import($pdfProfileData);
try {
$writer->write($typeId, $pdfProfileName, $structure);
}
catch (LAMException $e) {
logNewMessage(LOG_ERR, $e->getTitle() . ' ' . $e->getMessage());
$failedProfiles[] = $serverProfileName . ':' . $typeId . ':' . $pdfProfileName;
}
}
}
}
if (isset($data['logos'])) {
foreach ($data['logos'] as $logoFileName => $logoData) {
$tempFilePath = tempnam("/tmp", "lam");
$tempFile = fopen($tempFilePath, "w");
$logoBinary = base64_decode($logoData);
fwrite($tempFile, $logoBinary);
fclose($tempFile);
uploadPDFLogo($tempFilePath, $logoFileName, $serverProfileName);
unlink($tempFilePath);
}
}
}
if (!empty($failedProfiles)) {
throw new LAMException(_('Could not save PDF structure, access denied.'), implode(', ', $failedProfiles));
}
}
/**
* Imports the PDF profile templates.
*
* @param ImporterStep $step step
* @throws LAMException error during import
*/
private function importPdfProfileTemplates($step) {
$failedNames = array();
$data = $step->getValue();
if (isset($data['structures'])) {
$writer = new PDFStructureWriter(\LAM\PDF\GLOBAL_PROFILE);
foreach ($data['structures'] as $typeId => $pdfProfiles) {
foreach ($pdfProfiles as $pdfProfileName => $pdfProfileData) {
$structure = new PDFStructure();
$structure->import($pdfProfileData);
try {
$writer->write($typeId, $pdfProfileName, $structure);
}
catch (LAMException $e) {
$failedNames[] = $typeId . ':' . $pdfProfileName;
logNewMessage(LOG_ERR, $e->getTitle() . ' ' . $e->getMessage());
}
}
}
}
$failedLogos = array();
if (isset($data['logos'])) {
foreach ($data['logos'] as $logoFileName => $logoData) {
$tempFilePath = tempnam("/tmp", "lam");
$tempFile = fopen($tempFilePath, "w");
$logoBinary = base64_decode($logoData);
fwrite($tempFile, $logoBinary);
fclose($tempFile);
$message = uploadPDFLogo($tempFilePath, $logoFileName, \LAM\PDF\GLOBAL_PROFILE);
unlink($tempFilePath);
if ($message->getType() === 'ERROR') {
$failedLogos[] = $logoFileName;
}
}
}
if (!empty($failedNames)) {
throw new LAMException(_('Could not save PDF structure, access denied.'), implode(', ', $failedNames));
}
if (!empty($failedLogos)) {
throw new LAMException(_('Unable to upload logo file.'), implode(', ', $failedLogos));
}
}
/**
* Imports the self service profiles.
*
* @param ImporterStep $step importer step
* @throws LAMException error saving profiles
*/
private function importSelfServiceProfiles($step) {
$failedNames = array();
$data = $step->getValue();
foreach ($data as $typeId => $profileData