1<?php
2
3use dokuwiki\Extension\Event;
4
5/**
6 * DokuWiki Plugin userpagecreate (Action Component)
7 *
8 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
9 * @author  Adrian Lang <lang@cosmocode.de>
10 */
11class action_plugin_userpagecreate extends DokuWiki_Action_Plugin
12{
13    /** @inheritDoc */
14    public function register(Doku_Event_Handler $controller)
15    {
16        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handle_action_act_preprocess');
17
18        if ($this->getConf('delete')) {
19            $controller->register_hook('AUTH_USER_CHANGE', 'AFTER', $this, 'handleUserDeletion');
20        }
21    }
22
23    /**
24     * Check and if necessary trigger the page creation
25     *
26     * @triggers USERPAGECREATE_PAGE_CREATE
27     * @param Doku_Event $event
28     * @param $param
29     */
30    public function handle_action_act_preprocess(Doku_Event $event, $param)
31    {
32        global $INPUT;
33        global $conf;
34
35        $user = $INPUT->server->str('REMOTE_USER');
36        if (!$user) return;
37
38        $data = $this->userSpaceData($user);
39        if ($data === null) return;
40        if ($data['exists']) return;
41
42        // trigger custom Event
43        Event::createAndTrigger(
44            'USERPAGECREATE_PAGE_CREATE',
45            $data,
46            array($this, 'createUserSpace'),
47            true
48        );
49    }
50
51    /**
52     * @param $user
53     * @return array|null The appropriate data or null if configuration failed
54     */
55    protected function userSpaceData($user)
56    {
57        global $conf;
58
59        // prepare info
60        $res = $this->getConf('target') . $user;
61        $tpl = $this->getConf('template');
62        $do_ns = (strlen($tpl) > 0) && substr($tpl, -1, 1) === ':';
63
64        // no ressource, nothing to do
65        if ($res === '') return null;
66
67        // Check if userpage or usernamespace already exists.
68        $exists = page_exists($res . ($do_ns ? (':' . $conf['start']) : ''));
69
70        // prepare Event Data
71        return array(
72            'do_ns' => $do_ns,
73            'tpl' => $tpl,
74            'res' => $res,
75            'exists' => $exists,
76        );
77    }
78
79    /**
80     * @param $data
81     */
82    public function createUserSpace($data)
83    {
84        global $conf;
85
86        $do_ns = $data['do_ns'];
87        $tpl = $data['tpl'];
88        $res = $data['res'];
89
90        // Get templates and target page names.
91        $parsed = false;
92        $pages = array();
93        if ($do_ns) {
94            $t_pages = array();
95            search($t_pages, $conf['datadir'], 'search_universal',
96                array('depth' => 0, 'listfiles' => true),
97                str_replace(':', '/', getNS($tpl)));
98            foreach ($t_pages as $t_page) {
99                $tpl_name = cleanID($t_page['id']);
100                $pages[$res . ':' . substr($tpl_name, strlen(getNS($tpl)) + 1)] = rawWiki($tpl_name);
101            }
102        } else {
103            if ($tpl === '') {
104                $pages[$res] = pageTemplate($res);
105                $parsed = true;
106            } elseif (page_exists($tpl)) {
107                $pages[$res] = rawWiki($tpl);
108            }
109        }
110
111        if (count($pages) === 0) {
112            return;
113        }
114
115        // Get additional user data from auth backend.
116        global $USERINFO;
117        $auth_replaces = $USERINFO;
118        foreach (array(
119                     'grps',
120                     'pass', // Secret data
121                     'name',
122                     'mail' // Already replaced by parsePageTemplate
123                 ) as $hidden) {
124            if (isset($auth_replaces[$hidden])) {
125                unset($auth_replaces[$hidden]);
126            }
127        }
128
129        // Parse templates and write pages.
130        foreach ($pages as $name => &$content) {
131            if (!$parsed) {
132                $byref_data = array('tpl' => $content, 'id' => $name);
133                $content = parsePageTemplate($byref_data);
134            }
135            foreach ($auth_replaces as $k => $v) {
136                $content = str_replace('@' . strtoupper($k) . '@', $v, $content);
137            }
138
139            saveWikiText($name, $content, $this->getConf('create_summary'));
140        }
141    }
142
143    /**
144     * Handle the deletion of the user page when the user is deleted
145     *
146     * @param Doku_Event $event
147     * @param $param
148     */
149    public function handleUserDeletion(Doku_Event $event, $param)
150    {
151        if ($event->data['type'] !== 'delete') return;
152
153        foreach ($event->data['params'] as $info) {
154            $user = $info[0];
155            $data = $this->userSpaceData($user);
156            if ($data === null) continue;
157            if (!$data['exists']) continue;
158            if ($data['do_ns']) {
159                $this->deleteNamespace($data['res']);
160            } else {
161                $this->deletePage($data['res']);
162            }
163        }
164    }
165
166    /**
167     * Delete the given namespace and all old revisions
168     *
169     * @param string $ns
170     */
171    protected function deleteNamespace($ns)
172    {
173        global $conf;
174
175        $ns = str_replace(':', '/', $ns);
176
177        // pages
178        $dir = $conf['datadir'] . '/' . utf8_encodeFN($ns);
179        if (is_dir($dir)) {
180            io_rmdir($dir, true);
181        }
182
183        // attic
184        $dir = $conf['olddir'] . '/' . utf8_encodeFN($ns);
185        if (is_dir($dir)) {
186            io_rmdir($dir, true);
187        }
188    }
189
190    /**
191     * Delete the given page and all old revisions
192     *
193     * @param string $page
194     */
195    protected function deletePage($page)
196    {
197        global $conf;
198
199        $page = str_replace(':', '/', $page);
200
201        // page
202        $file = $conf['datadir'] . '/' . utf8_encodeFN($page) . '.txt';
203        if (is_file($file)) {
204            unlink($file);
205        }
206
207        // attic
208        $files = glob($conf['olddir'] . '/' . utf8_encodeFN($page) . '.*.txt.*');
209        foreach ($files as $file) {
210            if (is_file($file)) {
211                unlink($file);
212            }
213        }
214    }
215}
216