*/ class helper_plugin_bureaucracyau_actiontemplate extends helper_plugin_bureaucracyau_action { var $targetpages; var $pagename; /** * Performs template action * * @param helper_plugin_bureaucracyau_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; list($tpl, $this->pagename, $sep) = $argv; if(is_null($sep)) $sep = $conf['sepchar']; $this->patterns = array(); $this->values = array(); $this->targetpages = array(); $this->prepareNamespacetemplateReplacements(); $this->prepareDateTimereplacements(); $this->prepareLanguagePlaceholder(); $this->prepareNoincludeReplacement(); $this->prepareFieldReplacements($fields); $this->buildTargetPagename($fields, $sep); //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_bureaucracyau_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_bureaucracyau_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); } } } } /** * 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])) { $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_BUREAUCRACYAU_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 .= '' . trim(substr($item['id'], strrpos($item['id'], ':', -2)), ':') . ''; } 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 = "

$thanks

"; // 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 .= '
'; ob_start(); foreach ($pages as $ID) { // indexerWebBug uses ID and INFO[exists], but the bureaucracyau 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 ''; } $html .= ob_get_contents(); ob_end_clean(); $html .= '
'; $ID = $backupID; return $html; } /** * move the uploaded files to :FILENAME * * * @param helper_plugin_bureaucracyau_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) { $data = array( 'id' => $targetpageid, 'tpl' => rawWiki($templatepageid), '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: