Prevent under E_STRICT - Strict Standards: opendir(/var/www/hosts/mediawiki/wiki...
[lhc/web/wiklou.git] / includes / SpecialRevisiondelete.php
1 <?php
2
3 /**
4 * Not quite ready for production use yet; need to fix up the restricted mode,
5 * and provide for preservation across delete/undelete of the page.
6 *
7 * To try this out, set up extra permissions something like:
8 * $wgGroupPermissions['sysop']['deleterevision'] = true;
9 * $wgGroupPermissions['bureaucrat']['hiderevision'] = true;
10 */
11
12 function wfSpecialRevisiondelete( $par = null ) {
13 global $wgOut, $wgRequest;
14
15 $target = $wgRequest->getVal( 'target' );
16 $oldid = $wgRequest->getIntArray( 'oldid' );
17
18 $page = Title::newFromUrl( $target );
19
20 if( is_null( $page ) ) {
21 $wgOut->showErrorPage( 'notargettitle', 'notargettext' );
22 return;
23 }
24
25 if( is_null( $oldid ) ) {
26 $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
27 return;
28 }
29
30 $form = new RevisionDeleteForm( $wgRequest );
31 if( $wgRequest->wasPosted() ) {
32 $form->submit( $wgRequest );
33 } else {
34 $form->show( $wgRequest );
35 }
36 }
37
38 class RevisionDeleteForm {
39 /**
40 * @param Title $page
41 * @param int $oldid
42 */
43 function __construct( $request ) {
44 global $wgUser;
45
46 $target = $request->getVal( 'target' );
47 $this->page = Title::newFromUrl( $target );
48
49 $this->revisions = $request->getIntArray( 'oldid', array() );
50
51 $this->skin = $wgUser->getSkin();
52 $this->checks = array(
53 array( 'revdelete-hide-text', 'wpHideText', Revision::DELETED_TEXT ),
54 array( 'revdelete-hide-comment', 'wpHideComment', Revision::DELETED_COMMENT ),
55 array( 'revdelete-hide-user', 'wpHideUser', Revision::DELETED_USER ),
56 array( 'revdelete-hide-restricted', 'wpHideRestricted', Revision::DELETED_RESTRICTED ) );
57 }
58
59 /**
60 * @param WebRequest $request
61 */
62 function show( $request ) {
63 global $wgOut, $wgUser;
64
65 $wgOut->addWikiText( wfMsg( 'revdelete-selected', $this->page->getPrefixedText() ) );
66
67 $wgOut->addHtml( "<ul>" );
68 foreach( $this->revisions as $revid ) {
69 $rev = Revision::newFromTitle( $this->page, $revid );
70 if( !isset( $rev ) ) {
71 $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
72 return;
73 }
74 $wgOut->addHtml( $this->historyLine( $rev ) );
75 $bitfields[] = $rev->mDeleted; // FIXME
76 }
77 $wgOut->addHtml( "</ul>" );
78
79 $wgOut->addWikiText( wfMsg( 'revdelete-text' ) );
80
81 $items = array(
82 wfInputLabel( wfMsg( 'revdelete-log' ), 'wpReason', 'wpReason', 60 ),
83 wfSubmitButton( wfMsg( 'revdelete-submit' ) ) );
84 $hidden = array(
85 wfHidden( 'wpEditToken', $wgUser->editToken() ),
86 wfHidden( 'target', $this->page->getPrefixedText() ) );
87 foreach( $this->revisions as $revid ) {
88 $hidden[] = wfHidden( 'oldid[]', $revid );
89 }
90
91 $special = SpecialPage::getTitleFor( 'Revisiondelete' );
92 $wgOut->addHtml( wfElement( 'form', array(
93 'method' => 'post',
94 'action' => $special->getLocalUrl( 'action=submit' ) ),
95 null ) );
96
97 $wgOut->addHtml( '<fieldset><legend>' . wfMsgHtml( 'revdelete-legend' ) . '</legend>' );
98 foreach( $this->checks as $item ) {
99 list( $message, $name, $field ) = $item;
100 $wgOut->addHtml( '<div>' .
101 wfCheckLabel( wfMsg( $message), $name, $name, $rev->isDeleted( $field ) ) .
102 '</div>' );
103 }
104 $wgOut->addHtml( '</fieldset>' );
105 foreach( $items as $item ) {
106 $wgOut->addHtml( '<p>' . $item . '</p>' );
107 }
108 foreach( $hidden as $item ) {
109 $wgOut->addHtml( $item );
110 }
111
112 $wgOut->addHtml( '</form>' );
113 }
114
115 /**
116 * @param Revision $rev
117 * @returns string
118 */
119 function historyLine( $rev ) {
120 global $wgContLang;
121 $date = $wgContLang->timeanddate( $rev->getTimestamp() );
122 return
123 "<li>" .
124 $this->skin->makeLinkObj( $this->page, $date, 'oldid=' . $rev->getId() ) .
125 " " .
126 $this->skin->revUserLink( $rev ) .
127 " " .
128 $this->skin->revComment( $rev ) .
129 "</li>";
130 }
131
132 /**
133 * @param WebRequest $request
134 */
135 function submit( $request ) {
136 $bitfield = $this->extractBitfield( $request );
137 $comment = $request->getText( 'wpReason' );
138 if( $this->save( $bitfield, $comment ) ) {
139 return $this->success( $request );
140 } else {
141 return $this->show( $request );
142 }
143 }
144
145 function success( $request ) {
146 global $wgOut;
147 $wgOut->addWikiText( 'woo' );
148 }
149
150 /**
151 * Put together a rev_deleted bitfield from the submitted checkboxes
152 * @param WebRequest $request
153 * @return int
154 */
155 function extractBitfield( $request ) {
156 $bitfield = 0;
157 foreach( $this->checks as $item ) {
158 list( /* message */ , $name, $field ) = $item;
159 if( $request->getCheck( $name ) ) {
160 $bitfield |= $field;
161 }
162 }
163 return $bitfield;
164 }
165
166 function save( $bitfield, $reason ) {
167 $dbw = wfGetDB( DB_MASTER );
168 $deleter = new RevisionDeleter( $dbw );
169 $deleter->setVisibility( $this->revisions, $bitfield, $reason );
170 }
171 }
172
173
174 class RevisionDeleter {
175 function __construct( $db ) {
176 $this->db = $db;
177 }
178
179 /**
180 * @param array $items list of revision ID numbers
181 * @param int $bitfield new rev_deleted value
182 * @param string $comment Comment for log records
183 */
184 function setVisibility( $items, $bitfield, $comment ) {
185 $pages = array();
186
187 // To work!
188 foreach( $items as $revid ) {
189 $rev = Revision::newFromId( $revid );
190 if( !isset( $rev ) ) {
191 return false;
192 }
193 $this->updateRevision( $rev, $bitfield );
194 $this->updateRecentChanges( $rev, $bitfield );
195
196 // For logging, maintain a count of revisions per page
197 $pageid = $rev->getPage();
198 if( isset( $pages[$pageid] ) ) {
199 $pages[$pageid]++;
200 } else {
201 $pages[$pageid] = 1;
202 }
203 }
204
205 // Clear caches...
206 foreach( $pages as $pageid => $count ) {
207 $title = Title::newFromId( $pageid );
208 $this->updatePage( $title );
209 $this->updateLog( $title, $count, $bitfield, $comment );
210 }
211
212 return true;
213 }
214
215 /**
216 * Update the revision's rev_deleted field
217 * @param Revision $rev
218 * @param int $bitfield new rev_deleted bitfield value
219 */
220 function updateRevision( $rev, $bitfield ) {
221 $this->db->update( 'revision',
222 array( 'rev_deleted' => $bitfield ),
223 array( 'rev_id' => $rev->getId() ),
224 'RevisionDeleter::updateRevision' );
225 }
226
227 /**
228 * Update the revision's recentchanges record if fields have been hidden
229 * @param Revision $rev
230 * @param int $bitfield new rev_deleted bitfield value
231 */
232 function updateRecentChanges( $rev, $bitfield ) {
233 $this->db->update( 'recentchanges',
234 array(
235 'rc_user' => ($bitfield & Revision::DELETED_USER) ? 0 : $rev->getUser(),
236 'rc_user_text' => ($bitfield & Revision::DELETED_USER) ? wfMsg( 'rev-deleted-user' ) : $rev->getUserText(),
237 'rc_comment' => ($bitfield & Revision::DELETED_COMMENT) ? wfMsg( 'rev-deleted-comment' ) : $rev->getComment() ),
238 array(
239 'rc_this_oldid' => $rev->getId() ),
240 'RevisionDeleter::updateRecentChanges' );
241 }
242
243 /**
244 * Touch the page's cache invalidation timestamp; this forces cached
245 * history views to refresh, so any newly hidden or shown fields will
246 * update properly.
247 * @param Title $title
248 */
249 function updatePage( $title ) {
250 $title->invalidateCache();
251 }
252
253 /**
254 * Record a log entry on the action
255 * @param Title $title
256 * @param int $count the number of revisions altered for this page
257 * @param int $bitfield the new rev_deleted value
258 * @param string $comment
259 */
260 function updateLog( $title, $count, $bitfield, $comment ) {
261 $log = new LogPage( 'delete' );
262 $reason = "changed $count revisions to $bitfield";
263 $reason .= ": $comment";
264 $log->addEntry( 'revision', $title, $reason );
265 }
266 }
267
268 ?>