xref: /plugin/approve/action/approve.php (revision 165e4a3f51b8f2d6aa8fa6db125d9116aca89c60)
1<?php
2
3if(!defined('DOKU_INC')) die();
4define(APPROVED, 'Approved');
5define(READY_FOR_APPROVAL, 'Ready for approval');
6
7define(METADATA_VERSION_KEY, 'plugin_approve_version');
8
9class action_plugin_approve_approve extends DokuWiki_Action_Plugin {
10
11    private $hlp;
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    }
26
27	function handle_diff_accept(Doku_Event $event, $param) {
28		global $ID;
29
30		if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID)) return;
31
32		if ($event->data == 'diff' && isset($_GET['approve'])) {
33			ptln('<a href="'.DOKU_URL.'doku.php?id='.$_GET['id'].'&approve=approve">'.$this->getLang('approve').'</a>');
34		}
35
36        if ($event->data == 'diff' && isset($_GET['ready_for_approval']) && $this->getConf('ready_for_approval') === 1) {
37			ptln('<a href="'.DOKU_URL.'doku.php?id='.$_GET['id'].'&ready_for_approval=ready_for_approval">'.$this->getLang('approve_ready').'</a>');
38		}
39	}
40
41	function handle_showrev(Doku_Event $event, $param) {
42		global $ID, $REV;
43
44		$last = $this->find_lastest_approved();
45		if ($last == $REV)
46			$event->preventDefault();
47	}
48
49	function can_approve() {
50		global $ID;
51		return auth_quickaclcheck($ID) >= AUTH_DELETE;
52	}
53
54		function can_edit() {
55		global $ID;
56		return auth_quickaclcheck($ID) >= AUTH_EDIT;
57	}
58
59	function handle_approve(Doku_Event $event, $param) {
60		global $ID, $REV, $INFO;
61
62		if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID)) return;
63
64		if ($event->data == 'show' && isset($_GET['approve'])) {
65		    if ( ! $this->can_approve()) return;
66
67		    //create new page revison
68            saveWikiText($ID, rawWiki($ID), APPROVED);
69
70			header('Location: ?id='.$ID);
71		}
72
73		if ($event->data == 'show' && isset($_GET['ready_for_approval'])) {
74		    if ( ! $this->can_edit()) return;
75
76			//change last commit comment to Approved
77			$meta = p_read_metadata($ID);
78			$meta[current][last_change][sum] = $meta[persistent][last_change][sum] = READY_FOR_APPROVAL;
79			$meta[current][last_change][user] = $meta[persistent][last_change][user] = $INFO[client];
80			if (!array_key_exists($INFO[client], $meta[current][contributor])) {
81			    $meta[current][contributor][$INFO[client]] = $INFO[userinfo][name];
82			    $meta[persistent][contributor][$INFO[client]] = $INFO[userinfo][name];
83			}
84			p_save_metadata($ID, $meta);
85			//update changelog
86			//remove last line from file
87			$changelog_file = metaFN($ID, '.changes');
88			$changes = file($changelog_file, FILE_SKIP_EMPTY_LINES);
89			$lastLogLine = array_pop($changes);
90			$info = parseChangelogLine($lastLogLine);
91
92			$info[user] = $INFO[client];
93			$info[sum] = APPROVED;
94
95			$logline = implode("\t", $info)."\n";
96			array_push($changes, $logline);
97
98			io_saveFile($changelog_file, implode('', $changes));
99
100			header('Location: ?id='.$ID);
101		}
102	}
103    function handle_viewer(Doku_Event $event, $param) {
104        global $REV, $ID;
105        if ($event->data != 'show') return;
106        if (auth_quickaclcheck($ID) > AUTH_READ || ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID))) return;
107
108	    $last = $this->find_lastest_approved();
109	    //no page is approved
110		if ($last == -1) return;
111		//approved page is the newest page
112		if ($last == 0) return;
113
114		//if we are viewing lastest revision, show last approved
115		if ($REV == 0) header("Location: ?id=$ID&rev=$last");
116	}
117	function find_lastest_approved() {
118		global $ID;
119		$m = p_get_metadata($ID);
120		$sum = $m['last_change']['sum'];
121		if ($sum == APPROVED)
122			return 0;
123
124		$changelog = new PageChangeLog($ID);
125		//wyszukaj najnowszej zatwierdzonej
126		//poszukaj w dół
127		$chs = $changelog->getRevisions(0, 10000);
128		foreach ($chs as $rev) {
129			$ch = $changelog->getRevisionInfo($rev);
130			if ($ch['sum'] == APPROVED)
131				return $rev;
132		}
133		return -1;
134	}
135
136    function handle_display_banner(Doku_Event $event, $param) {
137		global $ID, $REV, $INFO;
138
139		if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID)) return;
140        if ($event->data != 'show') return;
141		if (!$INFO['exists']) return;
142
143		$sum = $this->hlp->page_sum($ID, $REV);
144
145		ptln('<div class="approval '.($sum == APPROVED ? 'approved_yes' : ($sum == READY_FOR_APPROVAL && $this->getConf('ready_for_approval') === 1 ? 'approved_ready' :'approved_no')).'">');
146
147		tpl_pageinfo();
148		ptln(' | ');
149		$last_approved_rev = $this->find_lastest_approved();
150		if ($sum == APPROVED) {
151		    $version = p_get_metadata($ID, METADATA_VERSION_KEY);
152		    if (!$version) {
153		        $version = $this->calculateVersion($ID);
154		        p_set_metadata($ID, array(METADATA_VERSION_KEY => $version));
155            }
156
157			ptln('<span>'.$this->getLang('approved').'</span> (' . $this->getLang('version') .  ': ' . $version
158                 . ')');
159			if ($REV != 0 && auth_quickaclcheck($ID) > AUTH_READ) {
160				ptln('<a href="'.wl($ID).'">');
161				ptln($this->getLang(p_get_metadata($ID, 'last_change sum') == APPROVED ? 'newest_approved' : 'newest_draft'));
162				ptln('</a>');
163			} else if ($REV != 0 && $REV != $last_approved_rev) {
164				ptln('<a href="'.wl($ID).'">');
165				ptln($this->getLang('newest_approved'));
166				ptln('</a>');
167			}
168		} else {
169			ptln('<span>'.$this->getLang('draft').'</span>');
170
171			if ($sum == READY_FOR_APPROVAL && $this->getConf('ready_for_approval') === 1) {
172				ptln('<span>| '.$this->getLang('marked_approve_ready').'</span>');
173			}
174
175
176			if ($last_approved_rev == -1) {
177			    if ($REV != 0) {
178				    ptln('<a href="'.wl($ID).'">');
179				    	ptln($this->getLang('newest_draft'));
180				    ptln('</a>');
181				}
182			} else {
183				if ($last_approved_rev != 0)
184					ptln('<a href="'.wl($ID, array('rev' => $last_approved_rev)).'">');
185				else
186					ptln('<a href="'.wl($ID).'">');
187
188					ptln($this->getLang('newest_approved'));
189				ptln('</a>');
190			}
191
192			if ($REV == 0 && $this->can_edit() && $sum != READY_FOR_APPROVAL && $this->getConf('ready_for_approval') === 1) {
193				ptln('<a href="'.wl($ID, array('rev' => $last_approved_rev, 'do' => 'diff',
194				'ready_for_approval' => 'ready_for_approval')).'">');
195					ptln($this->getLang('approve_ready'));
196				ptln('</a>');
197			}
198
199			//można zatwierdzać tylko najnowsze strony
200			if ($REV == 0 && $this->can_approve()) {
201				ptln('<a href="'.wl($ID, array('rev' => $last_approved_rev, 'do' => 'diff',
202				'approve' => 'approve')).'">');
203					ptln($this->getLang('approve'));
204				ptln('</a>');
205			}
206
207
208		}
209		ptln('</div>');
210	}
211
212    /**
213     * Check if the page has to be changed
214     *
215     * @param Doku_Event $event  event object by reference
216     * @param mixed      $param  [the parameters passed as fifth argument to register_hook() when this
217     *                           handler was registered]
218     * @return void
219     */
220    public function handle_pagesave_before(Doku_Event $event, $param) {
221        $id = $event->data['id'];
222        if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $id)) return;
223
224        //save page if summary is provided
225        if($event->data['summary'] == APPROVED) {
226            $event->data['contentChanged'] = true;
227
228            $version = p_get_metadata($id, METADATA_VERSION_KEY);
229
230            //calculate current version
231            if (!$version) {
232                $version = $this->calculateVersion($id);
233            } else {
234                $version += 1;
235            }
236
237            p_set_metadata($id, array(METADATA_VERSION_KEY => $version));
238        }
239    }
240
241    /**
242     * Calculate current version
243     *
244     * @param $id
245     * @return int
246     */
247    protected function calculateVersion($id) {
248        $version = 1;
249
250        $changelog = new PageChangeLog($id);
251        $first = 0;
252        $num = 100;
253        while (count($revs = $changelog->getRevisions($first, $num)) > 0) {
254            foreach ($revs as $rev) {
255                $revInfo = $changelog->getRevisionInfo($rev);
256                if ($revInfo['sum'] == APPROVED) {
257                    $version += 1;
258                }
259            }
260            $first += $num;
261        }
262
263        return $version;
264    }
265
266}
267