MediaWiki  master
WatchAction.php
Go to the documentation of this file.
1 <?php
28 
34 class WatchAction extends FormAction {
35 
37  protected $watchlistExpiry;
38 
40  protected $expiryFormFieldName = 'expiry';
41 
43  protected $watchedItem = false;
44 
45  private WatchlistManager $watchlistManager;
46 
55  public function __construct(
56  Article $article,
58  WatchlistManager $watchlistManager,
59  WatchedItemStore $watchedItemStore
60  ) {
61  parent::__construct( $article, $context );
62  $this->watchlistExpiry = $this->getContext()->getConfig()->get( MainConfigNames::WatchlistExpiry );
63  if ( $this->watchlistExpiry ) {
64  // The watchedItem is only used in this action's form if $wgWatchlistExpiry is enabled.
65  $this->watchedItem = $watchedItemStore->getWatchedItem(
66  $this->getUser(),
67  $this->getTitle()
68  );
69  }
70  $this->watchlistManager = $watchlistManager;
71  }
72 
73  public function getName() {
74  return 'watch';
75  }
76 
77  public function requiresUnblock() {
78  return false;
79  }
80 
81  protected function getDescription() {
82  return '';
83  }
84 
85  public function onSubmit( $data ) {
86  // Even though we're never unwatching here, use WatchlistManager::setWatch()
87  // because it also checks for changed expiry.
88  $result = $this->watchlistManager->setWatch(
89  true,
90  $this->getAuthority(),
91  $this->getTitle(),
92  $this->getRequest()->getVal( 'wp' . $this->expiryFormFieldName )
93  );
94 
95  return Status::wrap( $result );
96  }
97 
98  protected function checkCanExecute( User $user ) {
99  if ( !$user->isRegistered()
100  || ( $user->isTemp() && !$user->isAllowed( 'editmywatchlist' ) )
101  ) {
102  throw new UserNotLoggedIn( 'watchlistanontext', 'watchnologin' );
103  }
104 
105  parent::checkCanExecute( $user );
106  }
107 
108  public function getRestriction() {
109  return 'editmywatchlist';
110  }
111 
112  protected function usesOOUI() {
113  return true;
114  }
115 
116  protected function getFormFields() {
117  // If watchlist expiry is not enabled, return a simple confirmation message.
118  if ( !$this->watchlistExpiry ) {
119  return [
120  'intro' => [
121  'type' => 'info',
122  'raw' => true,
123  'default' => $this->msg( 'confirm-watch-top' )->parse(),
124  ],
125  ];
126  }
127 
128  // Otherwise, use a select-list of expiries.
129  $expiryOptions = static::getExpiryOptions( $this->getContext(), $this->watchedItem );
130  return [
131  $this->expiryFormFieldName => [
132  'type' => 'select',
133  'label-message' => 'confirm-watch-label',
134  'options' => $expiryOptions['options'],
135  'default' => $expiryOptions['default'],
136  ]
137  ];
138  }
139 
152  public static function getExpiryOptions( MessageLocalizer $msgLocalizer, $watchedItem ) {
153  $expiryOptions = self::getExpiryOptionsFromMessage( $msgLocalizer );
154  $default = in_array( 'infinite', $expiryOptions )
155  ? 'infinite'
156  : current( $expiryOptions );
157  if ( $watchedItem instanceof WatchedItem && $watchedItem->getExpiry() ) {
158  // If it's already being temporarily watched,
159  // add the existing expiry as the default option in the dropdown.
160  $default = $watchedItem->getExpiry( TS_ISO_8601 );
161  $daysLeft = $watchedItem->getExpiryInDaysText( $msgLocalizer, true );
162  $expiryOptions = array_merge( [ $daysLeft => $default ], $expiryOptions );
163  }
164  return [
165  'options' => $expiryOptions,
166  'default' => $default,
167  ];
168  }
169 
178  private static function getExpiryOptionsFromMessage(
179  MessageLocalizer $msgLocalizer, ?string $lang = null
180  ): array {
181  $expiryOptionsMsg = $msgLocalizer->msg( 'watchlist-expiry-options' );
182  $optionsText = !$lang ? $expiryOptionsMsg->text() : $expiryOptionsMsg->inLanguage( $lang )->text();
184  $optionsText
185  );
186 
187  $expiryOptions = [];
188  foreach ( $options as $label => $value ) {
189  if ( strtotime( $value ) || wfIsInfinity( $value ) ) {
190  $expiryOptions[$label] = $value;
191  }
192  }
193 
194  // If message options is invalid try to recover by returning
195  // english options (T267611)
196  if ( !$expiryOptions && $expiryOptionsMsg->getLanguage()->getCode() !== 'en' ) {
197  return self::getExpiryOptionsFromMessage( $msgLocalizer, 'en' );
198  }
199 
200  return $expiryOptions;
201  }
202 
203  protected function alterForm( HTMLForm $form ) {
204  $msg = $this->watchlistExpiry && $this->watchedItem ? 'updatewatchlist' : 'addwatch';
205  $form->setWrapperLegendMsg( $msg );
206  $submitMsg = $this->watchlistExpiry ? 'confirm-watch-button-expiry' : 'confirm-watch-button';
207  $form->setSubmitTextMsg( $submitMsg );
208  $form->setTokenSalt( 'watch' );
209  }
210 
223  public function onSuccess() {
224  $msgKey = $this->getTitle()->isTalkPage() ? 'addedwatchtext-talk' : 'addedwatchtext';
225  $expiryLabel = null;
226  $submittedExpiry = $this->getContext()->getRequest()->getText( 'wp' . $this->expiryFormFieldName );
227  if ( $submittedExpiry ) {
228  // We can't use $this->watcheditem to get the expiry because it's not been saved at this
229  // point in the request and so its values are those from before saving.
230  $expiry = ExpiryDef::normalizeExpiry( $submittedExpiry, TS_ISO_8601 );
231 
232  // If the expiry label isn't one of the predefined ones in the dropdown, calculate 'x days'.
233  $expiryDays = WatchedItem::calculateExpiryInDays( $expiry );
234  $defaultLabels = static::getExpiryOptions( $this->getContext(), false )['options'];
235  $localizedExpiry = array_search( $submittedExpiry, $defaultLabels );
236  $expiryLabel = $expiryDays && $localizedExpiry === false
237  ? $this->getContext()->msg( 'days', $expiryDays )->text()
238  : $localizedExpiry;
239 
240  // Determine which message to use, depending on whether this is a talk page or not
241  // and whether an expiry was selected.
242  $isTalk = $this->getTitle()->isTalkPage();
243  if ( wfIsInfinity( $expiry ) ) {
244  $msgKey = $isTalk ? 'addedwatchindefinitelytext-talk' : 'addedwatchindefinitelytext';
245  } elseif ( $expiryDays > 0 ) {
246  $msgKey = $isTalk ? 'addedwatchexpirytext-talk' : 'addedwatchexpirytext';
247  } elseif ( $expiryDays < 1 ) {
248  $msgKey = $isTalk ? 'addedwatchexpiryhours-talk' : 'addedwatchexpiryhours';
249  }
250  }
251  $this->getOutput()->addWikiMsg( $msgKey, $this->getTitle()->getPrefixedText(), $expiryLabel );
252  }
253 
254  public function doesWrites() {
255  return true;
256  }
257 }
wfIsInfinity( $str)
Determine input string is represents as infinity.
getContext()
IContextSource null $context
IContextSource if specified; otherwise we'll use the Context from the Page.
Definition: Action.php:62
getTitle()
Shortcut to get the Title object from the page.
Definition: Action.php:209
getContext()
Get the IContextSource in use here.
Definition: Action.php:115
getUser()
Shortcut to get the User being used for this instance.
Definition: Action.php:149
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: Action.php:221
getAuthority()
Shortcut to get the Authority executing this instance.
Definition: Action.php:159
getRequest()
Get the WebRequest being used for this instance.
Definition: Action.php:129
Legacy class representing an editable page and handling UI for some page actions.
Definition: Article.php:61
An action which shows a form and does something based on the input from the form.
Definition: FormAction.php:32
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition: HTMLForm.php:158
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
Definition: HTMLForm.php:1625
setWrapperLegendMsg( $msg)
Prompt the whole form to be wrapped in a "<fieldset>", with this message as its "<legend>" element.
Definition: HTMLForm.php:1834
setTokenSalt( $salt)
Set the salt for the edit token.
Definition: HTMLForm.php:1242
A class containing constants representing the names of configuration variables.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: Status.php:58
internal since 1.36
Definition: User.php:98
isTemp()
Is the user an autocreated temporary user?
Definition: User.php:3574
isAllowed(string $permission, PermissionStatus $status=null)
Checks whether this authority has the given permission in general.
Definition: User.php:2353
isRegistered()
Get whether the user is registered.
Definition: User.php:2296
Redirect a user to the login page.
Page addition to a user's watchlist.
Definition: WatchAction.php:34
getRestriction()
Get the permission required to perform this action.
static getExpiryOptions(MessageLocalizer $msgLocalizer, $watchedItem)
Get options and default for a watchlist expiry select list.
getDescription()
Returns the description that goes below the <h1> element.
Definition: WatchAction.php:81
string $expiryFormFieldName
Definition: WatchAction.php:40
bool $watchlistExpiry
The value of the $wgWatchlistExpiry configuration variable.
Definition: WatchAction.php:37
requiresUnblock()
Whether this action can still be executed by a blocked user.
Definition: WatchAction.php:77
getFormFields()
Get an HTMLForm descriptor array.
usesOOUI()
Whether the form should use OOUI.
__construct(Article $article, IContextSource $context, WatchlistManager $watchlistManager, WatchedItemStore $watchedItemStore)
Only public since 1.21.
Definition: WatchAction.php:55
alterForm(HTMLForm $form)
Play with the HTMLForm if you need to more substantially.
false WatchedItem $watchedItem
Definition: WatchAction.php:43
checkCanExecute(User $user)
Checks if the given user (identified by an object) can perform this action.
Definition: WatchAction.php:98
onSuccess()
Show one of 8 possible success messages.
onSubmit( $data)
Process the form on POST submission.
Definition: WatchAction.php:85
getName()
Return the name of the action this object responds to.
Definition: WatchAction.php:73
Storage layer class for WatchedItems.
getWatchedItem(UserIdentity $user, $target)
Representation of a pair of user and title for watchlist entries.
Definition: WatchedItem.php:38
getExpiryInDaysText(MessageLocalizer $msgLocalizer, $isDropdownOption=false)
Get days remaining until a watched item expires as a text.
getExpiry(?int $style=TS_MW)
When the watched item will expire.
static calculateExpiryInDays(?string $expiry)
Get the number of days remaining until the given expiry time.
Type definition for expiry timestamps.
Definition: ExpiryDef.php:17
static parseOptionsMessage(string $msg)
Parse labels and values out of a comma- and colon-separated list of options, such as is used for expi...
Definition: XmlSelect.php:148
Interface for objects which can provide a MediaWiki context on request.
Interface for localizing messages in MediaWiki.