array(cn => ..., description => ...))) */ private $printerCache = null; /** printer group cache */ private $groupCache = null; /** list of pass through options: label => value */ private $passThroughOptions; /** * Creates a new pykotaPrinter object. * * @param string $scope account type (user, group, host) */ function __construct($scope) { $this->passThroughOptions = array( _('Yes') => 't', _('No') => 'f', ); // call parent constructor parent::__construct($scope); } /** * Returns true if this module can manage accounts of the current type, otherwise false. * * @return boolean true if module fits */ public function can_manage() { return in_array($this->get_scope(), array('pykotaPrinterType')); } /** * Returns meta data that is interpreted by parent class * * @return array array with meta data * * @see baseModule::get_metaData() */ function get_metaData() { $return = array(); // icon $return['icon'] = 'printerBig.png'; // alias name $return["alias"] = _("PyKota"); // this is a base module $return["is_base"] = true; // RDN attribute $return["RDN"] = array("cn" => "high"); // LDAP filter $return["ldap_filter"] = array('or' => "(objectClass=pykotaPrinter)"); // module dependencies $return['dependencies'] = array('depends' => array(), 'conflicts' => array()); // managed object classes $return['objectClasses'] = array('pykotaObject', 'pykotaPrinter'); // managed attributes $return['attributes'] = array('cn', 'description', 'pykotaMaxJobSize', 'pykotaPassThrough', 'pykotaPricePerJob', 'pykotaPricePerPage', 'pykotaPrinterName', 'uniqueMember'); // help Entries $return['help'] = array( 'cn' => array( "Headline" => _("Printer name"), 'attr' => 'cn', "Text" => _("Printer name of the printer which should be created. Valid characters are: a-z, A-Z, 0-9 and .-_ .") ), 'description' => array ( "Headline" => _("Description"), 'attr' => 'description', "Text" => _("Printer description.") ), 'pykotaMaxJobSize' => array( "Headline" => _('Maximum job size'), 'attr' => 'pykotaMaxJobSize', "Text" => _('The maximum number of pages per job allowed on the printer. 0 means unlimited.') ), 'pykotaPassThrough' => array( "Headline" => _('Passthrough'), 'attr' => 'pykotaPassThrough', "Text" => _('In passthrough mode, users are allowed to print without any impact on their quota or account balance.') ), 'pykotaPricePerJob' => array( "Headline" => _('Price per job'), 'attr' => 'pykotaPricePerJob', "Text" => _('The price for each print job.') ), 'pykotaPricePerPage' => array( "Headline" => _('Price per page'), 'attr' => 'pykotaPricePerPage', "Text" => _('The price for each page of a print job.') ), 'uniqueMember' => array( "Headline" => _('Group members'), 'attr' => 'uniqueMember', "Text" => _('If this entry should be a printer group then you can set the member names here.') ), 'uniqueMemberUpload' => array( "Headline" => _('Group members'), 'attr' => 'uniqueMember', "Text" => _('If this entry should be a printer group then you can set the member names here.') . ' ' . _('Multiple values are separated by comma.') ), 'filter' => array( "Headline" => _("Filter"), "Text" => _("Here you can enter a filter value. Only entries which contain the filter text will be shown.") . ' ' . _('Possible wildcards are: "*" = any character, "^" = line start, "$" = line end') ), ); // profile options $profileContainer = new htmlResponsiveRow(); $profileContainer->add(new htmlResponsiveInputField(_('Maximum job size'), 'pykotaPrinter_pykotaMaxJobSize', '', 'pykotaMaxJobSize'), 12); $return['profile_options'] = $profileContainer; $return['profile_mappings']['pykotaPrinter_pykotaMaxJobSize'] = 'pykotaMaxJobSize'; $return['profile_checks']['pykotaPrinter_pykotaMaxJobSize'] = array( 'type' => 'ext_preg', 'regex' => 'digit', 'error_message' => $this->messages['pykotaMaxJobSize'][0]); // upload fields $return['upload_columns'] = array( array( 'name' => 'pykotaPrinter_cn', 'description' => _('Printer name'), 'help' => 'cn', 'example' => _('printer01'), 'required' => true, ), array( 'name' => 'pykotaPrinter_description', 'description' => _('Description'), 'help' => 'description', 'example' => _('Color laser printer'), ), array( 'name' => 'pykotaPrinter_pykotaMaxJobSize', 'description' => _('Maximum job size'), 'help' => 'pykotaMaxJobSize', 'example' => '100', 'default' => '0', ), array( 'name' => 'pykotaPrinter_pykotaPassThrough', 'description' => _('Passthrough'), 'help' => 'pykotaPassThrough', 'example' => _('No'), 'default' => _('No'), 'values' => _('Yes') . ', ' . _('No'), ), array( 'name' => 'pykotaPrinter_pykotaPricePerJob', 'description' => _('Price per job'), 'help' => 'pykotaPricePerJob', 'example' => '0.01', ), array( 'name' => 'pykotaPrinter_pykotaPricePerPage', 'description' => _('Price per page'), 'help' => 'pykotaPricePerPage', 'example' => '0.01', ), array( 'name' => 'pykotaPrinter_uniqueMember', 'description' => _('Group members'), 'help' => 'uniqueMemberUpload', 'example' => _('printergroup1'), ), ); // available PDF fields $return['PDF_fields'] = array( 'cn' => _('Printer name'), 'description' => _('Description'), 'pykotaMaxJobSize' => _('Maximum job size'), 'pykotaPassThrough' => _('Passthrough'), 'pykotaPricePerJob' => _('Price per job'), 'pykotaPricePerPage' => _('Price per page'), 'uniqueMember' => _('Group members'), 'parentUniqueMember' => _('Printer groups'), ); return $return; } /** * This function fills the $messages variable with output messages from this module. */ function load_Messages() { $this->messages['cn'][0] = array('ERROR', _('Printer name'), _('Printer name contains invalid characters. Valid characters are: a-z, A-Z, 0-9 and .-_ !')); $this->messages['cn'][1] = array('ERROR', _('Account %s:') . ' pykotaPrinter_cn', _('Printer name contains invalid characters. Valid characters are: a-z, A-Z, 0-9 and .-_ !')); $this->messages['cn'][2] = array('ERROR', _('Printer name'), _('Printer name already exists!')); $this->messages['cn'][3] = array('ERROR', _('Account %s:') . ' pykotaPrinter_cn', _('Printer name already exists!')); $this->messages['pykotaMaxJobSize'][0] = array('ERROR', _('Maximum job size'), _('Please enter a valid number.')); $this->messages['pykotaMaxJobSize'][1] = array('ERROR', _('Account %s:') . ' pykotaPrinter_pykotaMaxJobSize', _('Please enter a valid number.')); $this->messages['pykotaPricePerJob'][0] = array('ERROR', _('Price per job'), _('Please enter a valid number (e.g. "1.5").')); $this->messages['pykotaPricePerJob'][1] = array('ERROR', _('Account %s:') . ' pykotaPrinter_pykotaPricePerJob', _('Please enter a valid number (e.g. "1.5").')); $this->messages['pykotaPricePerPage'][0] = array('ERROR', _('Price per page'), _('Please enter a valid number (e.g. "1.5").')); $this->messages['pykotaPricePerPage'][1] = array('ERROR', _('Account %s:') . ' pykotaPrinter_pykotaPricePerPage', _('Please enter a valid number (e.g. "1.5").')); $this->messages['pykotaPassThrough'][0] = array('ERROR', _('Account %s:') . ' pykotaPrinter_pykotaPassThrough', _('Please enter "Yes" or "No".')); $this->messages['uniqueMember'][0] = array('ERROR', _('Account %s:') . ' pykotaPrinter_uniqueMember', _('Unable to find a printer with name "%s".')); } /** * Returns the HTML meta data for the main account page. * * @return htmlElement HTML meta data */ function display_html_attributes() { $container = new htmlResponsiveRow(); // cn $this->addSimpleInputTextField($container, 'cn', _('Printer name'), true); // job size $this->addSimpleInputTextField($container, 'pykotaMaxJobSize', _('Maximum job size')); // price per job $this->addSimpleInputTextField($container, 'pykotaPricePerJob', _('Price per job')); // price per page $this->addSimpleInputTextField($container, 'pykotaPricePerPage', _('Price per page')); // passthrough $pykotaPassThroughOption = 'f'; if (!empty($this->attributes['pykotaPassThrough'][0])) { $pykotaPassThroughOption = $this->attributes['pykotaPassThrough'][0]; } $pykotaPassThroughSelect = new htmlResponsiveSelect('pykotaPassThrough', $this->passThroughOptions, array($pykotaPassThroughOption), _('Passthrough'), 'pykotaPassThrough'); $pykotaPassThroughSelect->setHasDescriptiveElements(true); $container->add($pykotaPassThroughSelect, 12); // description $this->addMultiValueInputTextField($container, 'description', _('Description'), false, null, true); // printer groups if (!$this->getAccountContainer()->isNewAccount) { $groups = $this->getPrinterGroups(); $this->loadPrinterNameCache(); $parentPrinters = array(); foreach ($groups as $groupDN) { $parentPrinters[] = $this->printerCache[$groupDN]['cn']; } if (sizeof($parentPrinters) > 0) { $container->addLabel(new htmlOutputText(_('Printer groups'))); $parentPrinterText = new htmlOutputText(implode(', ', $parentPrinters)); $container->addField($parentPrinterText, true); } } // printer members $memberLabel = new htmlOutputText(_('Group members')); $container->addLabel($memberLabel); $addMemberButton = new htmlAccountPageButton(get_class($this), 'members', 'open', 'add.png', true); $addMemberButton->setTitle(_('Add')); $memberHelp = new htmlHelpLink('uniqueMember'); $memberTable = new htmlTable(); if (!empty($this->attributes['uniqueMember'][0])) { $memberTable->alignment = htmlElement::ALIGN_TOP; for ($i = 0; $i < sizeof($this->attributes['uniqueMember']); $i++) { $member = $this->attributes['uniqueMember'][$i]; if (isset($this->printerCache[$member]['cn'])) { $member = $this->printerCache[$member]['cn']; } $memberTable->addElement(new htmlOutputText($member)); $delButton = new htmlButton('uniqueMemberDel_' . $i, 'del.png', true); $delButton->setTitle(_('Delete')); $memberTable->addElement($delButton); if ($i == (sizeof($this->attributes['uniqueMember']) - 1)) { $memberTable->addElement($addMemberButton); $memberTable->addElement($memberHelp); } $memberTable->addNewLine(); } } else { $memberTable->addElement($addMemberButton); $memberTable->addElement($memberHelp); } $container->addField($memberTable); return $container; } /** * Processes user input of the primary module page. * It checks if all input values are correct and updates the associated LDAP attributes. * * @return array list of info/error messages */ function process_attributes() { $errors = array(); // cn if (isset($_POST['cn']) && ($_POST['cn'] != '')) { if (!get_preg($_POST['cn'], 'username')) { $errors[] = $this->messages['cn'][0]; } else { $this->attributes['cn'][0] = $_POST['cn']; $this->attributes['pykotaPrinterName'][0] = $_POST['cn']; if ((!isset($this->orig['cn'][0]) || ($this->attributes['cn'][0] != $this->orig['cn'][0])) && $this->cnExists($_POST['cn'])) { $errors[] = $this->messages['cn'][2]; } } } else { if (isset($this->attributes['cn'][0])) { unset($this->attributes['cn'][0]); } if (isset($this->attributes['pykotaPrinterName'][0])) { unset($this->attributes['pykotaPrinterName'][0]); } } // description $this->processMultiValueInputTextField('description', $errors); // job size $pykotaMaxJobSize = '0'; if (isset($_POST['pykotaMaxJobSize']) && ($_POST['pykotaMaxJobSize'] != '')) { $pykotaMaxJobSize = $_POST['pykotaMaxJobSize']; if (!get_preg($pykotaMaxJobSize, 'digit')) { $errors[] = $this->messages['pykotaMaxJobSize'][0]; } } $this->attributes['pykotaMaxJobSize'][0] = $pykotaMaxJobSize; // price per job $pykotaPricePerJob = '0.0'; if (isset($_POST['pykotaPricePerJob']) && ($_POST['pykotaPricePerJob'] != '')) { $pykotaPricePerJob = $_POST['pykotaPricePerJob']; $pykotaPricePerJob = str_replace(',', '.', $pykotaPricePerJob); if (strpos($pykotaPricePerJob, '.') === false) { $pykotaPricePerJob .= '.0'; } if (!get_preg($pykotaPricePerJob, 'float')) { $errors[] = $this->messages['pykotaPricePerJob'][0]; } } $this->attributes['pykotaPricePerJob'][0] = $pykotaPricePerJob; // price per page $pykotaPricePerPage = '0.0'; if (isset($_POST['pykotaPricePerPage']) && ($_POST['pykotaPricePerPage'] != '')) { $pykotaPricePerPage = $_POST['pykotaPricePerPage']; $pykotaPricePerPage = str_replace(',', '.', $pykotaPricePerPage); if (strpos($pykotaPricePerPage, '.') === false) { $pykotaPricePerPage .= '.0'; } if (!get_preg($pykotaPricePerPage, 'float')) { $errors[] = $this->messages['pykotaPricePerPage'][0]; } } $this->attributes['pykotaPricePerPage'][0] = $pykotaPricePerPage; // passthrough $this->attributes['pykotaPassThrough'][0] = $_POST['pykotaPassThrough']; // delete members foreach ($_POST as $key => $value) { if (strpos($key, 'uniqueMemberDel_') === 0) { $index = substr($key, strlen('uniqueMemberDel_')); unset($this->attributes['uniqueMember'][$index]); $this->attributes['uniqueMember'] = array_values($this->attributes['uniqueMember']); break; } } return $errors; } /** * This function will create the meta HTML code to show a page to add members. * * @return htmlElement HTML meta data */ function display_html_members() { $return = new htmlResponsiveRow(); $options = array(); $this->loadPrinterNameCache(); foreach ($this->printerCache as $dn => $attrs) { if (!empty($attrs['description'])) { $label = $attrs['cn'] . ' (' . $attrs['description'] . ')'; } else { $label = $attrs['cn']; } // skip own entry if (!$this->getAccountContainer()->isNewAccount && ($this->getAccountContainer()->dn_orig == $dn)) { continue; } // skip already set members if (!empty($this->attributes['uniqueMember'][0]) && in_array($dn, $this->attributes['uniqueMember'])) { continue; } $options[$label] = $dn; } $size = 20; if (sizeof($options) < 20) { $size = sizeof($options); } $membersSelect = new htmlSelect('members', $options, array(), $size); $membersSelect->setHasDescriptiveElements(true); $membersSelect->setMultiSelect(true); $membersSelect->setTransformSingleSelect(false); $return->add($membersSelect, 12); $filterGroup = new htmlGroup(); $filterGroup->addElement(new htmlOutputText(_('Filter'))); $filterInput = new htmlInputField('newFilter', null); $filterInput->setCSSClasses(array('maxwidth20')); $filterInput->filterSelectBox('members'); $filterGroup->addElement($filterInput); $filterGroup->addElement(new htmlHelpLink('filter')); $return->add($filterGroup, 12); $return->addVerticalSpacer('2rem'); $buttonTable = new htmlGroup(); $buttonTable->addElement(new htmlAccountPageButton(get_class($this), 'attributes', 'addMembers', _('Add'))); $buttonTable->addElement(new htmlSpacer('0.5rem', null)); $buttonTable->addElement(new htmlAccountPageButton(get_class($this), 'attributes', 'cancel', _('Cancel'))); $return->add($buttonTable, 12); return $return; } /** * Processes user input of the members page. * It checks if all input values are correct and updates the associated LDAP attributes. * * @return array list of info/error messages */ function process_members() { $return = array(); if (isset($_POST['form_subpage_' . get_class($this) . '_attributes_addMembers']) && isset($_POST['members'])) { for ($i = 0; $i < sizeof($_POST['members']); $i++) { $this->attributes['uniqueMember'][] = $_POST['members'][$i]; } } return $return; } /** * {@inheritDoc} * @see baseModule::build_uploadAccounts() */ function build_uploadAccounts($rawAccounts, $ids, &$partialAccounts, $selectedModules, &$type) { $messages = array(); $this->loadPrinterNameCache(); for ($i = 0; $i < sizeof($rawAccounts); $i++) { // add object classes if (!in_array('pykotaPrinter', $partialAccounts[$i]['objectClass'])) { $partialAccounts[$i]['objectClass'][] = 'pykotaPrinter'; } if (!in_array('pykotaObject', $partialAccounts[$i]['objectClass'])) { $partialAccounts[$i]['objectClass'][] = 'pykotaObject'; } // cn if (!empty($rawAccounts[$i][$ids['pykotaPrinter_cn']])) { if (!get_preg($rawAccounts[$i][$ids['pykotaPrinter_cn']], 'username')) { $errMsg = $this->messages['cn'][1]; array_push($errMsg, array($i)); $messages[] = $errMsg; } elseif ($this->cnExists($rawAccounts[$i][$ids['pykotaPrinter_cn']])) { $errMsg = $this->messages['cn'][3]; array_push($errMsg, array($i)); $messages[] = $errMsg; } else { $partialAccounts[$i]['cn'] = $rawAccounts[$i][$ids['pykotaPrinter_cn']]; $partialAccounts[$i]['pykotaPrinterName'] = $rawAccounts[$i][$ids['pykotaPrinter_cn']]; } } // description $this->mapSimpleUploadField($rawAccounts, $ids, $partialAccounts, $i, 'pykotaPrinter_description', 'description'); // job size $partialAccounts[$i]['pykotaMaxJobSize'] = '0.0'; $this->mapSimpleUploadField($rawAccounts, $ids, $partialAccounts, $i, 'pykotaPrinter_pykotaMaxJobSize', 'pykotaMaxJobSize', 'digit', $this->messages['pykotaMaxJobSize'][1], $messages); // price per job if (!empty($rawAccounts[$i][$ids['pykotaPrinter_pykotaPricePerJob']])) { $pykotaPricePerJob = $rawAccounts[$i][$ids['pykotaPrinter_pykotaPricePerJob']]; $pykotaPricePerJob = str_replace(',', '.', $pykotaPricePerJob); if (strpos($pykotaPricePerJob, '.') === false) { $pykotaPricePerJob .= '.0'; } if (!get_preg($pykotaPricePerJob, 'float')) { $errMsg = $this->messages['pykotaPricePerJob'][1]; array_push($errMsg, array($i)); $messages[] = $errMsg; } else { $partialAccounts[$i]['pykotaPricePerJob'] = $pykotaPricePerJob; } } else { $partialAccounts[$i]['pykotaPricePerJob'] = '0.0'; } // price per page if (!empty($rawAccounts[$i][$ids['pykotaPrinter_pykotaPricePerPage']])) { $pykotaPricePerPage = $rawAccounts[$i][$ids['pykotaPrinter_pykotaPricePerPage']]; $pykotaPricePerPage = str_replace(',', '.', $pykotaPricePerPage); if (strpos($pykotaPricePerPage, '.') === false) { $pykotaPricePerPage .= '.0'; } if (!get_preg($pykotaPricePerPage, 'float')) { $errMsg = $this->messages['pykotaPricePerPage'][1]; array_push($errMsg, array($i)); $messages[] = $errMsg; } else { $partialAccounts[$i]['pykotaPricePerPage'] = $pykotaPricePerPage; } } else { $partialAccounts[$i]['pykotaPricePerPage'] = '0.0'; } // passthrough if (!empty($rawAccounts[$i][$ids['pykotaPrinter_pykotaPassThrough']])) { if (isset($this->passThroughOptions[$rawAccounts[$i][$ids['pykotaPrinter_pykotaPassThrough']]])) { $partialAccounts[$i]['pykotaPassThrough'] = $this->passThroughOptions[$rawAccounts[$i][$ids['pykotaPrinter_pykotaPassThrough']]]; } else { $errMsg = $this->messages['pykotaPassThrough'][0]; array_push($errMsg, array($i)); $messages[] = $errMsg; } } else { $partialAccounts[$i]['pykotaPassThrough'] = 'f'; } // group members if (!empty($rawAccounts[$i][$ids['pykotaPrinter_uniqueMember']])) { $members = preg_split('/,[ ]*/', $rawAccounts[$i][$ids['pykotaPrinter_uniqueMember']]); $memberDNs = array(); foreach ($members as $cn) { if (empty($cn)) { continue; } // search printer cache for cn to get DN $found = false; foreach ($this->printerCache as $dn => $attrs) { if ($this->printerCache[$dn]['cn'] == $cn) { $found = true; $memberDNs[] = $dn; break; } } if (!$found) { $errMsg = $this->messages['uniqueMember'][0]; array_push($errMsg, array($i, htmlspecialchars($cn))); $messages[] = $errMsg; } } if (sizeof($memberDNs) > 0) { $partialAccounts[$i]['uniqueMember'] = $memberDNs; } } } return $messages; } /** * {@inheritDoc} * @see baseModule::get_pdfEntries() */ function get_pdfEntries($pdfKeys, $typeId) { $return = array(); $this->loadPrinterNameCache(); $this->addSimplePDFField($return, 'cn', _('Printer name')); $this->addSimplePDFField($return, 'description', _('Description')); $this->addSimplePDFField($return, 'pykotaMaxJobSize', _('Maximum job size')); $this->addSimplePDFField($return, 'pykotaPricePerJob', _('Price per job')); $this->addSimplePDFField($return, 'pykotaPricePerPage', _('Price per page')); // passthrough $passthroughOptions = array_flip($this->passThroughOptions); $passthroughValue = ''; if (!empty($this->attributes['pykotaPassThrough'][0]) && isset($passthroughOptions[$this->attributes['pykotaPassThrough'][0]])) { $passthroughValue = $passthroughOptions[$this->attributes['pykotaPassThrough'][0]]; } $this->addPDFKeyValue($return, 'pykotaPassThrough', _('Passthrough'), $passthroughValue); // members if (!empty($this->attributes['uniqueMember'][0])) { $members = array(); foreach ($this->attributes['uniqueMember'] as $member) { if (!empty($this->printerCache[$member]['cn'])) { $members[] = $this->printerCache[$member]['cn']; } else { $members[] = getAbstractDN($member); } } $this->addPDFKeyValue($return, 'uniqueMember', _('Group members'), implode(', ', $members)); } // printer groups $parentGroups = array(); $groups = $this->getPrinterGroups(); foreach ($groups as $group) { if (!empty($this->printerCache[$group]['cn'])) { $parentGroups[] = $this->printerCache[$group]['cn']; } else { $parentGroups[] = getAbstractDN($group); } } if (sizeof($parentGroups) > 0) { $this->addPDFKeyValue($return, 'parentUniqueMember', _('Printer groups'), implode(', ', $parentGroups)); } return $return; } /** * Returns if the given cn already exists. * * @param String $cn cn attribute value * @return boolean cn exists */ private function cnExists($cn) { if ($this->printerCache == null) { $this->loadPrinterNameCache(); } foreach ($this->printerCache as $attrs) { if (!empty($attrs['cn']) && ($attrs['cn'] == $cn)) { return true; } } return false; } /** * Loads the list of printer names into the cache. */ private function loadPrinterNameCache() { if ($this->printerCache != null) { return; } $results = searchLDAPByFilter('(objectClass=pykotaPrinter)', array('cn', 'dn', 'description'), array($this->get_scope())); $this->printerCache = array(); foreach ($results as $result) { if (isset($result['cn'][0])) { $this->printerCache[$result['dn']]['cn'] = $result['cn'][0]; } if (isset($result['description'][0])) { $this->printerCache[$result['dn']]['description'] = $result['description'][0]; } } } /** * Returns the printer group memberships. * * @return array DNs of parent groups */ private function getPrinterGroups() { if ($this->groupCache != null) { return $this->groupCache; } $results = searchLDAPByFilter('(&(objectClass=pykotaPrinter)(uniqueMember=' . $this->getAccountContainer()->dn_orig . '))', array('dn'), array($this->get_scope())); $this->groupCache = array(); foreach ($results as $result) { $this->groupCache[] = $result['dn']; } return $this->groupCache; } } ?>