xref: /plugin/approve/action/approve.php (revision bb67de1956b60d99a190daf3aec22a269459e1dc)
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->use_approve_here($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->use_approve_here($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), $this->getConf('sum 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), $this->getConf('sum 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->use_approve_here($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 == $this->getConf('sum 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'] == $this->getConf('sum 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->use_approve_here($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 == $this->getConf('sum approved')) {
131		    $classes[] = 'plugin__approve_green';
132		} elseif ($sum == $this->getConf('sum 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 == $this->getConf('sum 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') == $this->getConf('sum 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 == $this->getConf('sum 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 != $this->getConf('sum 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->use_approve_here($id)) return;
220
221        //save page if summary is provided
222        if($event->data['summary'] == $this->getConf('sum approved') ||
223            $event->data['summary'] == $this->getConf('sum ready for approval')) {
224            $event->data['contentChanged'] = true;
225        }
226    }
227
228    /**
229     * @param Doku_Event $event
230     * @param            $param
231     */
232    public function handle_pagesave_after(Doku_Event $event, $param) {
233        global $REV;
234        $id = $event->data['id'];
235        if (!$this->hlp->use_approve_here($id)) return;
236
237        //save page if summary is provided
238        if($event->data['summary'] == $this->getConf('sum approved')) {
239
240            $versions = p_get_metadata($id, ApproveConst::METADATA_VERSIONS_KEY);
241            //calculate versions
242            if (!$versions) {
243                $this->render_metadata_for_approved_page($id, $event->data['newRevision']);
244            } else {
245                $curver = $versions[0] + 1;
246                $versions[0] = $curver;
247                $versions[$event->data['newRevision']] = $curver;
248                p_set_metadata($id, array(ApproveConst::METADATA_VERSIONS_KEY => $versions));
249            }
250        }
251    }
252
253
254    /**
255     * Calculate current version
256     *
257     * @param $id
258     * @return array
259     */
260    protected function render_metadata_for_approved_page($id, $currev=false) {
261        if (!$currev) $currev = @filemtime(wikiFN($id));
262
263        $version = $this->approved($id);
264        //version for current page
265        $curver = $version + 1;
266        $versions = array(0 => $curver, $currev => $curver);
267
268        $changelog = new PageChangeLog($id);
269        $first = 0;
270        $num = 100;
271        while (count($revs = $changelog->getRevisions($first, $num)) > 0) {
272            foreach ($revs as $rev) {
273                $revInfo = $changelog->getRevisionInfo($rev);
274                if ($revInfo['sum'] == $this->getConf('sum approved')) {
275                    $versions[$rev] = $version;
276                    $version -= 1;
277                }
278            }
279            $first += $num;
280        }
281
282        p_set_metadata($id, array(ApproveConst::METADATA_VERSIONS_KEY => $versions));
283
284        return $versions;
285    }
286
287    /**
288     * Get the number of approved pages
289     * @param $id
290     * @return int
291     */
292    protected function approved($id) {
293        $count = 0;
294
295        $changelog = new PageChangeLog($id);
296        $first = 0;
297        $num = 100;
298        while (count($revs = $changelog->getRevisions($first, $num)) > 0) {
299            foreach ($revs as $rev) {
300                $revInfo = $changelog->getRevisionInfo($rev);
301                if ($revInfo['sum'] == $this->getConf('sum approved')) {
302                    $count += 1;
303                }
304            }
305            $first += $num;
306        }
307
308        return $count;
309    }
310}
311