1<?php 2/** 3 * PyCode plugin: it embeds a Python script hosted in a remote repository. 4 * 5 * action.php: it defines all the methods used by PyCode plugin 6 * who interact with DokuWiki's events. 7 * 8 * @author Torpedo <dgtorpedo@gmail.com> 9 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 10 * @package action 11 */ 12 13if (!defined('DOKU_INC')) die(); // the plugin must be run within Dokuwiki 14 15require_once "method.php"; // common methods used by PyCode plugin 16 17/** 18 * This class defines all the methods used by the PyCode plugin to interact 19 * with the DokuWiki's events. 20 * 21 * It extends DokuWiki's basic action defined in lib/plugins/action.php. 22 * 23 * @package action_pycode 24 */ 25class action_plugin_pycode extends DokuWiki_Action_Plugin { 26 27 /** 28 * Constructor method for class suitable for any initialization. 29 */ 30 public function __construct() { 31 $this->mpp = new method_pycode_plugin; 32 } 33 34 /** 35 * Here are registered the event handlers 36 */ 37 public function register(Doku_Event_Handler $controller) { 38 $controller->register_hook("ACTION_ACT_PREPROCESS", "BEFORE", $this, "update_code", array ()); 39 $controller->register_hook("INDEXER_PAGE_ADD", "BEFORE", $this, "add_code", array()); 40 $controller->register_hook("DOKUWIKI_DONE", "BEFORE", $this, "update_log", array ()); 41 $controller->register_hook("TOOLBAR_DEFINE", "AFTER", $this, "insert_button", array ()); 42 } 43 44 /** 45 * It substitutes, in the local copy of <file>, only the pice of code which 46 * the user wants to update. 47 * 48 * After that it's necessary to refresh the page, but, since it's used 49 * the function header() to reload the page it's important to call this 50 * method before any actual output is sent. 51 * So it's necessary to use ACTION_ACT_PREPROCESS. 52 * 53 * In DokuWiki, instead of use $_POST, is strongly recommended to access 54 * to it using its input classes: 55 * $_POST["foo"]; becomes $INPUT->post->str("foo"); 56 * 57 * @param (obj) $event the event object 58 * @param (arr) $param data passed when this handler was registered 59 */ 60 public function update_code(Doku_Event $event, $param) { 61 global $INPUT; 62 63 if ($INPUT->post->str("submit") == "Ok") { 64 $loc_url = $INPUT->post->str("url"); 65 $code_new = unserialize(base64_decode($INPUT->post->str("new"))); 66 $ln_s = $INPUT->post->str("start"); 67 $ln_e = $INPUT->post->str("end"); 68 list($code_all_old, $flag, $name, $subname) = $this->mpp->_get_code($loc_url); 69 70 $ls = $ln_s - 1; 71 $le = $ln_e - 1; 72 $ln = $le - $ls + 1; 73 array_splice($code_all_old, $ls, $ln, $code_new); 74 $this->mpp->_save_code($loc_url, $code_all_old); 75 76 $uri = rtrim(DOKU_URL, "/") . $_SERVER['REQUEST_URI']; 77 header("Location: " . $uri); 78 exit; 79 } 80 } 81 82 /** 83 * It adds the code to the page which has to be indexed. 84 * 85 * Since the code is embedded and not write whitin the page, normally, 86 * it is not parsed by the search engine. 87 * So it's necessary to append the code to the page. 88 * 89 * @param (obj) $event the event object 90 * @param (arr) $param data passed when this handler was registered 91 */ 92 public function add_code(Doku_Event $event, $param) { 93 $log = DOKU_PLUGIN . "pycode/tmp/logfile"; 94 $log = json_decode(file_get_contents($log), true); 95 96 foreach ($log as $page => $files) { 97 $page = substr($page, 0, -4); // remove extension .txt 98 $page = str_replace("/", ":", $page); 99 if ($event->data["page"] == $page) { 100 $event->data["body"] = p_cached_output(wikiFN($page)); 101 } 102 } 103 } 104 105 /** 106 * It records in a logfile all <file>(s) embedded in each wiki page. 107 * 108 * For each wiki page are listed all the <file>(s) embedded (same <file> is 109 * listed only one time) so that one of them is no longer used, the relative 110 * local copy can be safely deleted. 111 * 112 * During the creation of a wiki page, the list of <file>(s) is saved in a 113 * temporary logfile.tmp. 114 * When the page is created, logfile.tmp is used to update a permanent 115 * logfile. 116 * Same <file> in the same wiki page are listed only once. 117 * 118 * This function have to be called after the wiki page is created, 119 * so it's necessary to use an event like DOKUWIKI_DONE. 120 * 121 * @param (obj) $event the event object 122 * @param (arr) $param data passed when this handler was registered 123 */ 124 public function update_log(Doku_Event $event, $param) { 125 global $ACT; 126 global $INFO; 127 $wiki = str_replace(DOKU_INC . "data/pages/", "", $INFO["filepath"]); 128 $tmp = DOKU_PLUGIN . "pycode/tmp/"; 129 $log_old = DOKU_PLUGIN . "pycode/tmp/logfile"; 130 $log_new = DOKU_PLUGIN . "pycode/tmp/logfile.tmp"; 131 132 if ($ACT == "show") { 133 if (file_exists($log_old) == true) { 134 // recover data stored in the logfile so we have sth. like this: 135 // array { 136 // ["<wiki-pg>1"] => array { 137 // [0] => "<file>1", 138 // [1] => "<file>2" 139 // } 140 // } 141 $log_old = json_decode(file_get_contents($log_old), true); 142 if (file_exists($log_new) == true) { 143 // recover data stored in the temporary logfile 144 $log_new = json_decode(file_get_contents($log_new), true); 145 if (array_key_exists($wiki, $log_old) == false) { 146 // all <file>(s) added to this wiki page are new 147 $log_old[$wiki] = array(); 148 foreach ($log_new[$wiki] as $file) { 149 array_push($log_old[$wiki], $file); 150 } 151 } 152 else { 153 // look for new <file>(s) not present among old <file>(s) 154 $add = array_diff($log_new[$wiki], $log_old[$wiki]); 155 156 // add new entry <file>(s) in the logfile 157 foreach ($add as $file_add) { 158 array_push($log_old[$wiki], $file_add); 159 } 160 161 // look for old <file>(s) not present among new <file>(s) 162 $del = array_diff($log_old[$wiki], $log_new[$wiki]); 163 164 // check among all wiki pages if these <file>(s) deleted were 165 // the last ones and, if so, remove them from the logfile 166 // and the relatives <file>(s) 167 foreach ($del as $key => $file_del) { 168 $i = 0; 169 foreach ($log_old as $page => $files) { 170 if ($wiki == $page) { 171 continue; 172 } 173 if (array_search($file_del, $files) !== false) { 174 $i = 1; // <file> is still embedded in another wiki page 175 } 176 } 177 if ($i == 0) { 178 unlink(DOKU_PLUGIN . "pycode/tmp/" . $file_del); 179 unset($log_old[$wiki][$key]); 180 $log_old[$wiki] = array_values($log_old[$wiki]); // reindex 181 } 182 } 183 } 184 } 185 else { 186 // all <file>(s) deleted from this wiki page are old 187 $del = $log_old[$wiki]; 188 if (empty($del) == false) { 189 foreach ($del as $key => $file_del) { 190 unlink(DOKU_PLUGIN . "pycode/tmp/" . $file_del); 191 } 192 unset($log_old[$wiki]); 193 } 194 } 195 196 if (count($log_old) == 0) { 197 unlink(DOKU_PLUGIN . "pycode/tmp/logfile"); 198 } 199 else { 200 // now the array for logfile is update and ready to be written 201 $str = json_encode($log_old); 202 file_put_contents(DOKU_PLUGIN . "pycode/tmp/logfile", $str); 203 } 204 } 205 elseif (file_exists($log_old) == false and file_exists($log_new) == true) { 206 rename($log_new, $log_old); 207 } 208 209 if (file_exists($tmp) == true) { 210 // remove empty directories 211 $tree_dir = $this->mpp->_get_tree_dir(DOKU_PLUGIN . "pycode/tmp/"); 212 $this->mpp->_remove_empty_dir($tree_dir); 213 214 // destroy temporary logfile 215 if (file_exists(DOKU_PLUGIN . "pycode/tmp/logfile.tmp") == true) { 216 unlink(DOKU_PLUGIN . "pycode/tmp/logfile.tmp"); 217 } 218 } 219 } 220 } 221 222 /** 223 * It inserts the PyCode's buttons in the toolbar. 224 * 225 * @param (obj) $event the event object 226 * @param (arr) $param data passed when this handler was registered 227 */ 228 public function insert_button(Doku_Event $event, $param) { 229 $btns = $this->getConf("btns"); 230 231 if ($btns == 1){ 232 $event->data[] = array ( 233 'type' => "PyCode", 234 'title' => "PyCode Plugin", 235 'icon' => "../../plugins/pycode/images/picker.png" 236 ); 237 } 238 } 239} 240