*/
// must be run within Dokuwiki
if (!defined('DOKU_INC')) {
die();
}
//Resolve to absolute page ID
use dokuwiki\File\PageResolver;
class action_plugin_jsongendoc extends DokuWiki_Action_Plugin
{
/**
* Registers a callback function for a given event
*
* @param Doku_Event_Handler $controller DokuWiki's event controller object
*
* @return void
*/
public function register(Doku_Event_Handler $controller) {
$controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handle_ajax_call_unknown');
}
/**
* Handle event AJAX_CALL_UNKNOWN for json_plugin_save_inline and
* json_plugin_archive call
*
* @param Doku_Event $event event object by reference
* @param mixed $param [the parameters passed as fifth argument to register_hook() when this
* handler was registered]
*
* @return Ajax response as json
*/
public function handle_ajax_call_unknown(Doku_Event $event, $param) {
if ($event->data !== 'jsongendoc_plugin') {
return;
}
//no other ajax call handlers needed
$event->stopPropagation();
$event->preventDefault();
//access additional request variables
global $INPUT;
$new_page_id = cleanID($INPUT->str('name'));
$data = json_decode($INPUT->str('data'), true);
$parent_id = strval($data['parent_id']);
$mime = strval($data['mime']);
$docname_meta = strval($data['docname_meta']);
$namespace = strval($data['namespace']);
$template_id = cleanID($data['template']);
$json = $data['json'];
$new_page_exist = $template_exist = false;
$resolver = new PageResolver($namespace.':page'); // ':page' will be stripped
//resolve tempalate_id
if($template_id) {
$template_id = $resolver->resolveId($template_id);
$template_exist = page_exists($template_id);
$template_link = ''.$template_id.'';
}
//resolve page_id, if page will be stored locally (mime undefined)
if(!$mime && $new_page_id) {
$new_page_id = $resolver->resolveId($new_page_id);
$new_page_exist = page_exists($new_page_id);
$new_page_link = ''.$new_page_id.'';
$new_page_id_for_template = $new_page_id;
}
else {
//document will be downloaded to the client machine
$new_page_link = $new_page_id;
$new_page_id_for_template = $template_id;
}
//verify parameters, existances and rights
$err = '';
if(!isset($json)) {
$err = $this->getLang('err_json');
}
else if($data['template'] && $template_exist === false) {
$err = sprintf($this->getLang('err_template_not_exist'), $template_link);
}
else if($template_id && auth_quickaclcheck($template_id) < AUTH_READ) {
$err = sprintf($this->getLang('permision_denied_template'), $template_id);
}
else if(!$mime) {
if(!$new_page_id) {
$err = $this->getLang('err_no_page_name');
}
else if($new_page_exist === true) {
$err = sprintf($this->getLang('err_page_exists'), $new_page_link);
}
else if(auth_quickaclcheck($new_page_id) < AUTH_CREATE) {
$err = sprintf($this->getLang('permision_denied_write'), $new_page_link);
}
}
//load template text from user or default namespace template
//and replace standard replacement patterns
//https://www.dokuwiki.org/namespace_templates
if($err === '') {
if($template_exist === true) {
//load user template
$parsePageTemplate_arg = array('id'=>$new_page_id_for_template, 'tpl'=>rawWiki($template_id));
//perform common page template replacements
$new_page_text = parsePageTemplate($parsePageTemplate_arg);
}
else {
//load default template
$template_id = 'Namespace Template'; //for info
$new_page_text = pageTemplate($new_page_id_for_template);
$template_link = $this->external_link('https://www.dokuwiki.org/namespace_templates', 'Namespace Template', 'urlextern');
}
if(!$new_page_text) {
$err = sprintf($this->getLang('err_empty_template'), $template_link, $new_page_link);
}
}
//statistics
$cnt = array(
'sections shown' => 0,
'sections removed' => 0,
'scalars extracted' => 0,
'json extracted' => 0,
'null values' => 0
);
//helper functions from JSON plugin
$json_o = $this->loadHelper('json');
//display or remove sections @%$-start (filter)% ... %$end%@
if($err === '') {
$new_page_text = preg_replace_callback(
'/@(\%\$-start\s*\(([^[\]{}%]*?)\)%)(.*?)%\$end\%@/s',
function($matches) use($json_o, $json, &$cnt, &$err) {
if($err === '') {
list($match, $pattern, $filter, $contents) = array_pad($matches, 4, '');
$filter = $json_o->parse_filter($filter);
if(count($filter) > 0) {
if($json_o->filter($json, $filter)) {
$cnt['sections shown'] ++;
return $contents;
}
else {
$cnt['sections removed'] ++;
return '';
}
}
else {
$err = printf($this->getLang('err_tpl_section'), $template_link, $pattern);
}
}
return '';
},
$new_page_text
);
}
//replace patterns @%$ ... %@
if($err === '') {
$new_page_text = preg_replace_callback(
'/@%\$(.*?)%@/s',
function($matches) use($json_o, $json, &$cnt) {
list(, $path) = $matches;
$var = $json;
$tokens = $json_o->parse_tokens($path);
//get variable on specified path of the json data
foreach($tokens as $tok) {
if(is_array($var) && isset($var[$tok])) {
$var = $var[$tok];
}
else {
$var = null;
break;
}
}
//return extraced data
if(is_bool($var)) {
$cnt['scalars extracted'] ++;
return $var ? 'true' : 'false';
}
else if(is_scalar($var)) {
$cnt['scalars extracted'] ++;
return strval($var);
}
else if(is_array($var)) {
$cnt['json extracted'] ++;
return json_encode($var);
}
else {
$cnt['null values'] ++;
return 'null';
}
},
$new_page_text
);
}
//create new file or send error
if($err === '') {
$response = array(
'response' => 'OK',
'mime' => '',
'msg' => sprintf($this->getLang('file_created_msg'), $new_page_link, $template_link)
.'
'
.sprintf($this->getLang('file_created_stat'),
$cnt['sections shown'], $cnt['sections removed'],
$cnt['scalars extracted'], $cnt['json extracted'], $cnt['null values']
)
.'
'
);
if(!$mime) {
//save document as new Dokuwiki page
saveWikiText($new_page_id, $new_page_text, sprintf($this->getLang('file_created_summary'), $template_id));
}
else {
//send data, so they can be downloaded
$response['mime'] = $mime;
$response['document'] = $new_page_text;
}
//store autoincrement into metadata of the caller
if(strlen($docname_meta) > 0 && preg_match('/^(.+?)(\d+)$/', $new_page_id, $matches)) {
list(, $base, $number) = $matches;
$base .= str_repeat('0', strlen($number));
if($docname_meta === $base && strlen($parent_id) > 0) {
p_set_metadata($parent_id, array('jsongendoc_'.$docname_meta => $number + 1));
}
}
}
else {
$response = array(
'response' => 'error',
'msg' => ''.$this->getLang('err').': '.$err.'
'
);
}
//send response
header('Content-Type: application/json');
echo json_encode($response);
}
}