xref: /plugin/approve/action/approve.php (revision b81b11283adb1dcdb0fe36d5f4bdac1021fa065b)
1<?php
2
3use dokuwiki\plugin\approve\meta\ApproveConst;
4
5if(!defined('DOKU_INC')) die();
6
7class action_plugin_approve_approve extends DokuWiki_Action_Plugin {
8
9    /** @var DokuWiki_PluginInterface */
10    protected $hlp;
11
12    function __construct(){
13        $this->hlp = plugin_load('helper', 'approve');
14    }
15
16    function register(Doku_Event_Handler $controller) {
17
18        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handle_approve', array());
19        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handle_viewer', array());
20        $controller->register_hook('TPL_ACT_RENDER', 'AFTER', $this, 'handle_diff_accept', array());
21        $controller->register_hook('TPL_ACT_RENDER', 'BEFORE', $this, 'handle_display_banner', array());
22        $controller->register_hook('HTML_SHOWREV_OUTPUT', 'BEFORE', $this, 'handle_showrev', array());
23        // ensure a page revision is created when summary changes:
24        $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'BEFORE', $this, 'handle_pagesave_before');
25        $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'AFTER', $this, 'handle_pagesave_after');
26    }
27
28	function handle_diff_accept(Doku_Event $event, $param) {
29		global $ID;
30
31		if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID)) return;
32
33		if ($event->data == 'diff' && isset($_GET['approve'])) {
34			ptln('<a href="'.DOKU_URL.'doku.php?id='.$_GET['id'].'&approve=approve">'.$this->getLang('approve').'</a>');
35		}
36
37        if ($event->data == 'diff' && isset($_GET['ready_for_approval']) && $this->getConf('ready_for_approval') === 1) {
38			ptln('<a href="'.DOKU_URL.'doku.php?id='.$_GET['id'].'&ready_for_approval=ready_for_approval">'.$this->getLang('approve_ready').'</a>');
39		}
40	}
41
42	function handle_showrev(Doku_Event $event, $param) {
43		global $REV;
44
45		$last = $this->find_lastest_approved();
46		if ($last == $REV)
47			$event->preventDefault();
48	}
49
50	function can_approve() {
51		global $ID;
52		return auth_quickaclcheck($ID) >= AUTH_DELETE;
53	}
54
55    function can_edit() {
56		global $ID;
57		return auth_quickaclcheck($ID) >= AUTH_EDIT;
58	}
59
60	function handle_approve(Doku_Event $event, $param) {
61		global $ID;
62
63		if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID)) return;
64
65		if ($event->data == 'show' && isset($_GET['approve'])) {
66		    if ( ! $this->can_approve()) return;
67
68		    //create new page revison
69            saveWikiText($ID, rawWiki($ID), ApproveConst::APPROVED);
70
71			header('Location: ?id='.$ID);
72		} elseif ($event->data == 'show' && isset($_GET['ready_for_approval'])) {
73		    if ( ! $this->can_edit()) return;
74
75            //create new page revison
76            saveWikiText($ID, rawWiki($ID), ApproveConst::READY_FOR_APPROVAL);
77
78            header('Location: ?id='.$ID);
79		}
80	}
81
82    function handle_viewer(Doku_Event $event, $param) {
83        global $REV, $ID;
84        if ($event->data != 'show') return;
85        if (auth_quickaclcheck($ID) > AUTH_READ || ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID))) return;
86
87	    $last = $this->find_lastest_approved();
88	    //no page is approved
89		if ($last == -1) return;
90		//approved page is the newest page
91		if ($last == 0) return;
92
93		//if we are viewing lastest revision, show last approved
94		if ($REV == 0) header("Location: ?id=$ID&rev=$last");
95	}
96
97	function find_lastest_approved() {
98		global $ID;
99		$m = p_get_metadata($ID);
100		$sum = $m['last_change']['sum'];
101		if ($sum == ApproveConst::APPROVED)
102			return 0;
103
104		$changelog = new PageChangeLog($ID);
105
106		$chs = $changelog->getRevisions(0, 10000);
107		foreach ($chs as $rev) {
108			$ch = $changelog->getRevisionInfo($rev);
109			if ($ch['sum'] == ApproveConst::APPROVED)
110				return $rev;
111		}
112		return -1;
113	}
114
115    function handle_display_banner(Doku_Event $event, $param) {
116		global $ID, $REV, $INFO;
117
118		if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID)) return;
119        if ($event->data != 'show') return;
120		if (!$INFO['exists']) return;
121
122		$sum = $this->hlp->page_sum($ID, $REV);
123
124
125		$classes = array();
126		if ($this->getConf('prettyprint')) {
127		    $classes[] = 'plugin__approve_noprint';
128        }
129
130        if ($sum == ApproveConst::APPROVED) {
131		    $classes[] = 'plugin__approve_green';
132		} elseif ($sum == ApproveConst::READY_FOR_APPROVAL && $this->getConf('ready_for_approval')) {
133		    $classes[] = 'plugin__approve_ready';
134        } else {
135            $classes[] = 'plugin__approve_red';
136        }
137
138		ptln('<div id="plugin__approve" class="' . implode(' ', $classes) . '">');
139
140		tpl_pageinfo();
141		ptln(' | ');
142		$last_approved_rev = $this->find_lastest_approved();
143		if ($sum == ApproveConst::APPROVED) {
144		    $versions = p_get_metadata($ID, ApproveConst::METADATA_VERSIONS_KEY);
145		    if (!$versions) {
146                $versions = $this->render_metadata_for_approved_page($ID);
147            }
148            if (empty($REV)) {
149                $version = $versions[0];
150            } else {
151                $version = $versions[$REV];
152            }
153
154			ptln('<strong>'.$this->getLang('approved').'</strong> (' . $this->getLang('version') .  ': ' . $version
155                 . ')');
156			if ($REV != 0 && auth_quickaclcheck($ID) > AUTH_READ) {
157				ptln('<a href="'.wl($ID).'">');
158				ptln($this->getLang(p_get_metadata($ID, 'last_change sum') == ApproveConst::APPROVED ? 'newest_approved' : 'newest_draft'));
159				ptln('</a>');
160			} else if ($REV != 0 && $REV != $last_approved_rev) {
161				ptln('<a href="'.wl($ID).'">');
162				ptln($this->getLang('newest_approved'));
163				ptln('</a>');
164			}
165		} else {
166			ptln('<span>'.$this->getLang('draft').'</span>');
167
168			if ($sum == ApproveConst::READY_FOR_APPROVAL && $this->getConf('ready_for_approval') === 1) {
169				ptln('<span>| '.$this->getLang('marked_approve_ready').'</span>');
170			}
171
172
173			if ($last_approved_rev == -1) {
174			    if ($REV != 0) {
175				    ptln('<a href="'.wl($ID).'">');
176				    	ptln($this->getLang('newest_draft'));
177				    ptln('</a>');
178				}
179			} else {
180				if ($last_approved_rev != 0)
181					ptln('<a href="'.wl($ID, array('rev' => $last_approved_rev)).'">');
182				else
183					ptln('<a href="'.wl($ID).'">');
184
185					ptln($this->getLang('newest_approved'));
186				ptln('</a>');
187			}
188
189			if ($REV == 0 && $this->can_edit() && $sum != ApproveConst::READY_FOR_APPROVAL && $this->getConf('ready_for_approval') === 1) {
190				ptln(' | <a href="'.wl($ID, array('rev' => $last_approved_rev, 'do' => 'diff',
191				'ready_for_approval' => 'ready_for_approval')).'">');
192					ptln($this->getLang('approve_ready'));
193				ptln('</a>');
194			}
195
196			if ($REV == 0 && $this->can_approve()) {
197				ptln(' | <a href="'.wl($ID, array('rev' => $last_approved_rev, 'do' => 'diff',
198				'approve' => 'approve')).'">');
199					ptln($this->getLang('approve'));
200				ptln('</a>');
201			}
202
203
204		}
205		ptln('</div>');
206	}
207
208    /**
209     * Check if the page has to be changed
210     *
211     * @param Doku_Event $event  event object by reference
212     * @param mixed      $param  [the parameters passed as fifth argument to register_hook() when this
213     *                           handler was registered]
214     * @return void
215     */
216    public function handle_pagesave_before(Doku_Event $event, $param) {
217        global $REV;
218        $id = $event->data['id'];
219        if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $id)) return;
220
221        //save page if summary is provided
222        if($event->data['summary'] == ApproveConst::APPROVED) {
223            $event->data['contentChanged'] = true;
224        }
225    }
226
227    /**
228     * @param Doku_Event $event
229     * @param            $param
230     */
231    public function handle_pagesave_after(Doku_Event $event, $param) {
232        global $REV;
233        $id = $event->data['id'];
234        if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $id)) return;
235
236        //save page if summary is provided
237        if($event->data['summary'] == ApproveConst::APPROVED) {
238
239            $versions = p_get_metadata($id, ApproveConst::METADATA_VERSIONS_KEY);
240            //calculate versions
241            if (!$versions) {
242                $this->render_metadata_for_approved_page($id, $event->data['newRevision']);
243            } else {
244                $curver = $versions[0] + 1;
245                $versions[0] = $curver;
246                $versions[$event->data['newRevision']] = $curver;
247                p_set_metadata($id, array(ApproveConst::METADATA_VERSIONS_KEY => $versions));
248            }
249        }
250    }
251
252
253    /**
254     * Calculate current version
255     *
256     * @param $id
257     * @return array
258     */
259    protected function render_metadata_for_approved_page($id, $currev=false) {
260        if (!$currev) $currev = @filemtime(wikiFN($id));
261
262        $version = $this->approved($id);
263        //version for current page
264        $curver = $version + 1;
265        $versions = array(0 => $curver, $currev => $curver);
266
267        $changelog = new PageChangeLog($id);
268        $first = 0;
269        $num = 100;
270        while (count($revs = $changelog->getRevisions($first, $num)) > 0) {
271            foreach ($revs as $rev) {
272                $revInfo = $changelog->getRevisionInfo($rev);
273                if ($revInfo['sum'] == ApproveConst::APPROVED) {
274                    $versions[$rev] = $version;
275                    $version -= 1;
276                }
277            }
278            $first += $num;
279        }
280
281        p_set_metadata($id, array(ApproveConst::METADATA_VERSIONS_KEY => $versions));
282
283        return $versions;
284    }
285
286    /**
287     * Get the number of approved pages
288     * @param $id
289     * @return int
290     */
291    protected function approved($id) {
292        $count = 0;
293
294        $changelog = new PageChangeLog($id);
295        $first = 0;
296        $num = 100;
297        while (count($revs = $changelog->getRevisions($first, $num)) > 0) {
298            foreach ($revs as $rev) {
299                $revInfo = $changelog->getRevisionInfo($rev);
300                if ($revInfo['sum'] == ApproveConst::APPROVED) {
301                    $count += 1;
302                }
303            }
304            $first += $num;
305        }
306
307        return $count;
308    }
309}
310