32 private $mPageSet =
null;
35 private $expiryEnabled;
41 private $labelsEnabled;
52 parent::__construct( $mainModule, $moduleName );
61 if ( !$user->isRegistered()
62 || ( $user->isTemp() && !$user->isAllowed(
'editmywatchlist' ) )
64 $this->
dieWithError(
'watchlistanontext',
'notloggedin' );
77 if ( isset( $params[
'labels'] ) && $params[
'labels'] ) {
78 $validationResult = $this->validateLabels( $user, $params[
'labels'] );
79 $validLabels = $validationResult[
'labels'];
80 $labelError = $validationResult[
'error'];
83 $pageSet = $this->getPageSet();
86 if ( !isset( $params[
'title'] ) ) {
88 $res = $pageSet->getInvalidTitlesAndRevisions( [
96 foreach ( $pageSet->getMissingPages() as $page ) {
97 $r = $this->watchTitle( $page, $user, $params,
false, $validLabels, $labelError );
102 foreach ( $pageSet->getGoodPages() as $page ) {
103 $r = $this->watchTitle( $page, $user, $params,
false, $validLabels, $labelError );
109 $extraParams = array_keys( array_filter( $pageSet->extractRequestParams(),
static function ( $x ) {
110 return $x !==
null && $x !==
false;
113 if ( $extraParams ) {
116 'apierror-invalidparammix-cannotusewith',
118 $pageSet->encodeParamName( $extraParams[0] )
124 $title = Title::newFromText( $params[
'title'] );
125 if ( !$title || !$this->watchlistManager->isWatchable( $title ) ) {
126 $this->
dieWithError( [
'invalidtitle', $params[
'title'] ] );
128 $res = $this->watchTitle( $title, $user, $params,
true, $validLabels, $labelError );
133 $continuationManager->setContinuationIntoResult( $this->
getResult() );
137 bool $compatibilityMode =
false,
138 array $validLabels = [],
139 ?array $labelError =
null
141 $res = [
'title' => $this->titleFormatter->getPrefixedText( $page ),
'ns' => $page->getNamespace() ];
143 if ( !$this->watchlistManager->isWatchable( $page ) ) {
144 $res[
'watchable'] = 0;
148 if ( $params[
'unwatch'] ) {
149 $status = $this->watchlistManager->removeWatch( $user, $page );
150 $res[
'unwatched'] = $status->isOK();
155 if ( $this->expiryEnabled && isset( $params[
'expiry'] ) ) {
156 $expiry = $params[
'expiry'];
160 $status = $this->watchlistManager->addWatch( $user, $page, $expiry );
161 $res[
'watched'] = $status->isOK();
164 if ( $status->isOK() && $validLabels ) {
165 $this->applyLabelsToWatchedPage( $user, $page, $validLabels, $compatibilityMode, $res );
168 if ( !isset( $res[
'errors'] ) ) {
171 $res[
'errors'][] = $labelError;
173 } elseif ( $status->isOK() && $labelError ) {
175 $res[
'errors'] = [ $labelError ];
179 if ( !$status->isOK() ) {
180 if ( $compatibilityMode ) {
183 $res[
'errors'] = $this->
getErrorFormatter()->arrayFromStatus( $status,
'error' );
184 $res[
'warnings'] = $this->
getErrorFormatter()->arrayFromStatus( $status,
'warning' );
185 if ( !$res[
'warnings'] ) {
186 unset( $res[
'warnings'] );
204 private function applyLabelsToWatchedPage(
208 bool $compatibilityMode,
211 if ( !$this->labelsEnabled ) {
212 $res[
'errors'] = [ $this->getErrorFormatter()->formatMessage(
213 [
'apierror-labels-disabled',
'labels-disabled' ]
215 if ( $compatibilityMode ) {
216 $this->dieWithError(
'apierror-labels-disabled',
'labels-disabled' );
221 $title = Title::newFromPageIdentity( $page );
222 $pagesToWatch = [ $page ];
225 if ( $this->namespaceInfo->canHaveTalkPage( $title ) ) {
226 $talkPageTarget = $this->namespaceInfo->getTalkPage( $title );
228 $talkPage = PageReferenceValue::localReference(
229 $talkPageTarget->getNamespace(),
230 $talkPageTarget->getDBkey()
232 $pagesToWatch[] = $talkPage;
236 foreach ( $pagesToWatch as $pageToWatch ) {
237 $watchedItem = $this->watchedItemStore->loadWatchedItem( $user, $pageToWatch );
238 if ( $watchedItem ) {
239 $existingLabels = $watchedItem->getLabels();
241 if ( $existingLabels ) {
242 $this->watchedItemStore->removeLabels( $user, [ $pageToWatch ], $existingLabels );
248 if ( $validLabels ) {
249 $this->watchedItemStore->addLabels( $user, $pagesToWatch, $validLabels );
251 $res[
'labels'] = array_map(
static function ( WatchlistLabel $label ) {
253 'id' => $label->getId(),
254 'name' => $label->getName(),
267 private function validateLabels( User $user, array $labelIds ): array {
269 if ( !$this->labelsEnabled ) {
272 'error' => $this->getErrorFormatter()->formatMessage(
273 [
'apierror-labels-disabled',
'labels-disabled' ]
278 $validLabels = $this->watchlistLabelStore->loadByIds( $user, $labelIds );
279 $hasError = count( $labelIds ) !== count( $validLabels );
282 'labels' => $validLabels,
283 'error' => $hasError ? $this->getErrorFormatter()->formatMessage(
284 [
'apierror-invalid-label-id',
'invalid-label-id' ]
293 private function getPageSet() {
294 $this->mPageSet ??=
new ApiPageSet( $this );
296 return $this->mPageSet;
318 ParamValidator::PARAM_TYPE =>
'string',
319 ParamValidator::PARAM_DEPRECATED =>
true,
322 ParamValidator::PARAM_TYPE =>
'expiry',
323 ExpiryDef::PARAM_MAX => $this->maxDuration,
324 ExpiryDef::PARAM_USE_MAX =>
true,
327 ParamValidator::PARAM_TYPE =>
'integer',
328 ParamValidator::PARAM_ISMULTI =>
true,
329 ApiBase::PARAM_HELP_MSG =>
'apihelp-watch-param-labels',
333 ApiBase::PARAM_HELP_MSG =>
'api-help-param-continue',
338 if ( !$this->expiryEnabled ) {
339 unset( $result[
'expiry'] );
343 $result += $this->getPageSet()->getFinalParams( $flags );
351 $title = Title::newMainPage()->getPrefixedText();
352 $mp = rawurlencode( $title );
356 "action=watch&titles={$mp}&token=123ABC"
357 =>
'apihelp-watch-example-watch',
359 if ( $this->expiryEnabled ) {
360 $examples[
"action=watch&titles={$mp}|Foo|Bar&expiry=1%20month&token=123ABC"]
361 =
'apihelp-watch-example-watch-expiry';
365 $examples[
"action=watch&titles={$mp}&labels=1%7C2&token=123ABC"]
366 =
'apihelp-watch-example-watch-labels';
368 return array_merge( $examples, [
369 "action=watch&titles={$mp}&unwatch=&token=123ABC"
370 =>
'apihelp-watch-example-unwatch',
371 'action=watch&generator=allpages&gapnamespace=0&token=123ABC'
372 =>
'apihelp-watch-example-generator',
378 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Watch';
383class_alias( ApiWatch::class,
'ApiWatch' );
if(!defined('MW_SETUP_CALLBACK'))
This is the main API class, used for both external and internal processing.
This class contains a list of pages that the client has requested.
A class containing constants representing the names of configuration variables.
const EnableWatchlistLabels
Name constant for the EnableWatchlistLabels setting, for use with Config::get()
const WatchlistExpiry
Name constant for the WatchlistExpiry setting, for use with Config::get()
const WatchlistExpiryMaxDuration
Name constant for the WatchlistExpiryMaxDuration setting, for use with Config::get()
Interface for objects (potentially) representing an editable wiki page.