1<?php
2/**
3 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
4 * @author     Esther Brunner <wikidesign@gmail.com>
5 */
6
7class action_plugin_blog extends DokuWiki_Action_Plugin {
8
9    /**
10     * register the eventhandlers
11     * @param Doku_Event_Handler $contr
12     */
13    function register(Doku_Event_Handler $contr) {
14        $contr->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handle_act_preprocess', array());
15        $contr->register_hook('FEED_ITEM_ADD', 'BEFORE', $this, 'handle_feed_item');
16        $contr->register_hook('PARSER_CACHE_USE', 'BEFORE', $this, 'handle_cache');
17    }
18
19    /**
20     * Checks if 'newentry' was given as action, if so we
21     * do handle the event our self and no further checking takes place
22     * @param Doku_Event $event
23     * @param $param
24     */
25    function handle_act_preprocess(Doku_Event $event, $param) {
26        if ($event->data != 'newentry') return; // nothing to do for us
27
28        $event->data = $this->_handle_newEntry($event);
29    }
30
31    /**
32     * Removes draft entries from feeds
33     *
34     * @param Doku_Event $event
35     * @param $param
36     *
37     * @author Michael Klier <chi@chimeric.de>
38     */
39    function handle_feed_item(Doku_Event $event, $param) {
40        global $conf;
41
42        $url = parse_url($event->data['item']->link);
43        $base_url = getBaseURL();
44
45        // determine page id by rewrite mode
46        switch($conf['userewrite']) {
47            case 0:
48                preg_match('#id=([^&]*)#', $url['query'], $match);
49                if($base_url != '/') {
50                    $id = cleanID(str_replace($base_url, '', $match[1]));
51                } else {
52                    $id = cleanID($match[1]);
53                }
54                break;
55
56            case 1:
57                if($base_url != '/') {
58                    $id = cleanID(str_replace('/',':',str_replace($base_url, '', $url['path'])));
59                } else {
60                    $id = cleanID(str_replace('/',':', $url['path']));
61                }
62                break;
63
64            case 2:
65                preg_match('#doku.php/([^&]*)#', $url['path'], $match);
66                if($base_url != '/') {
67                    $id = cleanID(str_replace($base_url, '', $match[1]));
68                } else {
69                    $id = cleanID($match[1]);
70                }
71                break;
72        }
73
74        // don't add drafts to the feed
75        if(p_get_metadata($id, 'type') == 'draft') {
76            $event->preventDefault();
77            return;
78        }
79    }
80
81    /**
82     * Creates a new entry page
83     *
84     * @param Doku_Event $event
85     * @return string
86     */
87    function _handle_newEntry(Doku_Event $event) {
88        global $ID, $INFO;
89
90        $ns    = cleanID($_REQUEST['ns']);
91        $title = str_replace(':', '', $_REQUEST['title']);
92        $ID    = $this->_newEntryID($ns, $title);
93        $INFO  = pageinfo();
94
95        // check if we are allowed to create this file
96        if ($INFO['perm'] >= AUTH_CREATE) {
97
98            // prepare the new thread file with default stuff
99            if (!@file_exists($INFO['filepath'])) {
100
101                //check if locked by anyone - if not lock for my self
102                if ($INFO['locked']) return 'locked';
103                else lock($ID);
104
105                global $TEXT;
106
107                $TEXT = pageTemplate($ID);
108                if (!$TEXT) {
109                    // if there is no page template, load our custom one
110                    $TEXT  = io_readFile(DOKU_PLUGIN.'blog/_template.txt');
111                }
112
113                $data = array('id' => $ID, 'ns' => $ns, 'title' => $_REQUEST['title']);
114                // Apply replacements regardless if they have already been applied by DokuWiki in order to
115                // make custom replacements like @TITLE@ available in standard page templates.
116                $TEXT = $this->_pageTemplate($TEXT, $data);
117
118                return 'preview';
119            } else {
120                return 'edit';
121            }
122        } else {
123            return 'show';
124        }
125    }
126
127    /**
128     * Adapted version of pageTemplate() function
129     *
130     * @param $text
131     * @param $data
132     * @return string|string[]
133     */
134    function _pageTemplate($text, $data) {
135        global $conf, $INFO;
136
137        $id   = $data['id'];
138        $user = $_SERVER['REMOTE_USER'];
139
140        // standard replacements
141        $replace = array(
142                '@ID@'   => $id,
143                '@NS@'   => $data['ns'],
144                '@PAGE@' => strtr(noNS($id),'_',' '),
145                '@USER@' => $user,
146                '@NAME@' => $INFO['userinfo']['name'],
147                '@MAIL@' => $INFO['userinfo']['mail'],
148                '@DATE@' => strftime($conf['dformat']),
149                );
150
151        // additional replacements
152        $replace['@TITLE@'] = $data['title'];
153
154        // tag if tag plugin is available
155        if ((@file_exists(DOKU_PLUGIN.'tag/syntax/tag.php'))
156                && (!plugin_isdisabled('tag'))) {
157            $replace['@TAG@'] = "\n\n{{tag>}}";
158        } else {
159            $replace['@TAG@'] = '';
160        }
161
162        // discussion if discussion plugin is available
163        if ((@file_exists(DOKU_PLUGIN.'discussion/syntax/comments.php'))
164                && (!plugin_isdisabled('discussion'))) {
165            $replace['@DISCUSSION@'] = "~~DISCUSSION~~";
166        } else {
167            $replace['@DISCUSSION@'] = '';
168        }
169
170        // linkbacks if linkback plugin is available
171        if ((@file_exists(DOKU_PLUGIN.'linkback/syntax.php'))
172                && (!plugin_isdisabled('linkback'))) {
173            $replace['@LINKBACK@'] = "~~LINKBACK~~";
174        } else {
175            $replace['@LINKBACK@'] = '';
176        }
177
178        // do the replace
179        return str_replace(array_keys($replace), array_values($replace), $text);
180    }
181
182    /**
183     * Returns the ID of a new entry based on its namespace, title and the date prefix
184     *
185     * @param $ns
186     * @param $title
187     * @return mixed|string|string[]|null
188     *
189     * @author  Michael Arlt <michael.arlt@sk-chwanstetten.de>
190     * @author  Esther Brunner <wikidesign@gmail.com>
191     */
192    function _newEntryID($ns, $title) {
193        $dateprefix  = $this->getConf('dateprefix');
194        if (substr($dateprefix, 0, 1) == '<') {
195            // <9?%y1-%y2:%d.%m._   ->  05-06:31.08._ | 06-07:01.09._
196            list($newmonth, $dateprefix) = explode('?', substr($dateprefix, 1));
197            if (intval(strftime("%m")) < intval($newmonth)) {
198                $longyear2 = strftime("%Y");
199                $longyear1 = $longyear2 - 1;
200            } else {
201                $longyear1 = strftime("%Y");
202                $longyear2 = $longyear1 + 1;
203            }
204            $shortyear1 = substr($longyear1, 2);
205            $shortyear2 = substr($longyear2, 2);
206            $dateprefix = str_replace(
207                    array('%Y1', '%Y2', '%y1', '%y2'),
208                    array($longyear1, $longyear2, $shortyear1, $shortyear2),
209                    $dateprefix
210                    );
211        }
212        $pre = strftime($dateprefix);
213        return cleanID(($ns ? $ns.':' : '').$pre.$title);
214    }
215
216    /**
217     * Expire the renderer cache of archive pages whenever a page is updated or a comment or linkback is added
218     *
219     * @param Doku_Event $event
220     * @param $params
221     *
222     * @author Michael Hamann <michael@content-space.de>
223     */
224    function handle_cache(Doku_Event $event, $params) {
225        global $conf;
226        /** @var cache_parser $cache */
227        $cache = $event->data;
228        if (!in_array($cache->mode, array('xhtml', 'metadata'))) return;
229        $page = $cache->page;
230
231        // try to extract the page id from the file if possible
232        if (empty($page)) {
233            if (strpos($cache->file, $conf['datadir']) === 0) {
234                $page = pathID(substr($cache->file, strlen($conf['datadir'])+1));
235            } else {
236                return;
237            }
238        }
239
240        $meta = p_get_metadata($page, 'plugin_blog');
241        if ($meta === null) return;
242
243        if (isset($meta['purgefile_cache'])) {
244            $cache->depends['files'][] = $conf['cachedir'].'/purgefile';
245            $cache->depends['files'][] = $conf['metadir'].'/_comments.changes';
246            $cache->depends['files'][] = $conf['metadir'].'/_linkbacks.changes';
247        }
248
249        // purge the cache when a page is listed that the current user can't access
250        if (isset($meta['archive_pages'])) {
251            foreach ($meta['archive_pages'] as $page) {
252                if (auth_quickaclcheck($page) < AUTH_READ) {
253                    $cache->depends['purge'] = true;
254                    return;
255                }
256            }
257        }
258    }
259}
260