diff options
Diffstat (limited to 'platform/www/lib/plugins/bureaucracy/helper')
29 files changed, 2868 insertions, 0 deletions
diff --git a/platform/www/lib/plugins/bureaucracy/helper/action.php b/platform/www/lib/plugins/bureaucracy/helper/action.php new file mode 100644 index 0000000..5c6dd08 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/action.php @@ -0,0 +1,136 @@ +<?php +/** + * Base class for bureaucracy actions. + * + * All bureaucracy actions have to inherit from this class. + * + * ATM this class is pretty empty but, in the future it could be used to add + * helper functions which can be utilized by the different actions. + * + * @author Michael Klier <chi@chimeric.de> + */ +class helper_plugin_bureaucracy_action extends syntax_plugin_bureaucracy { + + /** + * Return false to prevent DokuWiki reusing instances of the plugin + * + * @return bool + */ + public function isSingleton() { + return false; + } + + /** + * Handle the user input [required] + * + * This function needs to be implemented to accept the user data collected + * from the form. Data has to be grabbed from $_POST['bureaucracy'] using + * the indicies in the 'idx' members of the $data items. + * + * @param helper_plugin_bureaucracy_field[] $fields the list of fields in the form + * @param string $thanks the thank you message as defined in the form + * or default one. Might be modified by the action + * before returned + * @param array $argv additional arguments passed to the action + * @return bool|string false on error, $thanks on success + */ + public function run($fields, $thanks, $argv){ + msg('ERROR: called action %s did not implement a run() function'); + return false; + } + + /** + * Adds some language related replacement patterns + */ + function prepareLanguagePlaceholder() { + global $ID; + global $conf; + + $this->patterns['__lang__'] = '/@LANG@/'; + $this->values['__lang__'] = $conf['lang']; + + $this->patterns['__trans__'] = '/@TRANS@/'; + $this->values['__trans__'] = ''; + + /** @var helper_plugin_translation $trans */ + $trans = plugin_load('helper', 'translation'); + if (!$trans) return; + + $this->values['__trans__'] = $trans->getLangPart($ID); + $this->values['__lang__'] = $trans->realLC(''); + } + + /** + * Adds replacement pattern for fieldlabels (e.g @@Label@@) + * + * @param helper_plugin_bureaucracy_field $field + */ + function prepareFieldReplacement($field) { + $label = $field->getParam('label'); + + if(!is_null($label)) { + $this->patterns[$label] = $field->getReplacementPattern(); + $this->values[$label] = $field->getReplacementValue(); + } + } + + /** + * Adds <noinclude></noinclude> to replacement patterns + */ + function prepareNoincludeReplacement() { + $this->patterns['__noinclude__'] = '/<noinclude>(.*?)<\/noinclude>/is'; + $this->values['__noinclude__'] = ''; + } + + /** + * Generate field replacements + * + * @param helper_plugin_bureaucracy_field[] $fields List of field objects + * @return array + */ + function prepareFieldReplacements($fields) { + foreach ($fields as $field) { + //field replacements + $this->prepareFieldReplacement($field); + } + } + + /** + * Returns ACL access level of the user or the (virtual) 'runas' user + * + * @param string $id pageid + * @return int + */ + protected function aclcheck($id) { + $runas = $this->getConf('runas'); + + if($runas) { + $auth = auth_aclcheck($id, $runas, array()); + } else { + $auth = auth_quickaclcheck($id); + } + return $auth; + + } + + /** + * Available methods + * + * @return array + */ + public function getMethods() { + $result = array(); + $result[] = array( + 'name' => 'run', + 'desc' => 'Handle the user input', + 'params' => array( + 'fields' => 'helper_plugin_bureaucracy_field[]', + 'thanks' => 'string', + 'argv' => 'array' + ), + 'return' => array('false on error, thanks message on success' => 'bool|string') + ); + return $result; + } + +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/actionmail.php b/platform/www/lib/plugins/bureaucracy/helper/actionmail.php new file mode 100644 index 0000000..698e6c0 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/actionmail.php @@ -0,0 +1,212 @@ +<?php +/** + * Action sendemail for DokuWiki plugin bureaucracy + */ + +class helper_plugin_bureaucracy_actionmail extends helper_plugin_bureaucracy_action { + + protected $_mail_html = ''; + protected $_mail_text = ''; + protected $subject = ''; + protected $replyto = array(); + protected $mailtemplate = ''; + + /** + * Build a nice email from the submitted data and send it + * + * @param helper_plugin_bureaucracy_field[] $fields + * @param string $thanks + * @param array $argv + * @return string thanks message + * @throws Exception mailing failed + */ + public function run($fields, $thanks, $argv) { + global $ID; + global $conf; + + $mail = new Mailer(); + + $this->prepareNamespacetemplateReplacements(); + $this->prepareDateTimereplacements(); + $this->prepareLanguagePlaceholder(); + $this->prepareNoincludeReplacement(); + $this->prepareFieldReplacements($fields); + + $evdata = [ + 'fields' => $fields, + 'values' => &$this->values + ]; + $event = new Doku_Event('PLUGIN_BUREAUCRACY_EMAIL_SEND', $evdata); + if($event->advise_before()) { + //set default subject + $this->subject = sprintf($this->getLang('mailsubject'), $ID); + + //build html&text table, collect replyto and subject + list($table_html, $table_text) = $this->processFieldsBuildTable($fields, $mail); + + //Body + if($this->mailtemplate) { + //show template + $this->patterns['__tablehtml__'] = '/@TABLEHTML@/'; + $this->patterns['__tabletext__'] = '/@TABLETEXT@/'; + $this->values['__tablehtml__'] = $table_html; + $this->values['__tabletext__'] = $table_text; + + list($this->_mail_html, $this->_mail_text) = $this->getContent(); + + } else { + //show simpel listing + $this->_mail_html .= sprintf($this->getLang('mailintro')."<br><br>", dformat()); + $this->_mail_html .= $table_html; + + $this->_mail_text .= sprintf($this->getLang('mailintro')."\n\n", dformat()); + $this->_mail_text .= $table_text; + } + $mail->setBody($this->_mail_text,null,null,$this->_mail_html); + + // Reply-to + if(!empty($this->replyto)) { + $replyto = $mail->cleanAddress($this->replyto); + $mail->setHeader('Reply-To', $replyto, false); + } + + // To + $to = $this->replace(implode(',',$argv)); // get recipient address(es) + $to = $mail->cleanAddress($to); + $mail->to($to); + + // From + $mail->from($conf['mailfrom']); + + // Subject + $this->subject = $this->replace($this->subject); + $mail->subject($this->subject); + + if(!$mail->send()) { + throw new Exception($this->getLang('e_mail')); + } + } + $event->advise_after(); + + return '<p>' . $thanks . '</p>'; + } + + /** + * Create html and plain table of the field + * and collect values for subject and replyto + * + * @param helper_plugin_bureaucracy_field[] $fields + * @param Mailer $mail + * @return array of html and text table + */ + protected function processFieldsBuildTable($fields, $mail) { + global $ID; + + $table_html = '<table>'; + $table_text = ''; + + foreach($fields as $field) { + $html = $text = ''; + $value = $field->getParam('value'); + $label = $field->getParam('label'); + + switch($field->getFieldType()) { + case 'fieldset': + if(!empty($field->depends_on)) { + //print fieldset only if depend condition is true + foreach($fields as $field_tmp) { + if($field_tmp->getParam('label') === $field->depends_on[0] && $field_tmp->getParam('value') === $field->depends_on[1] ) { + list($html, $text) = $this->mail_buildRow($label); + } + } + } else { + list($html, $text) = $this->mail_buildRow($label); + } + break; + case 'file': + if($value === null || $label === null) break; //print attachment only if field was visible + $file = $field->getParam('file'); + if(!$file['size']) { + $message = $this->getLang('attachmentMailEmpty'); + } else if($file['size'] > $this->getConf('maxEmailAttachmentSize')) { + $message = $file['name'] . ' ' . $this->getLang('attachmentMailToLarge'); + msg(sprintf($this->getLang('attachmentMailToLarge_userinfo'), hsc($file['name']), filesize_h($this->getConf('maxEmailAttachmentSize'))), 2); + } else { + $message = $file['name']; + $mail->attachFile($file['tmp_name'], $file['type'], $file['name']); + } + list($html, $text) = $this->mail_buildRow($label, $message); + break; + case 'subject': + $this->subject = $label; + break; + case 'usemailtemplate': + if (!is_null($field->getParam('template')) ) { + $this->mailtemplate = $this->replace($field->getParam('template')); + resolve_pageid(getNS($ID), $this->mailtemplate, $ignored); + } + break; + + default: + if($value === null || $label === null) break; + if(is_array($value)) $value = implode(', ', $value); + list($html, $text) = $this->mail_buildRow($label, $value); + + if(!is_null($field->getParam('replyto'))) { + $this->replyto[] = $value; + } + } + $table_html .= $html; + $table_text .= $text; + } + $table_html .= '</table>'; + + return array($table_html, $table_text); + } + + /** + * Build a row + * + * @param $column1 + * @param null $column2 + * @return array of html and text row + */ + protected function mail_buildRow($column1,$column2=null) { + if($column2 === null) { + $html = '<tr><td colspan="2"><u>'.hsc($column1).'<u></td></tr>'; + $text = "\n=====".$column1.'====='; + } else { + $html = '<tr><td><b>'.hsc($column1).'<b></td><td>'.hsc($column2).'</td></tr>'; + $text = "\n $column1 \t\t $column2"; + } + return array($html, $text); + } + + /** + * Parse mail template in html and text, and perform replacements + * + * @return array html and text content + */ + protected function getContent() { + $content = rawWiki($this->mailtemplate); + $html = ''; + $text = ''; + + if(preg_match_all('#<code\b(.*?)>(.*?)</code>#is', $content, $matches)) { + foreach($matches[1] as $index => $codeoptions) { + list($syntax,) = explode(' ', trim($codeoptions), 2); + if($syntax == 'html') { + $html = $matches[2][$index]; + } + if($syntax == 'text' || $syntax == '') { + $text = $matches[2][$index]; + } + } + } + return array( + $this->replace($html), + $this->replace($text) + ); + } +} +// vim:ts=4:sw=4:et:enc=utf-8: diff --git a/platform/www/lib/plugins/bureaucracy/helper/actionscript.php b/platform/www/lib/plugins/bureaucracy/helper/actionscript.php new file mode 100644 index 0000000..f308721 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/actionscript.php @@ -0,0 +1,62 @@ +<?php + +class helper_plugin_bureaucracy_actionscript extends helper_plugin_bureaucracy_action { + + protected $scriptNamePattern = '/^[_a-zA-Z0-9]+\.php$/'; + + /** + * @inheritDoc + * @throws \InvalidArgumentException + */ + public function run($fields, $thanks, $argv) { + if (count($argv) < 1) { + throw new InvalidArgumentException('The "script"-action expects exactly 1 argument: the script name.'); + } + + $scriptName = $argv[0]; + + if (!$this->validateScriptName($scriptName)) { + $cleanedScriptName = hsc($scriptName); + throw new InvalidArgumentException("The supplied scriptname \"<code>$cleanedScriptName</code>\" is invalid! It must conform to <code>{hsc($this->scriptNamePattern)}</code>!"); + } + + $path = DOKU_CONF . 'plugin/bureaucracy/' . $scriptName; + + if (!file_exists($path)) { + $shortPath = 'conf/plugin/bureaucracy/' . $scriptName; + throw new InvalidArgumentException("Script <code>$shortPath</code> doesn't exist!"); + } + + require $path; + + $classFragment = substr($scriptName, 0, strpos($scriptName, '.')); + $className = 'helper_plugin_bureaucracy_handler_' . $classFragment; + + $deprecatedClassName = 'bureaucracy_handler_' . $classFragment; + if (!class_exists($className) && class_exists($deprecatedClassName)) { + msg("Please change this script's class-name to <code>$className</code>. +Your current scheme <code>$deprecatedClassName</code> is deprecated and will stop working in the future.", 2); + $className = $deprecatedClassName; + } + + /** @var dokuwiki\plugin\bureaucracy\interfaces\bureaucracy_handler_interface $handler */ + $handler = new $className; + + if (!is_a($handler, dokuwiki\plugin\bureaucracy\interfaces\bureaucracy_handler_interface::class)) { + throw new InvalidArgumentException('The handler must implement the interface <code>dokuwiki\\plugin\\bureaucracy\\interfaces\\bureaucracy_handler_interface</code> !'); + } + + return $handler->handleData($fields, $thanks); + } + + /** + * @param $scriptName + * + * @return bool + */ + protected function validateScriptName($scriptName) { + $valid = preg_match($this->scriptNamePattern, $scriptName); + return $valid === 1; + } + +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/actiontemplate.php b/platform/www/lib/plugins/bureaucracy/helper/actiontemplate.php new file mode 100644 index 0000000..04714d8 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/actiontemplate.php @@ -0,0 +1,459 @@ +<?php +/** + * Simple template replacement action for the bureaucracy plugin + * + * @author Michael Klier <chi@chimeric.de> + */ + +class helper_plugin_bureaucracy_actiontemplate extends helper_plugin_bureaucracy_action { + + var $targetpages; + var $pagename; + + /** + * Performs template action + * + * @param helper_plugin_bureaucracy_field[] $fields array with form fields + * @param string $thanks thanks message + * @param array $argv array with entries: template, pagename, separator + * @return array|mixed + * + * @throws Exception + */ + public function run($fields, $thanks, $argv) { + global $conf; + + [$tpl, $this->pagename] = $argv; + $sep = $argv[2] ?? $conf['sepchar']; + + $this->patterns = array(); + $this->values = array(); + $this->targetpages = array(); + + $this->prepareNamespacetemplateReplacements(); + $this->prepareDateTimereplacements(); + $this->prepareLanguagePlaceholder(); + $this->prepareNoincludeReplacement(); + $this->prepareFieldReplacements($fields); + + $evdata = array( + 'patterns' => &$this->patterns, + 'values' => &$this->values, + 'fields' => $fields, + 'action' => $this + ); + + $event = new Doku_Event('PLUGIN_BUREAUCRACY_PAGENAME', $evdata); + if ($event->advise_before()) { + $this->buildTargetPagename($fields, $sep); + } + $event->advise_after(); + + //target&template(s) from addpage fields + $this->getAdditionalTargetpages($fields); + //target&template(s) from action field + $tpl = $this->getActionTargetpages($tpl); + + if(empty($this->targetpages)) { + throw new Exception(sprintf($this->getLang('e_template'), $tpl)); + } + + $this->checkTargetPageNames(); + + $this->processUploads($fields); + $this->replaceAndSavePages($fields); + + $ret = $this->buildThankYouPage($thanks); + + return $ret; + } + + /** + * Prepare and resolve target page + * + * @param helper_plugin_bureaucracy_field[] $fields List of field objects + * @param string $sep Separator between fields for page id + * @throws Exception missing pagename + */ + protected function buildTargetPagename($fields, $sep) { + global $ID; + + foreach ($fields as $field) { + $pname = $field->getParam('pagename'); + if (!is_null($pname)) { + if (is_array($pname)) $pname = implode($sep, $pname); + $this->pagename .= $sep . $pname; + } + } + + $this->pagename = $this->replace($this->pagename); + + $myns = getNS($ID); + resolve_pageid($myns, $this->pagename, $ignored); // resolve relatives + + if ($this->pagename === '') { + throw new Exception($this->getLang('e_pagename')); + } + } + + /** + * Handle templates from addpage field + * + * @param helper_plugin_bureaucracy_field[] $fields List of field objects + * @return array + */ + function getAdditionalTargetpages($fields) { + global $ID; + $ns = getNS($ID); + + foreach ($fields as $field) { + if (!is_null($field->getParam('page_tpl')) && !is_null($field->getParam('page_tgt')) ) { + //template + $templatepage = $this->replace($field->getParam('page_tpl')); + resolve_pageid(getNS($ID), $templatepage, $ignored); + + //target + $relativetargetpage = $field->getParam('page_tgt'); + resolve_pageid($ns, $relativeTargetPageid, $ignored); + $targetpage = "$this->pagename:$relativetargetpage"; + + $auth = $this->aclcheck($templatepage); // runas + if ($auth >= AUTH_READ ) { + $this->addParsedTargetpage($targetpage, $templatepage); + } + } + } + } + + /** + * Returns raw pagetemplate contents for the ID's namespace + * + * @param string $id the id of the page to be created + * @return string raw pagetemplate content + */ + protected function rawPageTemplate($id) { + global $conf; + + $path = dirname(wikiFN($id)); + if(file_exists($path.'/_template.txt')) { + $tplfile = $path.'/_template.txt'; + } else { + // search upper namespaces for templates + $len = strlen(rtrim($conf['datadir'], '/')); + while(strlen($path) >= $len) { + if(file_exists($path.'/__template.txt')) { + $tplfile = $path.'/__template.txt'; + break; + } + $path = substr($path, 0, strrpos($path, '/')); + } + } + + $tpl = io_readFile($tplfile); + return $tpl; + } + + /** + * Load template(s) for targetpage as given via action field + * + * @param string $tpl template name as given in form + * @return string parsed templatename + */ + protected function getActionTargetpages($tpl) { + global $USERINFO; + global $conf; + global $ID; + $runas = $this->getConf('runas'); + + if ($tpl == '_') { + // use namespace template + if (!isset($this->targetpages[$this->pagename])) { + $raw = $this->rawPageTemplate($this->pagename); + $this->noreplace_save($raw); + $this->targetpages[$this->pagename] = pageTemplate(array($this->pagename)); + } + } elseif ($tpl !== '!') { + $tpl = $this->replace($tpl); + + // resolve templates, but keep references to whole namespaces intact (ending in a colon) + if(substr($tpl, -1) == ':') { + $tpl = $tpl.'xxx'; // append a fake page name + resolve_pageid(getNS($ID), $tpl, $ignored); + $tpl = substr($tpl, 0, -3); // cut off fake page name again + } else { + resolve_pageid(getNS($ID), $tpl, $ignored); + } + + $backup = array(); + if ($runas) { + // Hack user credentials. + $backup = array($_SERVER['REMOTE_USER'], $USERINFO['grps']); + $_SERVER['REMOTE_USER'] = $runas; + $USERINFO['grps'] = array(); + } + + $template_pages = array(); + //search checks acl (as runas) + $opts = array( + 'depth' => 0, + 'listfiles' => true, + 'showhidden' => true + ); + search($template_pages, $conf['datadir'], 'search_universal', $opts, str_replace(':', '/', getNS($tpl))); + + foreach ($template_pages as $template_page) { + $templatepageid = cleanID($template_page['id']); + // try to replace $tpl path with $this->pagename path in the founded $templatepageid + // - a single-page template will only match on itself and will be replaced, + // other newtargets are pages in same namespace, so aren't changed + // - a namespace as template will match at the namespaces-part of the path of pages in this namespace + // so these newtargets are changed + // if there exist a single-page and a namespace with name $tpl, both are selected + $newTargetpageid = preg_replace('/^' . preg_quote_cb(cleanID($tpl)) . '($|:)/', $this->pagename . '$1', $templatepageid); + + if ($newTargetpageid === $templatepageid) { + // only a single-page template or page in the namespace template + // which matches the $tpl path are changed + continue; + } + + if (!isset($this->targetpages[$newTargetpageid])) { + $this->addParsedTargetpage($newTargetpageid, $templatepageid); + } + } + + if ($runas) { + /* Restore user credentials. */ + list($_SERVER['REMOTE_USER'], $USERINFO['grps']) = $backup; + } + } + return $tpl; + } + + /** + * Checks for existance and access of target pages + * + * @return mixed + * @throws Exception + */ + protected function checkTargetPageNames() { + foreach (array_keys($this->targetpages) as $pname) { + // prevent overriding already existing pages + if (page_exists($pname)) { + throw new Exception(sprintf($this->getLang('e_pageexists'), html_wikilink($pname))); + } + + $auth = $this->aclcheck($pname); + if ($auth < AUTH_CREATE) { + throw new Exception($this->getLang('e_denied')); + } + } + } + + /** + * Perform replacements on the collected templates, and save the pages. + * + * Note: wrt runas, for changelog are used: + * - $INFO['userinfo']['name'] + * - $INPUT->server->str('REMOTE_USER') + */ + protected function replaceAndSavePages($fields) { + global $ID; + foreach ($this->targetpages as $pageName => $template) { + // set NSBASE var to make certain dataplugin constructs easier + $this->patterns['__nsbase__'] = '/@NSBASE@/'; + $this->values['__nsbase__'] = noNS(getNS($pageName)); + + $evdata = array( + 'patterns' => &$this->patterns, + 'values' => &$this->values, + 'id' => $pageName, + 'template' => $template, + 'form' => $ID, + 'fields' => $fields + ); + + $event = new Doku_Event('PLUGIN_BUREAUCRACY_TEMPLATE_SAVE', $evdata); + if($event->advise_before()) { + // save page + saveWikiText( + $evdata['id'], + cleanText($this->replace($evdata['template'], false)), + sprintf($this->getLang('summary'), $ID) + ); + } + $event->advise_after(); + } + } + + /** + * (Callback) Sorts first by namespace depth, next by page ids + * + * @param string $a + * @param string $b + * @return int positive if $b is in deeper namespace than $a, negative higher. + * further sorted by pageids + * + * return an integer less than, equal to, or + * greater than zero if the first argument is considered to be + * respectively less than, equal to, or greater than the second. + */ + public function _sorttargetpages($a, $b) { + $ns_diff = substr_count($a, ':') - substr_count($b, ':'); + return ($ns_diff === 0) ? strcmp($a, $b) : ($ns_diff > 0 ? -1 : 1); + } + + /** + * (Callback) Build content of item + * + * @param array $item + * @return string + */ + public function html_list_index($item){ + $ret = ''; + if($item['type']=='f'){ + $ret .= html_wikilink(':'.$item['id']); + } else { + $ret .= '<strong>' . trim(substr($item['id'], strrpos($item['id'], ':', -2)), ':') . '</strong>'; + } + return $ret; + } + + /** + * Build thanks message, trigger indexing and rendering of new pages. + * + * @param string $thanks + * @return string html of thanks message or when redirect the first page id of created pages + */ + protected function buildThankYouPage($thanks) { + global $ID; + $backupID = $ID; + + $html = "<p>$thanks</p>"; + + // Build result tree + $pages = array_keys($this->targetpages); + usort($pages, array($this, '_sorttargetpages')); + + $data = array(); + $last_folder = array(); + foreach ($pages as $ID) { + $lvl = substr_count($ID, ':'); + for ($n = 0; $n < $lvl; ++$n) { + if (!isset($last_folder[$n]) || strpos($ID, $last_folder[$n]['id']) !== 0) { + $last_folder[$n] = array( + 'id' => substr($ID, 0, strpos($ID, ':', ($n > 0 ? strlen($last_folder[$n - 1]['id']) : 0) + 1) + 1), + 'level' => $n + 1, + 'open' => 1 + ); + $data[] = $last_folder[$n]; + } + } + $data[] = array('id' => $ID, 'level' => 1 + substr_count($ID, ':'), 'type' => 'f'); + } + $html .= html_buildlist($data, 'idx', array($this, 'html_list_index'), 'html_li_index'); + + // Add indexer bugs for every just-created page + $html .= '<div class="no">'; + ob_start(); + foreach ($pages as $ID) { + // indexerWebBug uses ID and INFO[exists], but the bureaucracy form + // page always exists, as does the just-saved page, so INFO[exists] + // is correct in any case + tpl_indexerWebBug(); + + // the iframe will trigger real rendering of the pages to make sure + // any used plugins are initialized (eg. the do plugin) + echo '<iframe src="' . wl($ID, array('do' => 'export_html')) . '" width="1" height="1" style="visibility:hidden"></iframe>'; + } + $html .= ob_get_contents(); + ob_end_clean(); + $html .= '</div>'; + + $ID = $backupID; + return $html; + } + + /** + * move the uploaded files to <pagename>:FILENAME + * + * + * @param helper_plugin_bureaucracy_field[] $fields + * @throws Exception + */ + protected function processUploads($fields) { + foreach($fields as $field) { + + if($field->getFieldType() !== 'file') continue; + + $label = $field->getParam('label'); + $file = $field->getParam('file'); + $ns = $field->getParam('namespace'); + + //skip empty files + if(!$file['size']) { + $this->values[$label] = ''; + continue; + } + + $id = $ns.':'.$file['name']; + resolve_mediaid($this->pagename, $id, $ignored); // resolve relatives + + $auth = $this->aclcheck($id); // runas + $move = 'copy_uploaded_file'; + //prevent from is_uploaded_file() check + if(defined('DOKU_UNITTEST')) { + $move = 'copy'; + } + $res = media_save( + array('name' => $file['tmp_name']), + $id, + false, + $auth, + $move); + + if(is_array($res)) throw new Exception($res[0]); + + $this->values[$label] = $res; + + } + } + + /** + * Load page data and do default pattern replacements like namespace templates do + * and add it to list of targetpages + * + * Note: for runas the values of the real user are used for the placeholders + * @NAME@ => $USERINFO['name'] + * @MAIL@ => $USERINFO['mail'] + * and the replaced value: + * @USER@ => $INPUT->server->str('REMOTE_USER') + * + * @param string $targetpageid pageid of destination + * @param string $templatepageid pageid of template for this targetpage + */ + protected function addParsedTargetpage($targetpageid, $templatepageid) { + $tpl = rawWiki($templatepageid); + $this->noreplace_save($tpl); + + $data = array( + 'id' => $targetpageid, + 'tpl' => $tpl, + 'doreplace' => true, + ); + parsePageTemplate($data); + + //collect and apply some other replacements + $patterns = array(); + $values = array(); + $keys = array('__lang__', '__trans__', '__year__', '__month__', '__day__', '__time__'); + foreach($keys as $key) { + $patterns[$key] = $this->patterns[$key]; + $values[$key] = $this->values[$key]; + } + + $this->targetpages[$targetpageid] = preg_replace($patterns, $values, $data['tpl']); + } + +} +// vim:ts=4:sw=4:et:enc=utf-8: diff --git a/platform/www/lib/plugins/bureaucracy/helper/field.php b/platform/www/lib/plugins/bureaucracy/helper/field.php new file mode 100644 index 0000000..070e331 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/field.php @@ -0,0 +1,508 @@ +<?php + +/** + * Base class for form fields + * + * This class provides basic functionality for many form fields. It supports + * labels, basic validation and template-based XHTML output. + * + * @author Adrian Lang <lang@cosmocode.de> + **/ + +/** + * Class helper_plugin_bureaucracy_field + * + * base class for all the form fields + */ +class helper_plugin_bureaucracy_field extends syntax_plugin_bureaucracy { + + protected $mandatory_args = 2; + public $opt = array(); + /** @var string|array */ + protected $tpl; + protected $checks = array(); + public $hidden = false; + protected $error = false; + protected $checktypes = array( + '/' => 'match', + '<' => 'max', + '>' => 'min' + ); + + /** + * Construct a helper_plugin_bureaucracy_field object + * + * This constructor initializes a helper_plugin_bureaucracy_field object + * based on a given definition. + * + * The first two items represent: + * * the type of the field + * * and the label the field has been given. + * Additional arguments are type-specific mandatory extra arguments and optional arguments. + * + * The optional arguments may add constraints to the field value, provide a + * default value, mark the field as optional or define that the field is + * part of a pagename (when using the template action). + * + * Since the field objects are cached, this constructor may not reference + * request data. + * + * @param array $args The tokenized definition, only split at spaces + */ + public function initialize($args) { + $this->init($args); + $this->standardArgs($args); + } + + /** + * Return false to prevent DokuWiki reusing instances of the plugin + * + * @return bool + */ + public function isSingleton() { + return false; + } + + /** + * Checks number of arguments and store 'cmd', 'label' and 'display' values + * + * @param array $args array with the definition + */ + protected function init(&$args) { + if(count($args) < $this->mandatory_args){ + msg(sprintf($this->getLang('e_missingargs'), hsc($args[0]), + hsc($args[1])), -1); + return; + } + + // get standard arguments + $this->opt = array(); + foreach (array('cmd', 'label') as $key) { + if (count($args) === 0) break; + $this->opt[$key] = array_shift($args); + } + $this->opt['display'] = $this->opt['label']; // allow to modify display value independently + } + + /** + * Check for additional arguments and store their values + * + * @param array $args array with remaining definition arguments + */ + protected function standardArgs($args) { + // parse additional arguments + foreach($args as $arg){ + if ($arg[0] == '=') { + $this->setVal(substr($arg,1)); + } elseif ($arg == '!') { + $this->opt['optional'] = true; + } elseif ($arg == '^') { + //only one field has focus + if (helper_plugin_bureaucracy_field::hasFocus()) { + $this->opt['id'] = 'focus__this'; + } + } elseif($arg == '@') { + $this->opt['pagename'] = true; + } elseif($arg == '@@') { + $this->opt['replyto'] = true; + } elseif(preg_match('/x\d/', $arg)) { + $this->opt['rows'] = substr($arg,1); + } elseif($arg[0] == '.') { + $this->opt['class'] = substr($arg, 1); + } elseif(preg_match('/^0{2,}$/', $arg)) { + $this->opt['leadingzeros'] = strlen($arg); + } elseif($arg[0].$arg[1] == '**') { + $this->opt['matchexplanation'] = substr($arg,2); + } else { + $t = $arg[0]; + $d = substr($arg,1); + if (in_array($t, array('>', '<')) && !is_numeric($d)) { + break; + } + if ($t == '/') { + if (substr($d, -1) !== '/') { + break; + } + $d = substr($d, 0, -1); + } + if (!isset($this->checktypes[$t]) || !method_exists($this, 'validate_' . $this->checktypes[$t])) { + msg(sprintf($this->getLang('e_unknownconstraint'), hsc($t).' ('.hsc($arg).')'), -1); + return; + } + $this->checks[] = array('t' => $t, 'd' => $d); + } + } + } + + /** + * Add parsed element to Form which generates XHTML + * + * Outputs the represented field using the passed Doku_Form object. + * Additional parameters (CSS class & HTML name) are passed in $params. + * HTML output is created by passing the template $this->tpl to the simple + * template engine _parse_tpl. + * + * @param array $params Additional HTML specific parameters + * @param Doku_Form $form The target Doku_Form object + * @param int $formid unique identifier of the form which contains this field + */ + public function renderfield($params, Doku_Form $form, $formid) { + $this->_handlePreload(); + if(!$form->_infieldset){ + $form->startFieldset(''); + } + if ($this->error) { + $params['class'] = 'bureaucracy_error'; + } + + $params = array_merge($this->opt, $params); + $form->addElement($this->_parse_tpl($this->tpl, $params)); + } + + /** + * Only the first use get the focus, next calls not + * + * @return bool + */ + protected static function hasFocus(){ + static $focus = true; + if($focus) { + $focus = false; + return true; + } else { + return false; + } + } + + + /** + * Check for preload value in the request url + */ + protected function _handlePreload() { + $preload_name = '@' . strtr($this->getParam('label'),' .','__') . '@'; + if (isset($_GET[$preload_name])) { + $this->setVal($_GET[$preload_name]); + } + } + + /** + * Handle a post to the field + * + * Accepts and validates a posted value. + * + * (Overridden by fieldset, which has as argument an array with the form array by reference) + * + * @param string $value The passed value or array or null if none given + * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field) + * @param int $index index number of field in form + * @param int $formid unique identifier of the form which contains this field + * @return bool Whether the passed value is valid + */ + public function handle_post($value, &$fields, $index, $formid) { + return $this->hidden || $this->setVal($value); + } + + /** + * Get the field type + * + * @return string + **/ + public function getFieldType() { + return $this->opt['cmd']; + } + + /** + * Get the replacement pattern used by action + * + * @return string + */ + public function getReplacementPattern() { + $label = $this->getParam('label'); + $value = $this->getParam('value'); + + if (is_array($value)) { + return '/(@@|##)' . preg_quote($label, '/') . + '(?:\((?P<delimiter>.*?)\))?' .//delimiter + '(?:\|(?P<default>.*?))' . (count($value) == 0 ? '' : '?') . + '\1/si'; + } + + return '/(@@|##)' . preg_quote($label, '/') . + '(?:\|(.*?))' . (is_null($value) ? '' : '?') . + '\1/si'; + } + + /** + * Used as an callback for preg_replace_callback + * + * @param $matches + * @return string + */ + public function replacementMultiValueCallback($matches) { + $value = $this->opt['value']; + + //default value + if (is_null($value) || $value === false) { + if (isset($matches['default']) && $matches['default'] != '') { + return $matches['default']; + } + return $matches[0]; + } + + //check if matched string containts a pair of brackets + $delimiter = preg_match('/\(.*\)/s', $matches[0]) ? $matches['delimiter'] : ', '; + + return implode($delimiter, $value); + } + + /** + * Get the value used by action + * If value is a callback preg_replace_callback is called instead preg_replace + * + * @return mixed|string + */ + public function getReplacementValue() { + $value = $this->getParam('value'); + + if (is_array($value)) { + return array($this, 'replacementMultiValueCallback'); + } + + return is_null($value) || $value === false ? '$2' : $value; + } + + /** + * Validate value and stores it + * + * @param mixed $value value entered into field + * @return bool whether the passed value is valid + */ + protected function setVal($value) { + if ($value === '') { + $value = null; + } + $this->opt['value'] = $value; + try { + $this->_validate(); + $this->error = false; + } catch (Exception $e) { + msg($e->getMessage(), -1); + $this->error = true; + } + return !$this->error; + } + + /** + * Whether the field is true (used for depending fieldsets) + * + * @return bool whether field is set + */ + public function isSet_() { + return !is_null($this->getParam('value')); + } + + /** + * Validate value of field and throws exceptions for bad values. + * + * @throws Exception when field didn't validate. + */ + protected function _validate() { + $value = $this->getParam('value'); + if (is_null($value)) { + if(!isset($this->opt['optional'])) { + throw new Exception(sprintf($this->getLang('e_required'),hsc($this->opt['label']))); + } + return; + } + + foreach ($this->checks as $check) { + $checktype = $this->checktypes[$check['t']]; + if (!call_user_func(array($this, 'validate_' . $checktype), $check['d'], $value)) { + //replacement is custom explanation or just the regexp or the requested value + if(isset($this->opt['matchexplanation'])) { + $replacement = hsc($this->opt['matchexplanation']); + } elseif($checktype == 'match') { + $replacement = sprintf($this->getLang('checkagainst'), hsc($check['d'])); + } else { + $replacement = hsc($check['d']); + } + + throw new Exception(sprintf($this->getLang('e_' . $checktype), hsc($this->opt['label']), $replacement)); + } + } + } + + /** + * Get an arbitrary parameter + * + * @param string $name + * @return mixed|null + */ + public function getParam($name) { + if (!isset($this->opt[$name]) || $name === 'value' && $this->hidden) { + return null; + } + if ($name === 'pagename') { + // If $this->opt['pagename'] is set, return the escaped value of the field. + $value = $this->getParam('value'); + if (is_null($value)) { + return null; + } + global $conf; + if($conf['useslash']) $value = str_replace('/',' ',$value); + return str_replace(':',' ',$value); + } + return $this->opt[$name]; + } + + /** + * Parse a template with given parameters + * + * Replaces variables specified like @@VARNAME|default@@ using the passed + * value map. + * + * @param string|array $tpl The template as string or array + * @param array $params A hash mapping parameters to values + * + * @return string|array The parsed template + */ + protected function _parse_tpl($tpl, $params) { + // addElement supports a special array format as well. In this case + // not all elements should be escaped. + $is_simple = !is_array($tpl); + if ($is_simple) $tpl = array($tpl); + + foreach ($tpl as &$val) { + // Select box passes options as an array. We do not escape those. + if (is_array($val)) continue; + + // find all variables and their defaults or param values + preg_match_all('/@@([A-Z]+)(?:\|((?:[^@]|@$|@[^@])*))?@@/', $val, $pregs); + for ($i = 0 ; $i < count($pregs[2]) ; ++$i) { + if (isset($params[strtolower($pregs[1][$i])])) { + $pregs[2][$i] = $params[strtolower($pregs[1][$i])]; + } + } + // we now have placeholders in $pregs[0] and their values in $pregs[2] + $replacements = array(); // check if empty to prevent php 5.3 warning + if (!empty($pregs[0])) { + $replacements = array_combine($pregs[0], $pregs[2]); + } + + if($is_simple){ + // for simple string templates, we escape all replacements + $replacements = array_map('hsc', $replacements); + }else{ + // for the array ones, we escape the label and display only + if(isset($replacements['@@LABEL@@'])) $replacements['@@LABEL@@'] = hsc($replacements['@@LABEL@@']); + if(isset($replacements['@@DISPLAY@@'])) $replacements['@@DISPLAY@@'] = hsc($replacements['@@DISPLAY@@']); + } + + // we attach a mandatory marker to the display + if(isset($replacements['@@DISPLAY@@']) && !isset($params['optional'])){ + $replacements['@@DISPLAY@@'] .= ' <sup>*</sup>'; + } + $val = str_replace(array_keys($replacements), array_values($replacements), $val); + } + return $is_simple ? $tpl[0] : $tpl; + } + + /** + * Executed after performing the action hooks + */ + public function after_action() { + } + + /** + * Constraint function: value of field should match this regexp + * + * @param string $d regexp + * @param mixed $value + * @return int|bool + */ + protected function validate_match($d, $value) { + return @preg_match('/' . $d . '/i', $value); + } + + /** + * Constraint function: value of field should be bigger + * + * @param int|number $d lower bound + * @param mixed $value of field + * @return bool + */ + protected function validate_min($d, $value) { + return $value > $d; + } + + /** + * Constraint function: value of field should be smaller + * + * @param int|number $d upper bound + * @param mixed $value of field + * @return bool + */ + protected function validate_max($d, $value) { + return $value < $d; + } + + /** + * Available methods + * + * @return array + */ + public function getMethods() { + $result = array(); + $result[] = array( + 'name' => 'initialize', + 'desc' => 'Initiate object, first parameters are at least cmd and label', + 'params' => array( + 'params' => 'array' + ) + ); + $result[] = array( + 'name' => 'renderfield', + 'desc' => 'Add parsed element to Form which generates XHTML', + 'params' => array( + 'params' => 'array', + 'form' => 'Doku_Form', + 'formid' => 'integer' + ) + ); + $result[] = array( + 'name' => 'handle_post', + 'desc' => 'Handle a post to the field', + 'params' => array( + 'value' => 'array', + 'fields' => 'helper_plugin_bureaucracy_field[]', + 'index' => 'Doku_Form', + 'formid' => 'integer' + ), + 'return' => array('isvalid' => 'bool') + ); + $result[] = array( + 'name' => 'getFieldType', + 'desc' => 'Get the field type', + 'return' => array('fieldtype' => 'string') + ); + $result[] = array( + 'name' => 'isSet_', + 'desc' => 'Whether the field is true (used for depending fieldsets) ', + 'return' => array('isset' => 'bool') + ); + $result[] = array( + 'name' => 'getParam', + 'desc' => 'Get an arbitrary parameter', + 'params' => array( + 'name' => 'string' + ), + 'return' => array('Parameter value' => 'mixed|null') + ); + $result[] = array( + 'name' => 'after_action', + 'desc' => 'Executed after performing the action hooks' + ); + return $result; + } + +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldaddpage.php b/platform/www/lib/plugins/bureaucracy/helper/fieldaddpage.php new file mode 100644 index 0000000..0c024fd --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldaddpage.php @@ -0,0 +1,63 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldaddpage + * + * Adds another page page_tgt based on a template page page_tpl only for use with the template action + */ +class helper_plugin_bureaucracy_fieldaddpage extends helper_plugin_bureaucracy_field { + + /** + * Arguments: + * - cmd + * - page_tpl + * - page_tgt + * + * @param array $args The tokenized definition, only split at spaces + */ + function initialize($args) { + if(count($args) < 3){ + msg(sprintf($this->getLang('e_missingargs'), hsc($args[0]), + hsc($args[1])), -1); + return; + } + + // get standard arguments + $this->opt = array_combine(array('cmd', 'page_tpl', 'page_tgt'), $args); + } + + /** + * Nothing displayed + * + * @params array $params Additional HTML specific parameters + * @params Doku_Form $form The target Doku_Form object + * @params int $formid unique identifier of the form which contains this field + */ + function renderfield($params, Doku_Form $form, $formid) { + } + + /** + * Handle a post to the field + * + * @param string $value null + * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field) + * @param int $index index number of field in form + * @param int $formid unique identifier of the form which contains this field + * @return bool Whether the passed value is valid + */ + function handle_post($value, &$fields, $index, $formid) { + return true; + } + + /** + * Get an arbitrary parameter + * + * @param string $name + * @return mixed|null + */ + function getParam($name) { + return ($name === 'value' || + (in_array($name, array('page_tpl', 'page_tgt')) && $this->hidden)) ? + null : + parent::getParam($name); + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fielddate.php b/platform/www/lib/plugins/bureaucracy/helper/fielddate.php new file mode 100644 index 0000000..6feae1c --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fielddate.php @@ -0,0 +1,42 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fielddate + * + * A date in the format YYYY-MM-DD, provides a date picker + */ +class helper_plugin_bureaucracy_fielddate extends helper_plugin_bureaucracy_fieldtextbox { + /** + * Arguments: + * - cmd + * - label + * - ^ (optional) + * + * @param array $args The tokenized definition, only split at spaces + */ + public function initialize($args) { + parent::initialize($args); + $attr = array( + 'class' => 'datepicker edit', + 'maxlength'=>'10' + ); + if(!isset($this->opt['optional'])) { + $attr['required'] = 'required'; + $attr['class'] .= ' required'; + } + $this->tpl = form_makeTextField('@@NAME@@', '@@VALUE@@', '@@DISPLAY@@', '@@ID@@', '@@CLASS@@', $attr); + } + + /** + * Validate field input + * + * @throws Exception when empty or wrong date format + */ + protected function _validate() { + parent::_validate(); + + $value = $this->getParam('value'); + if (!is_null($value) && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) { + throw new Exception(sprintf($this->getLang('e_date'),hsc($this->getParam('display')))); + } + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldemail.php b/platform/www/lib/plugins/bureaucracy/helper/fieldemail.php new file mode 100644 index 0000000..7857bd7 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldemail.php @@ -0,0 +1,30 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldemail + * + * Creates a single line input field where the input is validated to be a valid email address + */ +class helper_plugin_bureaucracy_fieldemail extends helper_plugin_bureaucracy_fieldtextbox { + + /** + * Arguments: + * - cmd + * - label + * - @@ (optional) + * - ^ (optional) + */ + + /** + * Validate field value + * + * @throws Exception when empty or not valid email address + */ + function _validate() { + parent::_validate(); + + $value = $this->getParam('value'); + if(!is_null($value) && $value !== '@MAIL@' && !mail_isvalid($value)){ + throw new Exception(sprintf($this->getLang('e_email'),hsc($this->getParam('display')))); + } + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldfieldset.php b/platform/www/lib/plugins/bureaucracy/helper/fieldfieldset.php new file mode 100644 index 0000000..ddce2b6 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldfieldset.php @@ -0,0 +1,114 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldfieldset + * + * Creates a new set of fields, which optional can be shown/hidden depending on the value of another field above it. + */ +class helper_plugin_bureaucracy_fieldfieldset extends helper_plugin_bureaucracy_field { + protected $mandatory_args = 1; + /** @var array with zero, one entry (fieldname) or two entries (fieldname and match value) */ + public $depends_on = array(); + + /** + * Arguments: + * - cmd + * - label (optional) + * - field name where switching depends on (optional) + * - match value (optional) + * + * @param array $args The tokenized definition, only split at spaces + */ + public function initialize($args) { + // get standard arguments + $this->opt = array('cmd' => array_shift($args)); + + if (count($args) > 0) { + $this->opt['label'] = array_shift($args); + $this->opt['display'] = $this->opt['label']; + + $this->depends_on = $args; + } + } + + /** + * Render the top of the fieldset as XHTML + * + * @param array $params Additional HTML specific parameters + * @param Doku_Form $form The target Doku_Form object + * @param int $formid unique identifier of the form which contains this field + */ + function renderfield($params, Doku_Form $form, $formid) { + $form->startFieldset(hsc($this->getParam('display'))); + if (!empty($this->depends_on)) { + $dependencies = array_map('hsc',(array) $this->depends_on); + if (count($this->depends_on) > 1) { + $msg = 'Only edit this fieldset if ' . + '“<span class="bureaucracy_depends_fname">%s</span>” '. + 'is set to “<span class="bureaucracy_depends_fvalue">%s</span>”.'; + } else { + $msg = 'Only edit this fieldset if ' . + '“<span class="bureaucracy_depends_fname">%s</span>” is set.'; + } + + $form->addElement('<p class="bureaucracy_depends">' . vsprintf($msg, $dependencies) . '</p>'); + } + } + + /** + * Handle a post to the fieldset + * + * When fieldset is closed, set containing fields to hidden + * + * @param null $value field value of fieldset always empty + * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field) + * @param int $index index number of field in form + * @param int $formid unique identifier of the form which contains this field + * @return bool Whether the passed value is valid + */ + public function handle_post($value, &$fields, $index, $formid) { + if(empty($this->depends_on)) { + return true; + } + + // search the field where fieldset depends on in fields before fieldset + $hidden = false; + for ($n = 0 ; $n < $index; ++$n) { + $field = $fields[$n]; + if ($field->getParam('label') != $this->depends_on[0]) { + continue; + } + if(count($this->depends_on) > 1) { + $hidden = $field->getParam('value') != $this->depends_on[1]; + } else { + $hidden = !$field->isSet_(); + } + break; + } + // mark fields after this fieldset as hidden + if ($hidden) { + $this->hidden = true; + for ($n = $index + 1 ; $n < count($fields) ; ++$n) { + $field = $fields[$n]; + if ($field->getFieldType() === 'fieldset') { + break; + } + $field->hidden = true; + } + } + return true; + } + + /** + * Get an arbitrary parameter + * + * @param string $name + * @return mixed|null + */ + function getParam($name) { + if($name === 'value') { + return null; + } else { + return parent::getParam($name); + } + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldfile.php b/platform/www/lib/plugins/bureaucracy/helper/fieldfile.php new file mode 100644 index 0000000..285308e --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldfile.php @@ -0,0 +1,75 @@ +<?php + +/** + * File upload field + */ +class helper_plugin_bureaucracy_fieldfile extends helper_plugin_bureaucracy_field { + + /** + * Arguments: + * - cmd + * - label + * - ^ (optional) + * + * @param array $args The tokenized definition, only split at spaces + */ + function initialize($args) { + $this->init($args); + + //default namespace for file upload (pagepath:file_name) + $this->opt['namespace'] = '.'; + + //check whenever the first argument is an upload namespace + if (isset($args[0]) && preg_match('/^[a-z.\-_:]+$/', $args[0])) { + $this->opt['namespace'] = array_shift($args); + } + $this->standardArgs($args); + + $attr = array(); + if(!isset($this->opt['optional'])) { + $attr['required'] = 'required'; + } + + $this->tpl = form_makeFileField('@@NAME@@', '@@DISPLAY@@', '@@ID@@', '@@CLASS@@', $attr); + + if(!isset($this->opt['optional'])){ + $this->tpl['class'] .= ' required'; + } + } + + /** + * Handle a post to the field + * + * Accepts and validates a posted value. + * + * @param array $value The passed value or array or null if none given + * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field) + * @param int $index index number of field in form + * @param int $formid unique identifier of the form which contains this field + * @return bool Whether the passed filename is valid + */ + public function handle_post($value, &$fields, $index, $formid) { + $this->opt['file'] = $value; + + return parent::handle_post($value['name'], $fields, $index, $formid); + } + + /** + * @throws Exception max size, required or upload error + */ + protected function _validate() { + global $lang; + parent::_validate(); + + $file = $this->getParam('file'); + if($file['error'] == 1 || $file['error'] == 2) { + throw new Exception(sprintf($lang['uploadsize'],filesize_h(php_to_byte(ini_get('upload_max_filesize'))))); + } else if($file['error'] == 4) { + if(!isset($this->opt['optional'])) { + throw new Exception(sprintf($this->getLang('e_required'),hsc($this->opt['label']))); + } + } else if( $file['error'] || !is_uploaded_file($file['tmp_name'])) { + throw new Exception(hsc($this->opt['label']) .' '. $lang['uploadfail'] . ' (' .$file['error'] . ')' ); + } + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldhidden.php b/platform/www/lib/plugins/bureaucracy/helper/fieldhidden.php new file mode 100644 index 0000000..dd63753 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldhidden.php @@ -0,0 +1,47 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldhidden + * + * Creates an invisible field with static data + */ +class helper_plugin_bureaucracy_fieldhidden extends helper_plugin_bureaucracy_field { + + /** + * Arguments: + * - cmd + * - label + * - =default value + */ + + /** + * Render the field as XHTML + * + * Outputs the represented field using the passed Doku_Form object. + * + * @param array $params Additional HTML specific parameters + * @param Doku_Form $form The target Doku_Form object + * @param int $formid unique identifier of the form which contains this field + */ + function renderfield($params, Doku_Form $form, $formid) { + $this->_handlePreload(); + $form->addHidden($params['name'], $this->getParam('value') . ''); + } + + /** + * Get an arbitrary parameter + * + * @param string $name + * @return mixed|null + */ + function getParam($name) { + if (!isset($this->opt[$name]) || in_array($name, array('pagename', 'value')) && $this->hidden) { + return null; + } + if ($name === 'pagename') { + // If $this->opt['pagename'] is set, return the value of the field, + // UNESCAPED. + $name = 'value'; + } + return $this->opt[$name]; + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldhiddenautoinc.php b/platform/www/lib/plugins/bureaucracy/helper/fieldhiddenautoinc.php new file mode 100644 index 0000000..787e081 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldhiddenautoinc.php @@ -0,0 +1,35 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldhiddenautoinc + * + * Creates an invisible field with a number that increases by 1 on each form submit + */ +class helper_plugin_bureaucracy_fieldhiddenautoinc extends helper_plugin_bureaucracy_fieldnumber { + + /** + * Arguments: + * - cmd + * - label + * + * @param array $args The tokenized definition, only split at spaces + */ + function initialize($args) { + $args[] = '++'; + parent::initialize($args); + } + + /** + * Render the field as XHTML + * + * Outputs the represented field using the passed Doku_Form object. + * + * @param array $params Additional HTML specific parameters + * @param Doku_Form $form The target Doku_Form object + * @param $formid + */ + function renderfield($params, Doku_Form $form, $formid) { + $this->_handlePreload(); + $form->addHidden($params['name'], $this->getParam('value') . ''); + } + +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldmultiselect.php b/platform/www/lib/plugins/bureaucracy/helper/fieldmultiselect.php new file mode 100644 index 0000000..5311d90 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldmultiselect.php @@ -0,0 +1,62 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldmultiselect + * + * Creates a multiselect box + */ +class helper_plugin_bureaucracy_fieldmultiselect extends helper_plugin_bureaucracy_fieldselect { + + /** + * Arguments: + * - cmd + * - label + * - option1|option2|etc + * - ^ (optional) + * + * @param array $args The tokenized definition, only split at spaces + */ + public function initialize($args) { + $this->init($args); + $this->opt['args'] = array_map('trim', explode('|',array_shift($args))); + $this->standardArgs($args); + if (isset($this->opt['value'])) { + $this->opt['value'] = array_map('trim', explode(',', $this->opt['value'])); + } else { + $this->opt['value'] = array(); + } + } + + /** + * Render the field as XHTML + * + * Outputs the represented field using the passed Doku_Form object. + * Additional parameters (CSS class & HTML name) are passed in $params. + * + * @params array $params Additional HTML specific parameters + * @params Doku_Form $form The target Doku_Form object + * @params int $formid unique identifier of the form which contains this field + */ + public function renderfield($params, Doku_Form $form, $formid) { + $this->_handlePreload(); + if(!$form->_infieldset){ + $form->startFieldset(''); + } + if ($this->error) { + $params['class'] = 'bureaucracy_error'; + } + $params = array_merge($this->opt, $params); + $form->addElement(call_user_func_array('form_makeListboxField', + $this->_parse_tpl( + array( + '@@NAME@@[]', + $params['args'], + $this->opt['value'], + '@@DISPLAY@@', + '@@ID@@', + '@@CLASS@@', + array('multiple' => 'multiple') + ), + $params + ))); + } +}
\ No newline at end of file diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldnumber.php b/platform/www/lib/plugins/bureaucracy/helper/fieldnumber.php new file mode 100644 index 0000000..93a2242 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldnumber.php @@ -0,0 +1,119 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldnumber + * + * Creates a single line input field, where input is validated to be numeric + */ +class helper_plugin_bureaucracy_fieldnumber extends helper_plugin_bureaucracy_fieldtextbox { + + private $autoinc = false; + + /** + * Arguments: + * - cmd + * - label + * - ++ (optional) + * - 0000 (optional) + * - ^ (optional) + * + * @param array $args The tokenized definition, only split at spaces + */ + public function initialize($args) { + $pp = array_search('++', $args, true); + if ($pp !== false) { + unset($args[$pp]); + $this->autoinc = true; + } + + parent::initialize($args); + + if ($this->autoinc) { + global $ID; + $key = $this->get_key(); + $c_val = p_get_metadata($ID, 'bureaucracy ' . $key); + if (is_null($c_val)) { + if (!isset($this->opt['value'])) { + $this->opt['value'] = 0; + } + p_set_metadata($ID, array('bureaucracy' => array($key => $this->opt['value']))); + } else { + $this->opt['value'] = $c_val; + } + } + $this->opt['value'] = $this->addLeadingzeros($this->opt['value']); + } + + /** + * Validate field value + * + * @throws Exception when not a number + */ + protected function _validate() { + $value = $this->getParam('value'); + if (!is_null($value) && !is_numeric($value)){ + throw new Exception(sprintf($this->getLang('e_numeric'),hsc($this->getParam('display')))); + } + + parent::_validate(); + } + + /** + * Handle a post to the field + * + * Accepts and validates a posted value. + * + * @param string $value The passed value or array or null if none given + * @param array $fields (reference) form fields (POST handled upto $this field) + * @param int $index index number of field in form + * @param int $formid unique identifier of the form which contains this field + * @return bool Whether the passed value is valid + */ + public function handle_post($value, &$fields, $index, $formid) { + $value = $this->addLeadingzeros($value); + + return parent::handle_post($value, $fields, $index, $formid); + } + + /** + * Returns the cleaned key for this field required for metadata + * + * @return string key + */ + private function get_key() { + return preg_replace('/\W/', '', $this->opt['label']) . '_autoinc'; + } + + /** + * Executed after performing the action hooks + * + * Increases counter and purge cache + */ + public function after_action() { + if ($this->autoinc) { + global $ID; + p_set_metadata($ID, array('bureaucracy' => array($this->get_key() => $this->opt['value'] + 1))); + // Force rerendering by removing the instructions cache file + $cache_fn = getCacheName(wikiFN($ID).$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'],'.'.'i'); + if (file_exists($cache_fn)) { + unlink($cache_fn); + } + } + } + + /** + * Add leading zeros, depending on the corresponding field option + * + * @param int|string $value number + * @return string + */ + protected function addLeadingzeros(&$value) { + if (isset($this->opt['leadingzeros'])) { + $length = strlen($value); + for($i = $length; $i < $this->opt['leadingzeros']; $i++) { + $value = '0' . $value; + } + return $value; + } + return $value; + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldonoff.php b/platform/www/lib/plugins/bureaucracy/helper/fieldonoff.php new file mode 100644 index 0000000..d73177b --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldonoff.php @@ -0,0 +1,16 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldonoff + * + * Creates a checkbox + */ +class helper_plugin_bureaucracy_fieldonoff extends helper_plugin_bureaucracy_fieldyesno { + /** + * Arguments: + * - cmd + * - label + * - =yesvalue + * - !falsevalue + * - ^ (optional) + */ +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldpassword.php b/platform/www/lib/plugins/bureaucracy/helper/fieldpassword.php new file mode 100644 index 0000000..e4e20f4 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldpassword.php @@ -0,0 +1,29 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldpassword + * + * Creates a single line password input field + */ +class helper_plugin_bureaucracy_fieldpassword extends helper_plugin_bureaucracy_field { + /** + * Arguments: + * - cmd + * - label + * - ^ (optional) + * + * @param array $args The tokenized definition, only split at spaces + */ + function initialize($args) { + parent::initialize($args); + + $attr = array(); + if(!isset($this->opt['optional'])) { + $attr['required'] = 'required'; + } + $this->tpl = form_makePasswordField('@@NAME@@', '@@DISPLAY@@', '@@ID@@', '@@CLASS@@', $attr); + + if(!isset($this->opt['optional'])){ + $this->tpl['class'] .= ' required'; + } + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldradio.php b/platform/www/lib/plugins/bureaucracy/helper/fieldradio.php new file mode 100644 index 0000000..e2b466d --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldradio.php @@ -0,0 +1,82 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldselect + * + * Creates a dropdown list + */ +class helper_plugin_bureaucracy_fieldradio extends helper_plugin_bureaucracy_field { + + protected $mandatory_args = 3; + + /** + * Arguments: + * - cmd + * - label + * - option1|option2|etc + * - ^ (optional) + * + * @param array $args The tokenized definition, only split at spaces + */ + public function initialize($args) { + $this->init($args); + $this->opt['args'] = array_filter(array_map('trim', explode('|',array_shift($args)))); + $this->standardArgs($args); + } + + /** + * Render the field as XHTML + * + * Outputs the represented field using the passed Doku_Form object. + * Additional parameters (CSS class & HTML name) are passed in $params. + * + * @params array $params Additional HTML specific parameters + * @params Doku_Form $form The target Doku_Form object + * @params int $formid unique identifier of the form which contains this field + */ + public function renderfield($params, Doku_Form $form, $formid) { + $this->_handlePreload(); + if(!$form->_infieldset){ + $form->startFieldset(''); + } + if ($this->error) { + $params['class'] = 'bureaucracy_error'; + } + $params = array_merge($this->opt, $params); + + list($name, $entries, $value, $label, $id, $class) = $this->_parse_tpl( + array( + '@@NAME@@', + $params['args'], + '@@VALUE@@', + '@@DISPLAY@@', + '@@ID@@', + '@@CLASS@@' + ), + $params + ); + + $value = (in_array($value, $entries) ? $value : null); + $valueoffieldwithid = ($value !== null ? $value : current($entries)); + // label + $s = '<label'; + $s .= ' class="radiolabel '.$class.'"'; + $s .= '><span>' . $label . '</span>'; + $s .= '</label>'; + $form->addElement($s); + + // radio fields + foreach($entries as $val) { + if($value === $val) { + $attrs = array('checked' => 'checked'); + } else { + $attrs = array(); + } + if($valueoffieldwithid === $val) { + $_id = $id; //e.g. autofocus with 'focus__this' id + } else { + $_id = ''; + } + $form->addElement(form_makeRadioField($name, $val, $val, $_id, $class, $attrs)); + } + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldselect.php b/platform/www/lib/plugins/bureaucracy/helper/fieldselect.php new file mode 100644 index 0000000..391e562 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldselect.php @@ -0,0 +1,61 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldselect + * + * Creates a dropdown list + */ +class helper_plugin_bureaucracy_fieldselect extends helper_plugin_bureaucracy_field { + + protected $mandatory_args = 3; + + /** + * Arguments: + * - cmd + * - label + * - option1|option2|etc + * - ^ (optional) + * + * @param array $args The tokenized definition, only split at spaces + */ + public function initialize($args) { + $this->init($args); + $this->opt['args'] = array_map('trim', explode('|',array_shift($args))); + $this->standardArgs($args); + if (!isset($this->opt['value']) && isset($this->opt['optional'])) { + array_unshift($this->opt['args'],' '); + } + } + + /** + * Render the field as XHTML + * + * Outputs the represented field using the passed Doku_Form object. + * Additional parameters (CSS class & HTML name) are passed in $params. + * + * @params array $params Additional HTML specific parameters + * @params Doku_Form $form The target Doku_Form object + * @params int $formid unique identifier of the form which contains this field + */ + public function renderfield($params, Doku_Form $form, $formid) { + $this->_handlePreload(); + if(!$form->_infieldset){ + $form->startFieldset(''); + } + if ($this->error) { + $params['class'] = 'bureaucracy_error'; + } + $params = array_merge($this->opt, $params); + $form->addElement(call_user_func_array('form_makeListboxField', + $this->_parse_tpl( + array( + '@@NAME@@', + $params['args'], + '@@VALUE|' . $params['args'][0] . '@@', + '@@DISPLAY@@', + '@@ID@@', + '@@CLASS@@' + ), + $params + ))); + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldstatic.php b/platform/www/lib/plugins/bureaucracy/helper/fieldstatic.php new file mode 100644 index 0000000..191be72 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldstatic.php @@ -0,0 +1,60 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldstatic + * + * Adds some static text to the form + */ +class helper_plugin_bureaucracy_fieldstatic extends helper_plugin_bureaucracy_field { + protected $tpl = '<p>@@DISPLAY@@</p>'; + + /** + * Arguments: + * - cmd + * - text + * + * @param array $args The tokenized definition, only split at spaces + */ + public function initialize($args) { + parent::initialize($args); + // make always optional to prevent being marked as required + $this->opt['optional'] = true; + } + + /** + * Handle a post to the field + * + * @param string $value The passed value + * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field) + * @param int $index index number of field in form + * @param int $formid unique identifier of the form which contains this field + * @return bool Whether the passed value is valid + */ + public function handle_post($value, &$fields, $index, $formid) { + return true; + } + + /** + * Get an arbitrary parameter + * + * @param string $name + * @return mixed|null + */ + public function getParam($name) { + return ($name === 'value') ? null : parent::getParam($name); + } + + /** + * Render the field as XHTML + * + * @params array $params Additional HTML specific parameters + * @params Doku_Form $form The target Doku_Form object + * @params int $formid unique identifier of the form which contains this field + */ + public function renderfield($params, Doku_Form $form, $formid) { + if (!isset($this->opt['display'])) { + $this->opt['display'] = $this->opt['label']; + } + parent::renderfield($params, $form, $formid); + } + +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldsubject.php b/platform/www/lib/plugins/bureaucracy/helper/fieldsubject.php new file mode 100644 index 0000000..f49c2b7 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldsubject.php @@ -0,0 +1,37 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldsubject + * + * Defines own subject for mail action from this form + */ +class helper_plugin_bureaucracy_fieldsubject extends helper_plugin_bureaucracy_field { + /** + * Arguments: + * - cmd + * - subjecttext + */ + + /** + * Render the field as XHTML + * + * @params array $params Additional HTML specific parameters + * @params Doku_Form $form The target Doku_Form object + * @params int $formid unique identifier of the form which contains this field + */ + public function renderfield($params, Doku_Form $form, $formid) { + $this->_handlePreload(); + } + + /** + * Handle a post to the field + * + * @param string $value null + * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field) + * @param int $index index number of field in form + * @param int $formid unique identifier of the form which contains this field + * @return bool Whether the passed value is valid + */ + function handle_post($value, &$fields, $index, $formid) { + return true; + } +}
\ No newline at end of file diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldsubmit.php b/platform/www/lib/plugins/bureaucracy/helper/fieldsubmit.php new file mode 100644 index 0000000..b9f2e45 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldsubmit.php @@ -0,0 +1,89 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldsubmit + * + * Creates a submit button + */ +class helper_plugin_bureaucracy_fieldsubmit extends helper_plugin_bureaucracy_field { + protected $mandatory_args = 1; + static $captcha_displayed = array(); + static $captcha_checked = array(); + + /** + * Arguments: + * - cmd + * - label (optional) + * - ^ (optional) + * + * @param array $args The tokenized definition, only split at spaces + */ + public function initialize($args) { + parent::initialize($args); + // make always optional to prevent being marked as required + $this->opt['optional'] = true; + } + + /** + * Render the field as XHTML + * + * @params array $params Additional HTML specific parameters + * @params Doku_Form $form The target Doku_Form object + * @params int $formid unique identifier of the form which contains this field + */ + public function renderfield($params, Doku_Form $form, $formid) { + if(!isset(helper_plugin_bureaucracy_fieldsubmit::$captcha_displayed[$formid])) { + helper_plugin_bureaucracy_fieldsubmit::$captcha_displayed[$formid] = true; + /** @var helper_plugin_captcha $helper */ + $helper = null; + if(@is_dir(DOKU_PLUGIN.'captcha')) $helper = plugin_load('helper','captcha'); + if(!is_null($helper) && $helper->isEnabled()){ + $form->addElement($helper->getHTML()); + } + } + $attr = array(); + if(isset($this->opt['id'])) { + $attr['id'] = $this->opt['id']; + } + $this->tpl = form_makeButton('submit','', '@@DISPLAY|' . $this->getLang('submit') . '@@', $attr); + parent::renderfield($params, $form, $formid); + } + + /** + * Handle a post to the field + * + * Accepts and validates a posted captcha value. + * + * @param string $value The passed value + * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field) + * @param int $index index number of field in form + * @param int $formid unique identifier of the form which contains this field + * @return bool Whether the posted form has a valid captcha + */ + public function handle_post($value, &$fields, $index, $formid) { + if ($this->hidden) { + return true; + } + if(!isset(helper_plugin_bureaucracy_fieldsubmit::$captcha_checked[$formid])) { + helper_plugin_bureaucracy_fieldsubmit::$captcha_checked[$formid] = true; + // check CAPTCHA + /** @var helper_plugin_captcha $helper */ + $helper = null; + if(@is_dir(DOKU_PLUGIN.'captcha')) $helper = plugin_load('helper','captcha'); + if(!is_null($helper) && $helper->isEnabled()){ + return $helper->check(); + } + } + return true; + } + + /** + * Get an arbitrary parameter + * + * @param string $name + * @return mixed|null + */ + public function getParam($name) { + return ($name === 'value') ? null : parent::getParam($name); + } + +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldtextarea.php b/platform/www/lib/plugins/bureaucracy/helper/fieldtextarea.php new file mode 100644 index 0000000..0dfcce2 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldtextarea.php @@ -0,0 +1,29 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldtextarea + * + * Creates a multi-line input field + */ +class helper_plugin_bureaucracy_fieldtextarea extends helper_plugin_bureaucracy_field { + /** + * Arguments: + * - cmd + * - label + * - x123 (optional) as number of lines + * - ^ (optional) + */ + public function initialize($args) { + parent::initialize($args); + if (!isset($this->opt['class'])) { + $this->opt['class'] = ''; + } + $this->opt['class'] .= ' textareafield'; + } + + protected $tpl = +'<label class="@@CLASS@@"> + <span>@@DISPLAY@@</span> + <textarea name="@@NAME@@" id="@@ID@@" rows="@@ROWS|10@@" cols="10" class="edit @@OPTIONAL|required" required="required@@">@@VALUE@@</textarea> +</label>'; + +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldtextbox.php b/platform/www/lib/plugins/bureaucracy/helper/fieldtextbox.php new file mode 100644 index 0000000..430cc2d --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldtextbox.php @@ -0,0 +1,34 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldtextbox + * + * Creates a single line input field + */ +class helper_plugin_bureaucracy_fieldtextbox extends helper_plugin_bureaucracy_field { + + /** + * Arguments: + * - cmd + * - label + * - =default (optional) + * - ^ (optional) + * + * @param array $args The tokenized definition, only split at spaces + */ + function initialize($args) { + parent::initialize($args); + + $attr = array(); + if(!isset($this->opt['optional'])) { + $attr['required'] = 'required'; + } + + $this->tpl = form_makeTextField('@@NAME@@', '@@VALUE@@', '@@DISPLAY@@', '@@ID@@', '@@CLASS@@', $attr); + if(isset($this->opt['class'])){ + $this->tpl['class'] .= ' '.$this->opt['class']; + } + if(!isset($this->opt['optional'])){ + $this->tpl['class'] .= ' required'; + } + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldtime.php b/platform/www/lib/plugins/bureaucracy/helper/fieldtime.php new file mode 100644 index 0000000..164e71f --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldtime.php @@ -0,0 +1,42 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldtime + * + * A time in the format (h)h:mm(:ss) + */ +class helper_plugin_bureaucracy_fieldtime extends helper_plugin_bureaucracy_fieldtextbox { + /** + * Arguments: + * - cmd + * - label + * - ^ (optional) + * + * @param array $args The tokenized definition, only split at spaces + */ + public function initialize($args) { + parent::initialize($args); + $attr = array( + 'class' => 'timefield edit', + 'maxlength'=>'8' + ); + if(!isset($this->opt['optional'])) { + $attr['required'] = 'required'; + $attr['class'] .= ' required'; + } + $this->tpl = form_makeTextField('@@NAME@@', '@@VALUE@@', '@@DISPLAY@@', '@@ID@@', '@@CLASS@@', $attr); + } + + /** + * Validate field input + * + * @throws Exception when empty or wrong time format + */ + protected function _validate() { + parent::_validate(); + + $value = $this->getParam('value'); + if (!is_null($value) && !preg_match('/^\d{1,2}:\d{2}(?::\d{2})?$/', $value)) { + throw new Exception(sprintf($this->getLang('e_time'),hsc($this->getParam('display')))); + } + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldusemailtemplate.php b/platform/www/lib/plugins/bureaucracy/helper/fieldusemailtemplate.php new file mode 100644 index 0000000..775f87b --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldusemailtemplate.php @@ -0,0 +1,62 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldusemailtemplate + * + * Adds a template only for use with the mail action + */ +class helper_plugin_bureaucracy_fieldusemailtemplate extends helper_plugin_bureaucracy_field { + + /** + * Arguments: + * - cmd + * - template + * + * @param array $args The tokenized definition, only split at spaces + */ + function initialize($args) { + if(count($args) < 2){ + msg(sprintf($this->getLang('e_missingargs'), hsc($args[0]), + hsc($args[1])), -1); + return; + } + + // get standard arguments + $this->opt = array_combine(array('cmd', 'template'), $args); + } + + /** + * Nothing displayed + * + * @params array $params Additional HTML specific parameters + * @params Doku_Form $form The target Doku_Form object + * @params int $formid unique identifier of the form which contains this field + */ + function renderfield($params, Doku_Form $form, $formid) { + } + + /** + * Handle a post to the field + * + * @param string $value null + * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field) + * @param int $index index number of field in form + * @param int $formid unique identifier of the form which contains this field + * @return bool Whether the passed value is valid + */ + function handle_post($value, &$fields, $index, $formid) { + return true; + } + + /** + * Get an arbitrary parameter + * + * @param string $name + * @return mixed|null + */ + function getParam($name) { + return ($name === 'value' || + (in_array($name, array('template')) && $this->hidden)) ? + null : + parent::getParam($name); + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fielduser.php b/platform/www/lib/plugins/bureaucracy/helper/fielduser.php new file mode 100644 index 0000000..49608e1 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fielduser.php @@ -0,0 +1,99 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fielduser + * + * Create single user input, with autocompletion + */ +class helper_plugin_bureaucracy_fielduser extends helper_plugin_bureaucracy_fieldtextbox { + + /** + * Arguments: + * - cmd + * - label + * - ^ (optional) + * + * @param array $args The tokenized definition, only split at spaces + */ + public function initialize($args) { + parent::initialize($args); + $this->tpl['class'] .= ' userpicker'; + } + + /** + * Allow receiving user attributes by ".". Ex. user.name + * You can pass an optional argument to user.grps enclosed in brackets, used as an groups delimiter Ex. user.grps(, ) + * + * @return string + */ + public function getReplacementPattern() { + $label = $this->opt['label']; + + return '/(@@|##)' . preg_quote($label, '/') . + '(?:\.(.*?))?' . //match attribute after "." + '(?:\((.*?)\))?' . //match parameter enclosed in "()". Used for grps separator + '\1/si'; + } + + /** + * Used as an callback for preg_replace_callback + * + * @param $matches + * @return string + */ + public function replacementValueCallback($matches) { + /** @var DokuWiki_Auth_Plugin $auth */ + global $auth; + + $value = $this->opt['value']; + //attr doesn't exists + if (!isset($matches[2])) { + return is_null($value) || $value === false ? '' : $value; + } + $attr = $matches[2]; + + $udata = $auth->getUserData($value); + //no such user + if ($udata === false) { + return $matches[0]; + } + + switch($attr) { + case 'name': + case 'mail': + return $udata[$attr]; + case 'grps': + $delitmiter = ', '; + if (isset($matches[3])) { + $delitmiter = $matches[3]; + } + return implode($delitmiter, $udata['grps']); + default: + return $matches[0]; + } + } + + /** + * Return the callback for user replacement + * + * @return array + */ + public function getReplacementValue() { + return array($this, 'replacementValueCallback'); + } + + /** + * Validate value of field + * + * @throws Exception when user not exists + */ + protected function _validate() { + parent::_validate(); + + /** @var DokuWiki_Auth_Plugin $auth */ + global $auth; + $value = $this->getParam('value'); + if (!is_null($value) && $auth->getUserData($value) === false) { + throw new Exception(sprintf($this->getLang('e_user'),hsc($this->getParam('display')))); + } + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldusers.php b/platform/www/lib/plugins/bureaucracy/helper/fieldusers.php new file mode 100644 index 0000000..bd5dce7 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldusers.php @@ -0,0 +1,96 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldusers + * + * Create multi-user input, with autocompletion + */ +class helper_plugin_bureaucracy_fieldusers extends helper_plugin_bureaucracy_fieldtextbox { + + /** + * Arguments: + * - cmd + * - label + * - ^ (optional) + * + * @param array $args The tokenized definition, only split at spaces + */ + public function initialize($args) { + parent::initialize($args); + $this->tpl['class'] .= ' userspicker'; + } + + /** + * Allow receiving user attributes by ".". Ex. user.name + * You can pass an optional argument to user.grps enclosed in brackets, used as an groups delimiter Ex. user.grps(, ) + * + * @return string + */ + public function getReplacementPattern() { + $label = $this->opt['label']; + return '/(@@|##)' . preg_quote($label, '/') . + '(?:\((?P<delimiter>.*?)\))?' .//delimiter + '(?:\.(?P<attribute>.*?))?' . //match attribute after "." + '\1/si'; + } + + /** + * Used as an callback for preg_replace_callback + * + * @param $matches + * @return string + */ + public function replacementValueCallback($matches) { + /** @var DokuWiki_Auth_Plugin $auth */ + global $auth; + + $value = $this->opt['value']; + //copy the value by default + if (isset($matches[2]) && is_array($matches[2]) && count($matches[2]) == 2) { + return is_null($value) || $value === false ? $matches[0] : $value; + } + + $attribute = isset($matches['attribute']) ? $matches['attribute'] : ''; + //check if matched string containts a pair of brackets + $delimiter = preg_match('/\(.*\)/s', $matches[0]) ? $matches['delimiter'] : ', '; + $users = array_map('trim', explode(',', $value)); + + switch($attribute) { + case '': + return implode($delimiter, $users); + case 'name': + case 'mail': + return implode($delimiter, array_map(function ($user) use ($auth, $attribute) { + return $auth->getUserData($user)[$attribute]; + }, $users)); + default: + return $matches[0]; + } + } + + /** + * Return the callback for user replacement + * + * @return array + */ + public function getReplacementValue() { + return array($this, 'replacementValueCallback'); + } + + /** + * Validate value of field + * + * @throws Exception when user not exists + */ + protected function _validate() { + parent::_validate(); + + /** @var DokuWiki_Auth_Plugin $auth */ + global $auth; + $users = array_filter(preg_split('/\s*,\s*/', $this->getParam('value'))); + foreach ($users as $user) { + if ($auth->getUserData($user) === false) { + throw new Exception(sprintf($this->getLang('e_users'), hsc($this->getParam('display')))); + } + } + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldwiki.php b/platform/www/lib/plugins/bureaucracy/helper/fieldwiki.php new file mode 100644 index 0000000..dada855 --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldwiki.php @@ -0,0 +1,70 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldwiki + * + * Adds some static text to the form, but parses the input as Wiki syntax (computationally expensive) + */ +class helper_plugin_bureaucracy_fieldwiki extends helper_plugin_bureaucracy_field { + + protected $tpl = '<p>@@LABEL@@</p>'; + + /** + * Arguments: + * - cmd + * - wiki text + * + * @param array $args The tokenized definition, only split at spaces + */ + public function initialize($args) { + parent::initialize($args); + // make always optional to prevent being marked as required + $this->opt['optional'] = true; + } + + /** + * Handle a post to the field + * + * @param null $value empty + * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field) + * @param int $index index number of field in form + * @param int $formid unique identifier of the form which contains this field + * @return bool Whether the passed value is valid + */ + public function handle_post($value, &$fields, $index, $formid) { + return true; + } + + /** + * Get an arbitrary parameter + * + * @param string $name + * @return mixed|null + */ + public function getParam($name) { + return ($name === 'value') ? null : parent::getParam($name); + } + + /** + * Returns parsed wiki instructions + * + * @param string|array $tpl The template as string + * @param array $params A hash mapping parameters to values + * + * @return string The parsed template + */ + protected function _parse_tpl($tpl, $params) { + $ins = p_get_instructions($params['display']); + // remove document and p instructions (opening and closing) + $start = 2; + $end = 2; + // check if struct instructions have to be removed as well from the beginning or end + if (isset($ins[1][1][0]) && $ins[1][1][0] === 'struct_output') { + $start = 3; + } elseif (isset($ins[count($ins) - 2][1][0]) && $ins[count($ins) - 2][1][0] === 'struct_output') { + $end = 3; + } + $ins = array_slice($ins, $start, -$end); + $tpl = p_render('xhtml', $ins, $byref_ignore); + return '<p>'.$tpl.'</p>'; + } +} diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldyesno.php b/platform/www/lib/plugins/bureaucracy/helper/fieldyesno.php new file mode 100644 index 0000000..77b83de --- /dev/null +++ b/platform/www/lib/plugins/bureaucracy/helper/fieldyesno.php @@ -0,0 +1,98 @@ +<?php +/** + * Class helper_plugin_bureaucracy_fieldyesno + * + * Creates a checkbox + */ +class helper_plugin_bureaucracy_fieldyesno extends helper_plugin_bureaucracy_field { + + /** + * Arguments: + * - cmd + * - label + * - =yesvalue + * - !falsevalue + * - ^ (optional) + * + * @param array $args The tokenized definition, only split at spaces + */ + public function initialize($args) { + $this->init($args); + $newargs = array(); + foreach ($args as $arg) { + switch ($arg[0]) { + case '=': + if($arg == '==1') { + $this->opt['value'] = '1'; + }elseif($arg == '==0') { + $this->opt['value'] = '0'; + }else{ + $this->opt['true_value'] = substr($arg, 1); + } + break; + case '!': + $this->opt['false_value'] = substr($arg, 1); + break; + default: + $newargs[] = $arg; + } + } + $this->standardArgs($newargs); + $this->opt['optional'] = true; + } + + /** + * Get an arbitrary parameter + * + * @param string $key + * @return mixed|null + */ + public function getParam($key) { + if ($key === 'value') { + if ($this->opt['value'] === '1') { + return isset($this->opt['true_value']) ? + $this->opt['true_value'] : + null; + } elseif ($this->opt['value'] === '0') { + return isset($this->opt['false_value']) ? + $this->opt['false_value'] : + null; + } + } + return parent::getParam($key); + } + + /** + * Whether the field is true (used for depending fieldsets) + * + * @return bool whether field is set + */ + public function isSet_() { + return $this->opt['value'] === '1'; + } + + /** + * Render the field as XHTML + * + * @params array $params Additional HTML specific parameters + * @params Doku_Form $form The target Doku_Form object + * @params int $formid unique identifier of the form which contains this field + */ + public function renderfield($params, Doku_Form $form, $formid) { + $id = 'bureaucracy__'.md5(rand()); + if(isset($this->opt['id'])) { + $id = $this->opt['id']; + } + $params = array_merge( + array('value' => false), + $this->opt, + $params + ); + $check = $params['value'] ? 'checked="checked"' : ''; + $this->tpl = '<label class="@@CLASS@@" for="'.$id.'"><span>@@DISPLAY@@</span>'. + '<input type="hidden" name="@@NAME@@" value="0" />' . + '<input type="checkbox" name="@@NAME@@" value="1" id="'.$id.'" ' . $check . ' />' . + '</label>'; + parent::renderfield($params, $form, $formid); + } +} |