3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
21 use MediaWiki\FileRepo\File\FileSelectQueryBuilder
;
22 use MediaWiki\MediaWikiServices
;
23 use MediaWiki\Page\UndeletePage
;
24 use MediaWiki\Title\Title
;
25 use MediaWiki\User\UserIdentity
;
26 use Wikimedia\Rdbms\IExpression
;
27 use Wikimedia\Rdbms\IReadableDatabase
;
28 use Wikimedia\Rdbms\IResultWrapper
;
29 use Wikimedia\Rdbms\LikeValue
;
30 use Wikimedia\Rdbms\SelectQueryBuilder
;
33 * Used to show archived pages and eventually restore them.
37 protected Title
$title;
39 public function __construct( Title
$title ) {
40 $this->title
= $title;
44 * List deleted pages recorded in the archive matching the
45 * given term, using search engine archive.
46 * Returns result wrapper with (ar_namespace, ar_title, count) fields.
48 * @param string $term Search term
49 * @return IResultWrapper|bool
51 public static function listPagesBySearch( $term ) {
52 $title = Title
::newFromText( $term );
54 $ns = $title->getNamespace();
55 $termMain = $title->getText();
56 $termDb = $title->getDBkey();
58 // Prolly won't work too good
59 // @todo handle bare namespace names cleanly?
61 $termMain = $termDb = $term;
64 // Try search engine first
65 $engine = MediaWikiServices
::getInstance()->newSearchEngine();
66 $engine->setLimitOffset( 100 );
67 $engine->setNamespaces( [ $ns ] );
68 $results = $engine->searchArchiveTitle( $termMain );
69 if ( !$results->isOK() ) {
72 $results = $results->getValue();
76 // Fall back to regular prefix search
77 return self
::listPagesByPrefix( $term );
80 $dbr = MediaWikiServices
::getInstance()->getConnectionProvider()->getReplicaDatabase();
81 $condTitles = array_values( array_unique( array_map( static function ( Title
$t ) {
82 return $t->getDBkey();
85 'ar_namespace' => $ns,
86 $dbr->expr( 'ar_title', '=', $condTitles )
87 ->or( 'ar_title', IExpression
::LIKE
, new LikeValue( $termDb, $dbr->anyString() ) ),
90 return self
::listPages( $dbr, $conds );
94 * List deleted pages recorded in the archive table matching the
96 * Returns result wrapper with (ar_namespace, ar_title, count) fields.
98 * @param string $prefix Title prefix
99 * @return IResultWrapper|bool
101 public static function listPagesByPrefix( $prefix ) {
102 $dbr = MediaWikiServices
::getInstance()->getConnectionProvider()->getReplicaDatabase();
104 $title = Title
::newFromText( $prefix );
106 $ns = $title->getNamespace();
107 $prefix = $title->getDBkey();
109 // Prolly won't work too good
110 // @todo handle bare namespace names cleanly?
115 'ar_namespace' => $ns,
116 $dbr->expr( 'ar_title', IExpression
::LIKE
, new LikeValue( $prefix, $dbr->anyString() ) ),
119 return self
::listPages( $dbr, $conds );
123 * @param IReadableDatabase $dbr
124 * @param string|array $condition
125 * @return IResultWrapper
127 protected static function listPages( IReadableDatabase
$dbr, $condition ) {
128 return $dbr->newSelectQueryBuilder()
129 ->select( [ 'ar_namespace', 'ar_title', 'count' => 'COUNT(*)' ] )
131 ->where( $condition )
132 ->groupBy( [ 'ar_namespace', 'ar_title' ] )
133 ->orderBy( [ 'ar_namespace', 'ar_title' ] )
135 ->caller( __METHOD__
)->fetchResultSet();
139 * List the deleted file revisions for this page, if it's a file page.
140 * Returns a result wrapper with various filearchive fields, or null
141 * if not a file page.
143 * @return IResultWrapper|null
144 * @todo Does this belong in Image for fuller encapsulation?
146 public function listFiles() {
147 if ( $this->title
->getNamespace() !== NS_FILE
) {
151 $dbr = MediaWikiServices
::getInstance()->getConnectionProvider()->getReplicaDatabase();
152 $queryBuilder = FileSelectQueryBuilder
::newForArchivedFile( $dbr );
153 $queryBuilder->where( [ 'fa_name' => $this->title
->getDBkey() ] )
154 ->orderBy( 'fa_timestamp', SelectQueryBuilder
::SORT_DESC
);
155 return $queryBuilder->caller( __METHOD__
)->fetchResultSet();
159 * Restore the given (or all) text and file revisions for the page.
160 * Once restored, the items will be removed from the archive tables.
161 * The deletion log will be updated with an undeletion notice.
164 * @deprecated since 1.38, use UndeletePage instead, hard-deprecated since 1.43
166 * @param array $timestamps Pass an empty array to restore all revisions,
167 * otherwise list the ones to undelete.
168 * @param UserIdentity $user
169 * @param string $comment
170 * @param array $fileVersions
171 * @param bool $unsuppress
172 * @param string|string[]|null $tags Change tags to add to log entry
173 * ($user should be able to add the specified tags before this is called)
174 * @return array|false [ number of file revisions restored, number of image revisions
175 * restored, log message ] on success, false on failure.
177 public function undeleteAsUser(
185 wfDeprecated( __METHOD__
, '1.43' );
186 $services = MediaWikiServices
::getInstance();
187 $page = $services->getWikiPageFactory()->newFromTitle( $this->title
);
188 $user = $services->getUserFactory()->newFromUserIdentity( $user );
189 $up = $services->getUndeletePageFactory()->newUndeletePage( $page, $user );
190 if ( is_string( $tags ) ) {
192 } elseif ( $tags === null ) {
196 ->setUndeleteOnlyTimestamps( $timestamps )
197 ->setUndeleteOnlyFileVersions( $fileVersions ?
: [] )
198 ->setUnsuppress( $unsuppress )
199 ->setTags( $tags ?
: [] )
200 ->undeleteUnsafe( $comment );
201 // BC with old return format
202 if ( $status->isGood() ) {
203 $restoredRevs = $status->getValue()[UndeletePage
::REVISIONS_RESTORED
];
204 $restoredFiles = $status->getValue()[UndeletePage
::FILES_RESTORED
];
205 if ( $restoredRevs === 0 && $restoredFiles === 0 ) {
208 $ret = [ $restoredRevs, $restoredFiles, $comment ];