wiki.techinc.nl/includes/api/ApiWatchlistTrait.php
MusikAnimal 6a898faed2 Add watchlist expiry support to applicable APIs
This introduces an ApiWatchlistTrait that refactors out common code
across APIs that allow you to watch pages. Some methods have been
migrated from ApiBase and changed completely, but codesearch suggests
they aren't being used outside the API modules in this patch.

Bug: T248512
Bug: T248514
Change-Id: Ia18627b9824dca81f44f0571e8420d89b7626cf6
2020-07-13 18:18:15 -04:00

148 lines
4.4 KiB
PHP

<?php
use Wikimedia\ParamValidator\ParamValidator;
use Wikimedia\ParamValidator\TypeDef\ExpiryDef;
/**
* An ApiWatchlistTrait adds class properties and convenience methods for APIs that allow you to
* watch a page. This should ONLY be used in API modules that extend ApiBase.
* Also, it should not be used in ApiWatch, which has its own special handling.
*
* Note the class-level properties watchlistExpiryEnabled and watchlistMaxDuration must still be
* set in the API module's constructor.
*
* @ingroup API
* @since 1.35
*/
trait ApiWatchlistTrait {
/** @var bool Whether watchlist expiries are enabled. */
private $watchlistExpiryEnabled;
/** @var string Relative maximum expiry. */
private $watchlistMaxDuration;
/**
* Get additional allow params specific to watchlisting.
* This should be merged in with the result of self::getAllowedParams().
*
* This purposefully does not include the deprecated 'watch' and 'unwatch'
* parameters that some APIs still accept.
*
* @param string[] $watchOptions
* @return array
*/
protected function getWatchlistParams( array $watchOptions = [] ): array {
if ( !$watchOptions ) {
$watchOptions = [
'watch',
'unwatch',
'preferences',
'nochange',
];
}
$result = [
'watchlist' => [
ParamValidator::PARAM_DEFAULT => 'preferences',
ParamValidator::PARAM_TYPE => $watchOptions,
],
];
if ( $this->watchlistExpiryEnabled ) {
$result['watchlistexpiry'] = [
ParamValidator::PARAM_TYPE => 'expiry',
ExpiryDef::PARAM_MAX => $this->watchlistMaxDuration,
ExpiryDef::PARAM_USE_MAX => true,
];
}
return $result;
}
/**
* Set a watch (or unwatch) based the based on a watchlist parameter.
* @param string $watch Valid values: 'watch', 'unwatch', 'preferences', 'nochange'
* @param Title $titleObj The article's title to change
* @param string|null $userOption The user option to consider when $watch=preferences
* @param string|null $expiry Optional expiry timestamp in any format acceptable to wfTimestamp(),
* null will not create expiries, or leave them unchanged should they already exist.
*/
protected function setWatch(
string $watch,
Title $titleObj,
?string $userOption = null,
?string $expiry = null
): void {
$value = $this->getWatchlistValue( $watch, $titleObj, $userOption );
WatchAction::doWatchOrUnwatch( $value, $titleObj, $this->getUser(), $expiry );
}
/**
* Return true if we're to watch the page, false if not.
* @param string $watchlist Valid values: 'watch', 'unwatch', 'preferences', 'nochange'
* @param Title $titleObj The page under consideration
* @param string|null $userOption The user option to consider when $watchlist=preferences.
* If not set will use watchdefault always and watchcreations if $titleObj doesn't exist.
* @return bool
*/
protected function getWatchlistValue(
string $watchlist,
Title $titleObj,
?string $userOption = null
): bool {
$user = $this->getUser();
$userWatching = $user->isWatched( $titleObj, User::IGNORE_USER_RIGHTS );
switch ( $watchlist ) {
case 'watch':
return true;
case 'unwatch':
return false;
case 'preferences':
// If the user is already watching, don't bother checking
if ( $userWatching ) {
return true;
}
// If no user option was passed, use watchdefault and watchcreations
if ( $userOption === null ) {
return $user->getBoolOption( 'watchdefault' ) ||
$user->getBoolOption( 'watchcreations' ) &&
!$titleObj->exists();
}
// Watch the article based on the user preference
return $user->getBoolOption( $userOption );
case 'nochange':
return $userWatching;
default:
return $userWatching;
}
}
/**
* Get formatted expiry from the given parameters, or null if no expiry was provided.
* @param array $params Request parameters passed to the API.
* @return string|null
*/
protected function getExpiryFromParams( array $params ): ?string {
$watchlistExpiry = null;
if ( $this->watchlistExpiryEnabled && isset( $params['watchlistexpiry'] ) ) {
$watchlistExpiry = ApiResult::formatExpiry( $params['watchlistexpiry'] );
}
return $watchlistExpiry;
}
/**
* Implemented by ApiBase. We do this because otherwise Phan would complain
* about calls to $this->getUser() in this trait, since it doesn't infer that
* classes using the trait are also extending ApiBase.
* @return User
*/
abstract protected function getUser();
}