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