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