73 $this->user = RequestContext::getMain()->getUser();
80 if ( $this->title ===
null ) {
97 if ( $params[
'older_than'] !==
null && $params[
'newer_than'] !==
null ) {
99 new MessageValue(
'rest-pagehistory-incompatible-params' ), 400 );
102 if ( ( $params[
'older_than'] !==
null && $params[
'older_than'] < 1 ) ||
103 ( $params[
'newer_than'] !==
null && $params[
'newer_than'] < 1 )
106 new MessageValue(
'rest-pagehistory-param-range-error' ), 400 );
110 if ( $params[
'filter'] ===
'reverted' ) {
111 foreach ( self::REVERTED_TAG_NAMES as $tagName ) {
113 $tagIds[] = $this->changeTagDefStore->getId( $tagName );
120 $titleObj = Title::newFromText(
$title );
121 if ( !$titleObj || !$titleObj->getArticleID() ) {
129 if ( !$this->permissionManager->userCan(
'read', $this->user, $titleObj ) ) {
137 $relativeRevId = $params[
'older_than'] ?? $params[
'newer_than'] ?? 0;
138 if ( $relativeRevId ) {
140 $rev = $this->revisionStore->getRevisionByPageId(
141 $titleObj->getArticleID(),
152 $ts = $rev->getTimestamp();
153 if ( $ts ===
null ) {
165 $res = $this->
getDbResults( $titleObj, $params, $relativeRevId, $ts, $tagIds );
180 $revQuery = $this->revisionStore->getQueryInfo();
185 if ( $params[
'filter'] ) {
189 "temp_rev_user.revactor_rev = rev_id AND revactor_page = rev_page";
192 switch ( $params[
'filter'] ) {
194 $cond[] =
'EXISTS(' .
$dbr->selectSQLText(
198 'actor_rev_user.actor_user = ug_user',
199 'ug_group' => $this->permissionManager->getGroupsWithPermission(
'bot' ),
200 'ug_expiry IS NULL OR ug_expiry >= ' .
$dbr->addQuotes(
$dbr->timestamp() )
206 $cond[] =
$dbr->bitAnd(
'rev_deleted', $bitmask ) .
" != $bitmask";
211 $cond[] =
"actor_user IS NULL";
214 $cond[] =
$dbr->bitAnd(
'rev_deleted', $bitmask ) .
" != $bitmask";
222 $cond[] =
'EXISTS(' .
$dbr->selectSQLText(
225 [
'ct_rev_id = rev_id',
'ct_tag_id' => $tagIds ],
231 $cond[] =
'rev_minor_edit != 0';
236 if ( $relativeRevId ) {
237 $op = $params[
'older_than'] ?
'<' :
'>';
238 $sort = $params[
'older_than'] ?
'DESC' :
'ASC';
239 $ts =
$dbr->addQuotes(
$dbr->timestamp( $ts ) );
240 $cond[] =
"rev_timestamp $op $ts OR " .
241 "(rev_timestamp = $ts AND rev_id $op $relativeRevId)";
242 $orderBy =
"rev_timestamp $sort, rev_id $sort";
244 $orderBy =
"rev_timestamp DESC, rev_id DESC";
248 $limit = self::REVISIONS_RETURN_LIMIT + 1;
256 'ORDER BY' => $orderBy,
273 if ( !$this->permissionManager->userHasRight( $this->user,
'deletedhistory' ) ) {
274 $bitmask = RevisionRecord::DELETED_USER;
275 } elseif ( !$this->permissionManager
276 ->userHasAnyRight( $this->user,
'suppressrevision',
'viewsuppressed' )
278 $bitmask = RevisionRecord::DELETED_USER | RevisionRecord::DELETED_RESTRICTED;
296 foreach (
$res as $row ) {
297 $rev = $this->revisionStore->newRevisionFromRow(
299 IDBAccessObject::READ_NORMAL,
303 $firstRevId = $row->rev_id;
305 $lastRevId = $row->rev_id;
308 'id' => $rev->getId(),
309 'timestamp' =>
wfTimestamp( TS_ISO_8601, $rev->getTimestamp() ),
310 'minor' => $rev->isMinor(),
311 'size' => $rev->getSize()
316 $sizes[$rev->getId()] = $rev->getSize();
317 $parentId = $rev->getParentId();
319 $revision[
'parent_id'] = $parentId;
322 $comment = $rev->getComment( RevisionRecord::FOR_THIS_USER, $this->user );
323 $revision[
'comment'] = $comment ? $comment->text :
null;
325 $revUser = $rev->getUser( RevisionRecord::FOR_THIS_USER, $this->user );
327 $revision[
'user'] = [
328 'id' => $revUser->isRegistered() ? $revUser->getId() :
null,
329 'name' => $revUser->getName()
332 $revision[
'user'] =
null;
335 $revisions[] = $revision;
338 if ( count( $revisions ) == self::REVISIONS_RETURN_LIMIT ) {
345 foreach ( $revisions as $revision ) {
346 if ( isset( $revision[
'parent_id'] ) && !isset( $sizes[$revision[
'parent_id']] ) ) {
347 $unknownSizes[] = $revision[
'parent_id'];
350 if ( $unknownSizes ) {
351 $sizes += $this->revisionStore->getRevisionSizes( $unknownSizes );
353 foreach ( $revisions as &$revision ) {
354 $revision[
'delta'] =
null;
355 if ( isset( $revision[
'parent_id'] ) ) {
356 if ( isset( $sizes[$revision[
'parent_id']] ) ) {
357 $revision[
'delta'] = $revision[
'size'] - $sizes[$revision[
'parent_id']];
361 unset( $revision[
'parent_id'] );
365 if ( $revisions && $params[
'newer_than'] ) {
366 $revisions = array_reverse( $revisions );
368 $lastRevId = $firstRevId;
374 'revisions' => $revisions
380 if ( $params[
'newer_than'] ||
$res->numRows() > self::REVISIONS_RETURN_LIMIT ) {
383 if ( $params[
'older_than'] ||
384 ( $params[
'newer_than'] &&
$res->numRows() > self::REVISIONS_RETURN_LIMIT )
386 $newer = $firstRevId;
392 if ( isset( $params[
'filter'] ) ) {
393 $queryParts[
'filter'] = $params[
'filter'];
396 $pathParams = [
'title' => $titleObj->getPrefixedDBkey() ];
398 $response[
'latest'] = $this->
getRouteUrl( $pathParams, $queryParts );
400 if ( isset( $older ) ) {
402 $this->
getRouteUrl( $pathParams, $queryParts + [
'older_than' => $older ] );
404 if ( isset( $newer ) ) {
406 $this->
getRouteUrl( $pathParams, $queryParts + [
'newer_than' => $newer ] );
419 self::PARAM_SOURCE =>
'path',
420 ParamValidator::PARAM_TYPE =>
'string',
421 ParamValidator::PARAM_REQUIRED =>
true,
424 self::PARAM_SOURCE =>
'query',
425 ParamValidator::PARAM_TYPE =>
'integer',
426 ParamValidator::PARAM_REQUIRED =>
false,
429 self::PARAM_SOURCE =>
'query',
430 ParamValidator::PARAM_TYPE =>
'integer',
431 ParamValidator::PARAM_REQUIRED =>
false,
434 self::PARAM_SOURCE =>
'query',
436 ParamValidator::PARAM_REQUIRED =>
false,
466 $rev = $this->revisionStore->getKnownCurrentRevision(
$title );
467 return $rev->getTimestamp();
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Handler class for Core REST API endpoints that perform operations on revisions.
getETag()
Returns an ETag representing a page's latest revision.
RevisionStore $revisionStore
const ALLOWED_FILTER_TYPES
ILoadBalancer $loadBalancer
__construct(RevisionStore $revisionStore, NameTableStoreFactory $nameTableStoreFactory, PermissionManager $permissionManager, ILoadBalancer $loadBalancer)
RevisionStore $revisionStore.
processDbResults( $res, $titleObj, $params)
getLastModified()
Returns the time of the last change to the page.
PermissionManager $permissionManager
NameTableStore $changeTagDefStore
getBitmask()
Helper function for rev_deleted/user rights query conditions.
needsWriteAccess()
Indicates whether this route requires write access.
run( $title)
At most one of older_than and newer_than may be specified.
getParamSettings()
Fetch ParamValidator settings for parameters.
const REVISIONS_RETURN_LIMIT
getDbResults(Title $titleObj, array $params, $relativeRevId, $ts, $tagIds)
Group all the pieces relevant to the context of a request into one instance @newable.
Represents a title within MediaWiki.
getLatestRevID( $flags=0)
What is the page_latest field for this page?
getArticleID( $flags=0)
Get the article ID for this Title from the link cache, adding it if necessary.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Interface for database access objects.