xref: /plugin/struct/action/aggregationeditor.php (revision 87788c7fd124822dd2f2d2f9106fe381507a1f20)
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->arr('data')['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
168        // filter columns based on searchconf cols from syntax
169        $columns = [];
170        if (!empty($INPUT->arr('data')['searchconf']['cols']) && is_array($INPUT->arr('data')['searchconf']['cols'])) {
171            foreach ($INPUT->arr('data')['searchconf']['cols'] as $col) {
172                $columns[] = $schema->findColumn($col);
173            }
174        } else {
175            $columns = $schema->getColumns(false);
176        }
177
178        foreach ($columns as $column) {
179            $label = $column->getLabel();
180            $field = new Value($column, '');
181            echo $edit->makeField($field, "entry[$label]");
182        }
183        formSecurityToken(); // csrf protection
184        echo '<input type="hidden" name="call" value="plugin_struct_aggregationeditor_save" />';
185        echo '<input type="hidden" name="schema" value="' . hsc($tablename) . '" />';
186
187        echo '<button type="submit">' . $lang['btn_save'] . '</button>';
188
189        echo '<div class="err"></div>';
190        echo '</fieldset>';
191        echo '</div>';
192    }
193
194    /**
195     * Returns data accessor
196     *
197     * @param string $tablename
198     * @return AccessTableGlobal
199     */
200    protected function getAccess($tablename)
201    {
202        if ($this->pid) {
203            return AccessTable::getSerialAccess($tablename, $this->pid, $this->rid);
204        }
205        return AccessTable::getGlobalAccess($tablename, $this->rid);
206    }
207
208    /**
209     * Adds filter to search config to differentiate data types
210     *
211     * @param array $config
212     * @return array
213     */
214    protected function addTypeFilter($config)
215    {
216        $config['filter'][] = ['%rowid%', '=', $this->rid, 'AND'];
217        if ($this->pid) {
218            $config['filter'][] = ['%pageid%', '=', $this->pid, 'AND'];
219        }
220        return $config;
221    }
222
223    /**
224     * Throws an exception if data is invalid
225     */
226    protected function validate()
227    {
228        if (!$this->rid) {
229            throw new StructException('No row id given');
230        }
231    }
232}
233