1<?php
2// must be run within Dokuwiki
3if(!defined('DOKU_INC')) die();
4
5if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
6require_once(DOKU_PLUGIN.'admin.php');
7
8/**
9 * All DokuWiki plugins to extend the admin function
10 * need to inherit from this class
11 */
12class admin_plugin_csvtodwpages extends DokuWiki_Admin_Plugin
13{
14    /**
15     * Version: see lang.php
16     */
17
18    protected $params;
19    protected $paramcount;
20
21    /**
22     * access for managers
23     */
24    function forAdminOnly()
25    {
26        return false;
27    }
28
29    /**
30     * return sort order for position in admin menu
31     */
32    function getMenuSort()
33    {
34        return 1;
35    }
36
37    /**
38     * handle user request
39     */
40    function handle()
41    {
42        global $params;
43        global $paramcount;
44
45        // todo: use the $INPUT dokuwiki class instead of $_REQUEST - https://www.dokuwiki.org/devel:request_vars
46        if (array_key_exists('csvdw_submit', $_REQUEST)) {
47            if (checkSecurityToken()) {
48                foreach ($_REQUEST as $key => $value) {
49                	if (in_array($key, array('csvdw_namespace','csvdw_delim','csvdw_pagename','csvdw_csvdata','csvdw_csvtemplate','csvdw_overwrite','csvdw_dummyrun' ,'csvdw_trim'))){
50                        // if (!empty($value) || is_numeric($value)) {
51                        if (!blank($value)) {
52                            $paramcount++;
53                            $params[$key] = $value;
54                        }
55                	}
56                }
57            }
58        }
59    }
60
61    /**
62     * output appropriate html
63     */
64    function html()
65    {
66        global $params;
67        global $paramcount;
68
69        $fieldcount = 0;
70
71        // update the label when the namespace is changed
72        echo "<script language='javascript'>function csvtodw_nslabel(){document.getElementById('csvtodw_nslabel').innerHTML=document.getElementById('csvtodw_ns').value;};</script>";
73
74        ptln( $this->locale_xhtml('intro') );
75        ptln( '<form method="post" action="" class="csvtodwpages">' );
76        ptln( '<input type="hidden" name="do" value="admin"/>' );
77        ptln( '<input type="hidden" name="page" value="'.$this->getPluginName().'"/>' );
78        formSecurityToken();
79
80        ptln( '<fieldset class="csvtodwpages">' );
81
82        ptln( '<table class="csvtodwpages"><tr><td>' );
83
84        ptln( '<h4>'.$this->getLang('csvdw_namespace').'</h4>' );
85        ptln( '<input type="text" name="csvdw_namespace" value="'.$this->_field('csvdw_namespace','').'" id="csvtodw_ns" onblur="csvtodw_nslabel()"/>' );
86        $fieldcount++;
87
88        ptln( '</td><td>' );
89
90        ptln( '<h4>'.$this->getLang('csvdw_pagename').'</h4>' );
91        ptln( '<input type="text" name="csvdw_pagename" value="'.$this->_field('csvdw_pagename','').'"/>' );
92        $fieldcount++;
93
94        ptln( '</td><td>' );
95
96        ptln( '<h4>'.$this->getLang('csvdw_delim').'</h4>' );
97        ptln( '<input type="text" name="csvdw_delim" maxlength="1" value="'.$this->_field('csvdw_delim',',').'"/>' );
98        $fieldcount++;
99
100        ptln( '</td></tr></table>' );
101
102        ptln( '<h4>'.$this->getLang('csvdw_csvtemplate').'</h4>' );
103        ptln( '<textarea name="csvdw_csvtemplate" class="edit">'.$this->_field('csvdw_csvtemplate').'</textarea><br/><br/>' );
104        $fieldcount++;
105
106        ptln( '<h4>'.$this->getLang('csvdw_csvdata').'</h4>' );
107        ptln( '<textarea name="csvdw_csvdata" class="edit">'.$this->_field('csvdw_csvdata').'</textarea><br/><br/>' );
108        $fieldcount++;
109
110        ptln( '<table class="csvtodwpages"><tr><td>' );
111
112        ptln( '<h4>'.sprintf($this->getLang('csvdw_overwrite'), $this->_field('csvdw_namespace','csvexploded')).'</h4>' );
113        ptln( '<input type="radio" class="csvtodwpages" name="csvdw_overwrite[]" value="true" id="owt" '.$this->_field('csvdw_overwrite','true',true).'/> ');
114        ptln( '<label class="csvtodwpages" for="owt">'.$this->getLang('csvdw_yes').'</label> --- <label class="csvtodwpages" for="owf">'.$this->getLang('csvdw_no').'</label>' );
115        ptln( '<input type="radio" class="csvtodwpages" name="csvdw_overwrite[]" value="false" id="owf" '.$this->_field('csvdw_overwrite','false',true).'/>' );
116        $fieldcount++;
117
118        ptln( '</td><td>' );
119
120        ptln( '<h4>'.$this->getLang('csvdw_dummyrun').'</h4>' );
121        ptln( '<input type="radio" class="csvtodwpages" name="csvdw_dummyrun[]" value="true" id="drt" '.$this->_field('csvdw_dummyrun','true',true).'/> ' );
122        ptln( '<label class="csvtodwpages" for="drt">'.$this->getLang('csvdw_yes').'</label> --- <label class="csvtodwpages" for="drf">'.$this->getLang('csvdw_no').'</label>' );
123        ptln( '<input type="radio" class="csvtodwpages" name="csvdw_dummyrun[]" value="false" id="drf" '.$this->_field('csvdw_dummyrun','false',true).'/>' );
124        $fieldcount++;
125
126        ptln( '</td><td>' );
127
128        ptln( '<h4>'.$this->getLang('csvdw_trim').'</h4>' );
129        ptln( '<input type="radio" name="csvdw_trim[]" value="true" id="trimt" '.$this->_field('csvdw_trim','true',true).'/> ' );
130        ptln( '<label class="csvtodwpages" for="trimt">'.$this->getLang('csvdw_yes').'</label> --- <label class="csvtodwpages" for="trimf">'.$this->getLang('csvdw_no').'</label>' );
131        ptln( '<input type="radio" name="csvdw_trim[]" value="false" id="trimf" '.$this->_field('csvdw_trim','false',true).'/>' );
132        $fieldcount++;
133
134        ptln( '</td></tr></table>' );
135
136        // required fields warning
137		ptln( (is_numeric($paramcount) && $paramcount !== $fieldcount) ? "<span class='csvtodwpageswarning'>".$this->getLang('csvdw_allfields')."</span><br/>" : '' );
138
139        ptln( '<input type="submit" name="csvdw_submit" class="csvtodwpages" value="'.$this->getLang('csvdw_submitbtn').'"/>' );
140
141        echo '<div class="csvtodwpages_ver">'.$this->getLang('csvdw_ver').'</div>';
142        echo '</fieldset>';
143
144        echo '</form>';
145
146        // if all form values recieved, let's explode!
147        if ($paramcount == $fieldcount) {
148        	$this->_csvexploder();
149
150		} elseif ($paramcount > $fieldcount) {
151            // something weird going on
152            ptln( '<br/><fieldset><span class="csvtodwpageswarning">Incorrect number of form parameters received. We\'re screwed!<br/>Needed '.$fieldcount.', got '.$paramcount.'</span></fieldset>');
153        }
154	}
155
156
157    /**
158     * take form values and explode the submitted csvdata into dokuwiki pages based on submitted csvtemplate
159     */
160	function _csvexploder()
161    {
162        global $conf;       // get dokuwiki conf array
163        global $params;
164        global $paramcount;
165
166
167        $namespace      = strtolower($params['csvdw_namespace']); // which namespace to create pages within
168
169        $pagename_column = $params['csvdw_pagename']; // which column(s) in the csv file used for the pagename
170
171        $indexpage      = (empty($conf['start'])) ? 'start' : $conf['start']; // the dokuwiki index page name
172
173        $csvdata        = $params['csvdw_csvdata'];         // the dokuwiki page in which you pasted the csv data
174        $csvtemplate    = $params['csvdw_csvtemplate'];     // the dokuwiki page you created holding the template
175        $csvdelim       = $params['csvdw_delim'][0];        // the csv delimiter character (single character)
176
177        $overwrite_files = ($params['csvdw_overwrite'][0] == 'true') ? TRUE : FALSE;  // set this to TRUE to overwrite existing pages
178        $dummyrun        = ($params['csvdw_dummyrun'][0]  == 'true') ? TRUE : FALSE;  // is this just a dummy run?
179        $trimspaces      = ($params['csvdw_trim'][0]      == 'true') ? TRUE : FALSE;  // is this just a dummy run?
180
181        $indexpagecontent = $this->getLang('csvdw_indexpagecontent');   // template for autogenerated index page
182
183        // $dr = rtrim( $_SERVER['DOCUMENT_ROOT'], "/" ) .'/';
184
185        // get field names from first row
186        $csvfieldnames = str_getcsv(strtok($csvdata, PHP_EOL), $csvdelim);
187
188        // if we have some csvfieldnames lets rock'n'roll
189        if ($csvfieldnames !== FALSE) {
190
191            if ($dummyrun) {
192                ptln( $this->getLang('csvdw_dummyrunnotice') );
193            }
194
195            ptln( $this->getLang('csvdw_explodednotice') );
196
197            if (array_count_values($csvfieldnames) >= 1) {
198
199                while (($line = strtok(PHP_EOL)) !== FALSE) {
200
201                    $line = str_getcsv($line, $csvdelim);
202
203                    if (!empty(array_filter($line))) {
204
205                        // get clean copy of the template
206                        $thispage = $csvtemplate;
207
208                        // set the page name for the index page text
209                        $pagename = $this->_get_filename($pagename_column, $line);
210
211                        // clean output filename to dokuwiki standards
212                        $cleanpagename = cleanID($pagename);
213
214                        $indexpagecontent .= "  * [[$cleanpagename|$pagename]]\r\n";
215
216                        // replace the template [placeholder] names with content
217                        foreach ($csvfieldnames as $key => $field) {
218                            $thispage = str_replace('['.strtolower($field).']', $trimspaces ? trim($line[$key]) : $line[$key], $thispage);
219                        }
220
221                        // create wiki page
222                        $filecreated = FALSE;
223
224                        if ($overwrite_files !== TRUE && page_exists(resolve_id($namespace, $cleanpagename))) {
225                            echo $this->getLang('csvdw_skipnoticep');   // msg($this->getLang('csvdw_skipnotice'));
226                        } else {
227                            if ($dummyrun) {
228                                $filecreated = TRUE;
229                            } else {
230                                // we are assuming that if the file exists after saveWikiText() then it was created
231                                // Unfortunately saveWikiText() doesn't provide a return value to indicate if it succeeded or failed.
232                                // This leaves it possible that a page existed previously but we were unable to overwrite it.
233                                // The DW notice system will put a notice in the exploded file list to indicate the failure though.
234                                // see io_writeWikiPage() and _io_writeWikiPage_action() in .\dokuwiki\inc\io.php
235                                saveWikiText(resolve_id($namespace, $cleanpagename), $thispage, $this->getLang('csvdw_summary'));
236                                $filecreated = page_exists(resolve_id($namespace, $cleanpagename));
237                            }
238
239                            if ($filecreated == FALSE) {
240                                echo $this->getLang('csvdw_errornotice');
241                            } else {
242                                echo $this->getLang('csvdw_creatednoticep');
243                            }
244                        }
245
246                        ptln( wikiFN(resolve_id($namespace, $cleanpagename))."<br/>" );
247
248                    }
249
250                }
251
252                // show an example template page if this is a dummy run
253                // (uses the data from the last processed csv row)
254                if ($dummyrun) {
255                    ptln( $this->getLang('csvdw_examplepagenotice') );
256                    ptln( nl2br($thispage) );
257                }
258
259                ptln( "<br/><br/><hr/>" );
260
261                // create index page
262                $filecreated = FALSE;
263
264                if ($overwrite_files !== TRUE && page_exists(resolve_id($namespace, $indexpage))) {
265                    echo $this->getLang('csvdw_skipnoticei');   // msg($this->getLang('csvdw_skipnoticei'));
266
267                } else {
268                    if ($dummyrun) {
269                        $filecreated = TRUE;
270                    } else {
271                        saveWikiText(resolve_id($namespace, $indexpage), $indexpagecontent, $this->getLang('csvdw_summary'));
272                        $filecreated = page_exists(resolve_id($namespace, $indexpage));
273                    }
274                    if ($filecreated == FALSE) {
275                        echo $this->getLang('csvdw_errornotice');
276                    } else {
277                        echo $this->getLang('csvdw_creatednoticei');
278                    }
279                }
280
281                ptln( wikiFN(resolve_id($namespace, $indexpage))."<br/>" );
282            }
283
284            ptln( "<br/>" );
285            // ptln( 'Go to '.$namespace.' <a href="/'.$namespace.'/'.$indexpage.'">index</a> page.' );
286            ptln( 'Go to '.$namespace.' <a href="'.wl($ID,'',true).resolve_id($namespace, $indexpage).'">index</a> page.' );
287        }
288
289        strtok('',''); // release strtok memory
290	}
291
292
293    /**
294     * Helper to build a unique pagename from specified csv column data
295     *
296     * Will combine multiple column data together if comma separated list
297     * is supplied. Each field will be separated with underscores _
298     *
299     * @param $pagecols string Single int value or comma separated list eg. 0,3
300     * @param $line     array  An array containing the csv values for the current row
301     * @return string   A page name combining all row values separated with _ eg. youngstown_oh
302     */
303    protected function _get_filename($pagecols='', &$line)
304    {
305        $pagename = '';
306        $pagecols = explode(',', $pagecols);
307
308        // combine column data into filename
309        foreach ($pagecols as $col) {
310            $pagename .= trim($line[$col]).'_';
311        }
312
313        return rtrim($pagename, "_");
314    }
315
316    /**
317     * Helper to repopulate form field values from POST data
318     *
319     * @param  $field   = fieldname
320     * @param  $default = default value to return if no value present
321     * @param  $isradio = flag indicating if field is a radiobutton - return 'checked' instead of value
322     * @return string : form field value or default
323     * @return array  : first element of array if incoming field was an array (multivalue field)
324     */
325	protected function _field($field, $default='', $isradio=false)
326    {
327        global $params;
328        global $paramcount;
329
330        $val = '';
331        if (!empty($params[$field])) {
332            $val = is_array($params[$field]) ? $params[$field][0] : $params[$field];
333        }
334
335        if ($isradio) {
336            if ($val==$default) {
337                return 'checked';
338            }
339            return '';
340        }
341
342        return !empty($val) ? $val : $default;
343    }
344
345}
346
347