MediaWiki master
WatchAction.php
Go to the documentation of this file.
1<?php
33
39class WatchAction extends FormAction {
40
43
45 protected $expiryFormFieldName = 'expiry';
46
48 protected $watchedItem = false;
49
50 private WatchlistManager $watchlistManager;
51
60 public function __construct(
61 Article $article,
62 IContextSource $context,
63 WatchlistManager $watchlistManager,
64 WatchedItemStore $watchedItemStore
65 ) {
66 parent::__construct( $article, $context );
67 $this->watchlistExpiry = $this->getContext()->getConfig()->get( MainConfigNames::WatchlistExpiry );
68 if ( $this->watchlistExpiry ) {
69 // The watchedItem is only used in this action's form if $wgWatchlistExpiry is enabled.
70 $this->watchedItem = $watchedItemStore->getWatchedItem(
71 $this->getUser(),
72 $this->getTitle()
73 );
74 }
75 $this->watchlistManager = $watchlistManager;
76 }
77
78 public function getName() {
79 return 'watch';
80 }
81
82 public function requiresUnblock() {
83 return false;
84 }
85
86 protected function getDescription() {
87 return '';
88 }
89
90 public function onSubmit( $data ) {
91 // Even though we're never unwatching here, use WatchlistManager::setWatch()
92 // because it also checks for changed expiry.
93 $result = $this->watchlistManager->setWatch(
94 true,
95 $this->getAuthority(),
96 $this->getTitle(),
97 $this->getRequest()->getVal( 'wp' . $this->expiryFormFieldName )
98 );
99
100 return Status::wrap( $result );
101 }
102
109 protected function checkCanExecute( User $user ) {
110 if ( !$user->isRegistered()
111 || ( $user->isTemp() && !$user->isAllowed( 'editmywatchlist' ) )
112 ) {
113 throw new UserNotLoggedIn( 'watchlistanontext', 'watchnologin' );
114 }
115
116 parent::checkCanExecute( $user );
117 }
118
119 public function getRestriction() {
120 return 'editmywatchlist';
121 }
122
123 protected function usesOOUI() {
124 return true;
125 }
126
127 protected function getFormFields() {
128 // If watchlist expiry is not enabled, return a simple confirmation message.
129 if ( !$this->watchlistExpiry ) {
130 return [
131 'intro' => [
132 'type' => 'info',
133 'raw' => true,
134 'default' => $this->msg( 'confirm-watch-top' )->parse(),
135 ],
136 ];
137 }
138
139 // Otherwise, use a select-list of expiries.
140 $expiryOptions = static::getExpiryOptions( $this->getContext(), $this->watchedItem );
141 return [
142 $this->expiryFormFieldName => [
143 'type' => 'select',
144 'label-message' => 'confirm-watch-label',
145 'options' => $expiryOptions['options'],
146 'default' => $expiryOptions['default'],
147 ]
148 ];
149 }
150
163 public static function getExpiryOptions( MessageLocalizer $msgLocalizer, $watchedItem ) {
164 $expiryOptions = self::getExpiryOptionsFromMessage( $msgLocalizer );
165 $default = in_array( 'infinite', $expiryOptions )
166 ? 'infinite'
167 : current( $expiryOptions );
168 if ( $watchedItem instanceof WatchedItem && $watchedItem->getExpiry() ) {
169 // If it's already being temporarily watched,
170 // add the existing expiry as the default option in the dropdown.
171 $default = $watchedItem->getExpiry( TS_ISO_8601 );
172 $daysLeft = $watchedItem->getExpiryInDaysText( $msgLocalizer, true );
173 $expiryOptions = array_merge( [ $daysLeft => $default ], $expiryOptions );
174 }
175 return [
176 'options' => $expiryOptions,
177 'default' => $default,
178 ];
179 }
180
189 private static function getExpiryOptionsFromMessage(
190 MessageLocalizer $msgLocalizer, ?string $lang = null
191 ): array {
192 $expiryOptionsMsg = $msgLocalizer->msg( 'watchlist-expiry-options' );
193 $optionsText = !$lang ? $expiryOptionsMsg->text() : $expiryOptionsMsg->inLanguage( $lang )->text();
194 $options = XmlSelect::parseOptionsMessage(
195 $optionsText
196 );
197
198 $expiryOptions = [];
199 foreach ( $options as $label => $value ) {
200 if ( strtotime( $value ) || wfIsInfinity( $value ) ) {
201 $expiryOptions[$label] = $value;
202 }
203 }
204
205 // If message options is invalid try to recover by returning
206 // english options (T267611)
207 if ( !$expiryOptions && $expiryOptionsMsg->getLanguage()->getCode() !== 'en' ) {
208 return self::getExpiryOptionsFromMessage( $msgLocalizer, 'en' );
209 }
210
211 return $expiryOptions;
212 }
213
214 protected function alterForm( HTMLForm $form ) {
215 $msg = $this->watchlistExpiry && $this->watchedItem ? 'updatewatchlist' : 'addwatch';
216 $form->setWrapperLegendMsg( $msg );
217 $submitMsg = $this->watchlistExpiry ? 'confirm-watch-button-expiry' : 'confirm-watch-button';
218 $form->setSubmitTextMsg( $submitMsg );
219 $form->setTokenSalt( 'watch' );
220 }
221
234 public function onSuccess() {
235 $msgKey = $this->getTitle()->isTalkPage() ? 'addedwatchtext-talk' : 'addedwatchtext';
236 $expiryLabel = null;
237 $submittedExpiry = $this->getContext()->getRequest()->getText( 'wp' . $this->expiryFormFieldName );
238 if ( $submittedExpiry ) {
239 // We can't use $this->watcheditem to get the expiry because it's not been saved at this
240 // point in the request and so its values are those from before saving.
241 $expiry = ExpiryDef::normalizeExpiry( $submittedExpiry, TS_ISO_8601 );
242
243 // If the expiry label isn't one of the predefined ones in the dropdown, calculate 'x days'.
244 $expiryDays = WatchedItem::calculateExpiryInDays( $expiry );
245 $defaultLabels = static::getExpiryOptions( $this->getContext(), false )['options'];
246 $localizedExpiry = array_search( $submittedExpiry, $defaultLabels );
247 $expiryLabel = $expiryDays && $localizedExpiry === false
248 ? $this->getContext()->msg( 'days', $expiryDays )->text()
249 : $localizedExpiry;
250
251 // Determine which message to use, depending on whether this is a talk page or not
252 // and whether an expiry was selected.
253 $isTalk = $this->getTitle()->isTalkPage();
254 if ( wfIsInfinity( $expiry ) ) {
255 $msgKey = $isTalk ? 'addedwatchindefinitelytext-talk' : 'addedwatchindefinitelytext';
256 } elseif ( $expiryDays > 0 ) {
257 $msgKey = $isTalk ? 'addedwatchexpirytext-talk' : 'addedwatchexpirytext';
258 } elseif ( $expiryDays < 1 ) {
259 $msgKey = $isTalk ? 'addedwatchexpiryhours-talk' : 'addedwatchexpiryhours';
260 }
261 }
262 $this->getOutput()->addWikiMsg( $msgKey, $this->getTitle()->getPrefixedText(), $expiryLabel );
263 }
264
265 public function doesWrites() {
266 return true;
267 }
268}
getUser()
getRequest()
getAuthority()
wfIsInfinity( $str)
Determine input string is represents as infinity.
getContext()
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition Action.php:223
Legacy class representing an editable page and handling UI for some page actions.
Definition Article.php:70
An action which shows a form and does something based on the input from the form.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:206
setWrapperLegendMsg( $msg)
Prompt the whole form to be wrapped in a "<fieldset>", with this message as its "<legend>" element.
setTokenSalt( $salt)
Set the salt for the edit token.
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
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:54
internal since 1.36
Definition User.php:94
isTemp()
Is the user an autocreated temporary user?
Definition User.php:3382
isAllowed(string $permission, PermissionStatus $status=null)
Checks whether this authority has the given permission in general.
Definition User.php:2186
isRegistered()
Get whether the user is registered.
Definition User.php:2129
Storage layer class for WatchedItems.
getWatchedItem(UserIdentity $user, $target)
Representation of a pair of user and title for watchlist entries.
getExpiry(?int $style=TS_MW)
When the watched item will expire.
getExpiryInDaysText(MessageLocalizer $msgLocalizer, $isDropdownOption=false)
Get days remaining until a watched item expires as a text.
Class for generating HTML <select> or <datalist> elements.
Definition XmlSelect.php:30
Redirect a user to the login page.
Page addition to a user's watchlist.
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.
string $expiryFormFieldName
bool $watchlistExpiry
The value of the $wgWatchlistExpiry configuration variable.
requiresUnblock()
Whether this action can still be executed by a blocked user.
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.
alterForm(HTMLForm $form)
Play with the HTMLForm if you need to more substantially.
false WatchedItem $watchedItem
checkCanExecute(User $user)
onSuccess()
Show one of 8 possible success messages.
onSubmit( $data)
Process the form on POST submission.
getName()
Return the name of the action this object responds to.
Type definition for expiry timestamps.
Definition ExpiryDef.php:17
Interface for objects which can provide a MediaWiki context on request.
Interface for localizing messages in MediaWiki.