1<?php 2 3/** 4 * DokuWiki Plugin struct (Action Component) 5 * 6 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 7 * @author Andreas Gohr, Michael Große <dokuwiki@cosmocode.de> 8 */ 9 10use dokuwiki\plugin\struct\meta\AccessTable; 11use dokuwiki\plugin\struct\meta\AccessTableGlobal; 12use dokuwiki\plugin\struct\meta\AggregationEditorTable; 13use dokuwiki\plugin\struct\meta\Column; 14use dokuwiki\plugin\struct\meta\Schema; 15use dokuwiki\plugin\struct\meta\SearchConfig; 16use dokuwiki\plugin\struct\meta\StructException; 17use dokuwiki\plugin\struct\meta\Value; 18 19/** 20 * Class action_plugin_struct_lookup 21 * 22 * Handle global and serial data table editing 23 */ 24class action_plugin_struct_aggregationeditor extends DokuWiki_Action_Plugin 25{ 26 /** @var Column */ 27 protected $column = null; 28 29 /** @var string */ 30 protected $pid = ''; 31 32 /** @var int */ 33 protected $rid = 0; 34 35 /** 36 * Registers a callback function for a given event 37 * 38 * @param Doku_Event_Handler $controller DokuWiki's event controller object 39 * @return void 40 */ 41 public function register(Doku_Event_Handler $controller) 42 { 43 $controller->register_hook('DOKUWIKI_STARTED', 'AFTER', $this, 'addJsinfo'); 44 $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjax'); 45 } 46 47 /** 48 * Add user's permissions to JSINFO 49 * 50 * @param Doku_Event $event 51 */ 52 public function addJsinfo(Doku_Event $event) 53 { 54 global $ID; 55 global $JSINFO; 56 $JSINFO['plugins']['struct']['isPageEditor'] = (bool)(auth_quickaclcheck($ID) >= AUTH_EDIT); 57 } 58 59 60 /** 61 * @param Doku_Event $event 62 */ 63 public function handleAjax(Doku_Event $event) 64 { 65 $len = strlen('plugin_struct_aggregationeditor_'); 66 if (substr($event->data, 0, $len) != 'plugin_struct_aggregationeditor_') { 67 return; 68 } 69 $event->preventDefault(); 70 $event->stopPropagation(); 71 72 try { 73 if (substr($event->data, $len) == 'new') { 74 $this->newRowEditor(); 75 } 76 77 if (substr($event->data, $len) == 'save') { 78 $this->saveRow(); 79 } 80 81 if (substr($event->data, $len) == 'delete') { 82 $this->deleteRow(); 83 } 84 } catch (StructException $e) { 85 http_status(500); 86 header('Content-Type: text/plain'); 87 echo $e->getMessage(); 88 } 89 } 90 91 /** 92 * Deletes a row 93 */ 94 protected function deleteRow() 95 { 96 global $INPUT; 97 $tablename = $INPUT->str('schema'); 98 if (!$tablename) { 99 throw new StructException('No schema given'); 100 } 101 102 $this->rid = $INPUT->int('rid'); 103 $this->validate(); 104 105 action_plugin_struct_inline::checkCSRF(); 106 107 $access = $this->getAccess($tablename); 108 if (!$access->getSchema()->isEditable()) { 109 throw new StructException('lookup delete error: no permission for schema'); 110 } 111 $access->clearData(); 112 } 113 114 /** 115 * Save one new row 116 */ 117 protected function saveRow() 118 { 119 global $INPUT; 120 $tablename = $INPUT->str('schema'); 121 $data = $INPUT->arr('entry'); 122 $this->pid = $INPUT->str('pid'); 123 action_plugin_struct_inline::checkCSRF(); 124 125 // create a new row based on the original aggregation config 126 $access = $this->getAccess($tablename); 127 128 /** @var helper_plugin_struct $helper */ 129 $helper = plugin_load('helper', 'struct'); 130 $helper->saveLookupData($access, $data); 131 132 $config = json_decode($INPUT->str('searchconf'), true); 133 // update row id 134 $this->rid = $access->getRid(); 135 $config = $this->addTypeFilter($config); 136 137 $editorTable = new AggregationEditorTable( 138 $this->pid, 139 'xhtml', 140 new Doku_Renderer_xhtml(), 141 new SearchConfig($config) 142 ); 143 144 echo $editorTable->getFirstRow(); 145 } 146 147 /** 148 * Create the Editor for a new row 149 */ 150 protected function newRowEditor() 151 { 152 global $INPUT; 153 global $lang; 154 $tablename = $INPUT->str('schema'); 155 156 $schema = new Schema($tablename); 157 if (!$schema->isEditable()) { 158 return; 159 } // no permissions, no editor 160 // separate check for serial data in JS 161 162 echo '<div class="struct_entry_form">'; 163 echo '<fieldset>'; 164 echo '<legend>' . $this->getLang('lookup new entry') . '</legend>'; 165 /** @var action_plugin_struct_edit $edit */ 166 $edit = plugin_load('action', 'struct_edit'); 167 foreach ($schema->getColumns(false) as $column) { 168 $label = $column->getLabel(); 169 $field = new Value($column, ''); 170 echo $edit->makeField($field, "entry[$label]"); 171 } 172 formSecurityToken(); // csrf protection 173 echo '<input type="hidden" name="call" value="plugin_struct_aggregationeditor_save" />'; 174 echo '<input type="hidden" name="schema" value="' . hsc($tablename) . '" />'; 175 176 echo '<button type="submit">' . $lang['btn_save'] . '</button>'; 177 178 echo '<div class="err"></div>'; 179 echo '</fieldset>'; 180 echo '</div>'; 181 } 182 183 /** 184 * Returns data accessor 185 * 186 * @param string $tablename 187 * @return AccessTableGlobal 188 */ 189 protected function getAccess($tablename) 190 { 191 if ($this->pid) { 192 return AccessTable::getSerialAccess($tablename, $this->pid, $this->rid); 193 } 194 return AccessTable::getGlobalAccess($tablename, $this->rid); 195 } 196 197 /** 198 * Adds filter to search config to differentiate data types 199 * 200 * @param array $config 201 * @return array 202 */ 203 protected function addTypeFilter($config) 204 { 205 $config['filter'][] = ['%rowid%', '=', $this->rid, 'AND']; 206 if ($this->pid) { 207 $config['filter'][] = ['%pageid%', '=', $this->pid, 'AND']; 208 } 209 return $config; 210 } 211 212 /** 213 * Throws an exception if data is invalid 214 */ 215 protected function validate() 216 { 217 if (!$this->rid) { 218 throw new StructException('No row id given'); 219 } 220 } 221} 222