xref: /plugin/struct/action/aggregationeditor.php (revision 307755deb4733d3fa94770354bf10652147bb059)
1308cc83fSAndreas Gohr<?php
2308cc83fSAndreas Gohr
3308cc83fSAndreas Gohr/**
4308cc83fSAndreas Gohr * DokuWiki Plugin struct (Action Component)
5308cc83fSAndreas Gohr *
6308cc83fSAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
7308cc83fSAndreas Gohr * @author  Andreas Gohr, Michael Große <dokuwiki@cosmocode.de>
8308cc83fSAndreas Gohr */
9308cc83fSAndreas Gohr
10308cc83fSAndreas Gohruse dokuwiki\plugin\struct\meta\AccessTable;
11308cc83fSAndreas Gohruse dokuwiki\plugin\struct\meta\AccessTableGlobal;
12308cc83fSAndreas Gohruse dokuwiki\plugin\struct\meta\AggregationEditorTable;
130549dcc5SAndreas Gohruse dokuwiki\plugin\struct\meta\Column;
14308cc83fSAndreas Gohruse dokuwiki\plugin\struct\meta\Schema;
15308cc83fSAndreas Gohruse dokuwiki\plugin\struct\meta\SearchConfig;
16308cc83fSAndreas Gohruse dokuwiki\plugin\struct\meta\StructException;
17308cc83fSAndreas Gohruse dokuwiki\plugin\struct\meta\Value;
18308cc83fSAndreas Gohr
19308cc83fSAndreas Gohr/**
20308cc83fSAndreas Gohr * Class action_plugin_struct_lookup
21308cc83fSAndreas Gohr *
22308cc83fSAndreas Gohr * Handle global and serial data table editing
23308cc83fSAndreas Gohr */
24308cc83fSAndreas Gohrclass action_plugin_struct_aggregationeditor extends DokuWiki_Action_Plugin
25308cc83fSAndreas Gohr{
26308cc83fSAndreas Gohr    /** @var  Column */
27308cc83fSAndreas Gohr    protected $column = null;
28308cc83fSAndreas Gohr
29308cc83fSAndreas Gohr    /** @var string */
30308cc83fSAndreas Gohr    protected $pid = '';
31308cc83fSAndreas Gohr
32308cc83fSAndreas Gohr    /** @var int */
33308cc83fSAndreas Gohr    protected $rid = 0;
34308cc83fSAndreas Gohr
35308cc83fSAndreas Gohr    /**
36308cc83fSAndreas Gohr     * Registers a callback function for a given event
37308cc83fSAndreas Gohr     *
38308cc83fSAndreas Gohr     * @param Doku_Event_Handler $controller DokuWiki's event controller object
39308cc83fSAndreas Gohr     * @return void
40308cc83fSAndreas Gohr     */
41308cc83fSAndreas Gohr    public function register(Doku_Event_Handler $controller)
42308cc83fSAndreas Gohr    {
4317dda596SAnna Dabrowska        $controller->register_hook('DOKUWIKI_STARTED', 'AFTER', $this, 'addJsinfo');
44308cc83fSAndreas Gohr        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleAjax');
45308cc83fSAndreas Gohr    }
46308cc83fSAndreas Gohr
47308cc83fSAndreas Gohr    /**
4817dda596SAnna Dabrowska     * Add user's permissions to JSINFO
4917dda596SAnna Dabrowska     *
50308cc83fSAndreas Gohr     * @param Doku_Event $event
51308cc83fSAndreas Gohr     */
5217dda596SAnna Dabrowska    public function addJsinfo(Doku_Event $event)
5317dda596SAnna Dabrowska    {
5417dda596SAnna Dabrowska        global $ID;
5517dda596SAnna Dabrowska        global $JSINFO;
5617dda596SAnna Dabrowska        $JSINFO['plugins']['struct']['isPageEditor'] = (bool)(auth_quickaclcheck($ID) >= AUTH_EDIT);
5717dda596SAnna Dabrowska    }
5817dda596SAnna Dabrowska
5917dda596SAnna Dabrowska
6017dda596SAnna Dabrowska    /**
6117dda596SAnna Dabrowska     * @param Doku_Event $event
6217dda596SAnna Dabrowska     */
6317dda596SAnna Dabrowska    public function handleAjax(Doku_Event $event)
64308cc83fSAndreas Gohr    {
65308cc83fSAndreas Gohr        $len = strlen('plugin_struct_aggregationeditor_');
66308cc83fSAndreas Gohr        if (substr($event->data, 0, $len) != 'plugin_struct_aggregationeditor_') {
67308cc83fSAndreas Gohr            return;
68308cc83fSAndreas Gohr        }
69308cc83fSAndreas Gohr        $event->preventDefault();
70308cc83fSAndreas Gohr        $event->stopPropagation();
71308cc83fSAndreas Gohr
72308cc83fSAndreas Gohr        try {
73308cc83fSAndreas Gohr            if (substr($event->data, $len) == 'new') {
74308cc83fSAndreas Gohr                $this->newRowEditor();
75308cc83fSAndreas Gohr            }
76308cc83fSAndreas Gohr
77308cc83fSAndreas Gohr            if (substr($event->data, $len) == 'save') {
78308cc83fSAndreas Gohr                $this->saveRow();
79308cc83fSAndreas Gohr            }
80308cc83fSAndreas Gohr
81308cc83fSAndreas Gohr            if (substr($event->data, $len) == 'delete') {
82308cc83fSAndreas Gohr                $this->deleteRow();
83308cc83fSAndreas Gohr            }
84308cc83fSAndreas Gohr        } catch (StructException $e) {
85308cc83fSAndreas Gohr            http_status(500);
86308cc83fSAndreas Gohr            header('Content-Type: text/plain');
87308cc83fSAndreas Gohr            echo $e->getMessage();
88308cc83fSAndreas Gohr        }
89308cc83fSAndreas Gohr    }
90308cc83fSAndreas Gohr
91308cc83fSAndreas Gohr    /**
92308cc83fSAndreas Gohr     * Deletes a row
93308cc83fSAndreas Gohr     */
94308cc83fSAndreas Gohr    protected function deleteRow()
95308cc83fSAndreas Gohr    {
96308cc83fSAndreas Gohr        global $INPUT;
97308cc83fSAndreas Gohr        $tablename = $INPUT->str('schema');
98308cc83fSAndreas Gohr        if (!$tablename) {
99308cc83fSAndreas Gohr            throw new StructException('No schema given');
100308cc83fSAndreas Gohr        }
101308cc83fSAndreas Gohr
102308cc83fSAndreas Gohr        $this->rid = $INPUT->int('rid');
103308cc83fSAndreas Gohr        $this->validate();
104308cc83fSAndreas Gohr
105308cc83fSAndreas Gohr        action_plugin_struct_inline::checkCSRF();
106308cc83fSAndreas Gohr
107308cc83fSAndreas Gohr        $access = $this->getAccess($tablename);
108308cc83fSAndreas Gohr        if (!$access->getSchema()->isEditable()) {
109308cc83fSAndreas Gohr            throw new StructException('lookup delete error: no permission for schema');
110308cc83fSAndreas Gohr        }
111308cc83fSAndreas Gohr        $access->clearData();
112308cc83fSAndreas Gohr    }
113308cc83fSAndreas Gohr
114308cc83fSAndreas Gohr    /**
115308cc83fSAndreas Gohr     * Save one new row
116308cc83fSAndreas Gohr     */
117308cc83fSAndreas Gohr    protected function saveRow()
118308cc83fSAndreas Gohr    {
119308cc83fSAndreas Gohr        global $INPUT;
120308cc83fSAndreas Gohr        $tablename = $INPUT->str('schema');
121308cc83fSAndreas Gohr        $data = $INPUT->arr('entry');
122308cc83fSAndreas Gohr        $this->pid = $INPUT->str('pid');
123308cc83fSAndreas Gohr        action_plugin_struct_inline::checkCSRF();
124308cc83fSAndreas Gohr
125308cc83fSAndreas Gohr        // create a new row based on the original aggregation config
126308cc83fSAndreas Gohr        $access = $this->getAccess($tablename);
127308cc83fSAndreas Gohr
128308cc83fSAndreas Gohr        /** @var helper_plugin_struct $helper */
129308cc83fSAndreas Gohr        $helper = plugin_load('helper', 'struct');
130308cc83fSAndreas Gohr        $helper->saveLookupData($access, $data);
131308cc83fSAndreas Gohr
132308cc83fSAndreas Gohr        $config = json_decode($INPUT->str('searchconf'), true);
133308cc83fSAndreas Gohr        // update row id
134308cc83fSAndreas Gohr        $this->rid = $access->getRid();
135308cc83fSAndreas Gohr        $config = $this->addTypeFilter($config);
136308cc83fSAndreas Gohr
137308cc83fSAndreas Gohr        $editorTable = new AggregationEditorTable(
138308cc83fSAndreas Gohr            $this->pid,
139308cc83fSAndreas Gohr            'xhtml',
140308cc83fSAndreas Gohr            new Doku_Renderer_xhtml(),
141308cc83fSAndreas Gohr            new SearchConfig($config)
142308cc83fSAndreas Gohr        );
143308cc83fSAndreas Gohr
144308cc83fSAndreas Gohr        echo $editorTable->getFirstRow();
145308cc83fSAndreas Gohr    }
146308cc83fSAndreas Gohr
147308cc83fSAndreas Gohr    /**
148308cc83fSAndreas Gohr     * Create the Editor for a new row
149308cc83fSAndreas Gohr     */
150308cc83fSAndreas Gohr    protected function newRowEditor()
151308cc83fSAndreas Gohr    {
152308cc83fSAndreas Gohr        global $INPUT;
153308cc83fSAndreas Gohr        global $lang;
154615e5131SAnna Dabrowska
155*307755deSAnna Dabrowska        $searchconf = $INPUT->arr('searchconf');
156*307755deSAnna Dabrowska        $tablename = $searchconf['schemas'][0][0];
157308cc83fSAndreas Gohr
158308cc83fSAndreas Gohr        $schema = new Schema($tablename);
159308cc83fSAndreas Gohr        if (!$schema->isEditable()) {
160308cc83fSAndreas Gohr            return;
161308cc83fSAndreas Gohr        } // no permissions, no editor
16217dda596SAnna Dabrowska        // separate check for serial data in JS
163308cc83fSAndreas Gohr
164308cc83fSAndreas Gohr        echo '<div class="struct_entry_form">';
165308cc83fSAndreas Gohr        echo '<fieldset>';
166308cc83fSAndreas Gohr        echo '<legend>' . $this->getLang('lookup new entry') . '</legend>';
167308cc83fSAndreas Gohr        /** @var action_plugin_struct_edit $edit */
168308cc83fSAndreas Gohr        $edit = plugin_load('action', 'struct_edit');
16987788c7fSAnna Dabrowska
17087788c7fSAnna Dabrowska        // filter columns based on searchconf cols from syntax
171*307755deSAnna Dabrowska        $columns = $this->resolveColumns($searchconf, $schema);
17287788c7fSAnna Dabrowska
17387788c7fSAnna Dabrowska        foreach ($columns as $column) {
174308cc83fSAndreas Gohr            $label = $column->getLabel();
175308cc83fSAndreas Gohr            $field = new Value($column, '');
176308cc83fSAndreas Gohr            echo $edit->makeField($field, "entry[$label]");
177308cc83fSAndreas Gohr        }
178308cc83fSAndreas Gohr        formSecurityToken(); // csrf protection
179308cc83fSAndreas Gohr        echo '<input type="hidden" name="call" value="plugin_struct_aggregationeditor_save" />';
180308cc83fSAndreas Gohr        echo '<input type="hidden" name="schema" value="' . hsc($tablename) . '" />';
181308cc83fSAndreas Gohr
182308cc83fSAndreas Gohr        echo '<button type="submit">' . $lang['btn_save'] . '</button>';
183308cc83fSAndreas Gohr
184308cc83fSAndreas Gohr        echo '<div class="err"></div>';
185308cc83fSAndreas Gohr        echo '</fieldset>';
186308cc83fSAndreas Gohr        echo '</div>';
187308cc83fSAndreas Gohr    }
188308cc83fSAndreas Gohr
189308cc83fSAndreas Gohr    /**
190615e5131SAnna Dabrowska     * Names of columns in the new entry editor: either all,
191615e5131SAnna Dabrowska     * or the selection defined in config. If config contains '*',
192615e5131SAnna Dabrowska     * just return the full set.
193615e5131SAnna Dabrowska     *
194615e5131SAnna Dabrowska     * @param array $searchconf
195615e5131SAnna Dabrowska     * @param Schema $schema
196615e5131SAnna Dabrowska     * @return array
197615e5131SAnna Dabrowska     */
198615e5131SAnna Dabrowska    protected function resolveColumns($searchconf, $schema)
199615e5131SAnna Dabrowska    {
200615e5131SAnna Dabrowska        // if no valid column config, return all columns
201615e5131SAnna Dabrowska        if (
202615e5131SAnna Dabrowska            empty($searchconf['cols']) ||
203615e5131SAnna Dabrowska            !is_array($searchconf['cols']) ||
204615e5131SAnna Dabrowska            in_array('*', $searchconf['cols'])
205615e5131SAnna Dabrowska        ) {
206615e5131SAnna Dabrowska            return $schema->getColumns(false);
207615e5131SAnna Dabrowska        }
208615e5131SAnna Dabrowska
209615e5131SAnna Dabrowska        $columns = [];
210615e5131SAnna Dabrowska        foreach ($searchconf['cols'] as $col) {
211615e5131SAnna Dabrowska            $columns[] = $schema->findColumn($col);
212615e5131SAnna Dabrowska        }
213615e5131SAnna Dabrowska        // filter invalid columns (where findColumn() returned false)
214615e5131SAnna Dabrowska        return array_filter($columns);
215615e5131SAnna Dabrowska    }
216615e5131SAnna Dabrowska
217615e5131SAnna Dabrowska    /**
218308cc83fSAndreas Gohr     * Returns data accessor
219308cc83fSAndreas Gohr     *
220308cc83fSAndreas Gohr     * @param string $tablename
221308cc83fSAndreas Gohr     * @return AccessTableGlobal
222308cc83fSAndreas Gohr     */
223308cc83fSAndreas Gohr    protected function getAccess($tablename)
224308cc83fSAndreas Gohr    {
225308cc83fSAndreas Gohr        if ($this->pid) {
226308cc83fSAndreas Gohr            return AccessTable::getSerialAccess($tablename, $this->pid, $this->rid);
227308cc83fSAndreas Gohr        }
228ed77599cSAnna Dabrowska        return AccessTable::getGlobalAccess($tablename, $this->rid);
229308cc83fSAndreas Gohr    }
230308cc83fSAndreas Gohr
231308cc83fSAndreas Gohr    /**
232308cc83fSAndreas Gohr     * Adds filter to search config to differentiate data types
233308cc83fSAndreas Gohr     *
234308cc83fSAndreas Gohr     * @param array $config
235308cc83fSAndreas Gohr     * @return array
236308cc83fSAndreas Gohr     */
237308cc83fSAndreas Gohr    protected function addTypeFilter($config)
238308cc83fSAndreas Gohr    {
239308cc83fSAndreas Gohr        $config['filter'][] = ['%rowid%', '=', $this->rid, 'AND'];
240308cc83fSAndreas Gohr        if ($this->pid) {
241308cc83fSAndreas Gohr            $config['filter'][] = ['%pageid%', '=', $this->pid, 'AND'];
242308cc83fSAndreas Gohr        }
243308cc83fSAndreas Gohr        return $config;
244308cc83fSAndreas Gohr    }
245308cc83fSAndreas Gohr
246308cc83fSAndreas Gohr    /**
247308cc83fSAndreas Gohr     * Throws an exception if data is invalid
248308cc83fSAndreas Gohr     */
249308cc83fSAndreas Gohr    protected function validate()
250308cc83fSAndreas Gohr    {
251308cc83fSAndreas Gohr        if (!$this->rid) {
252308cc83fSAndreas Gohr            throw new StructException('No row id given');
253308cc83fSAndreas Gohr        }
254308cc83fSAndreas Gohr    }
255308cc83fSAndreas Gohr}
256