ApiUserrights.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <?php
  2. /**
  3. * API userrights module
  4. *
  5. * Copyright © 2009 Roan Kattouw "<Firstname>.<Lastname>@gmail.com"
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program; if not, write to the Free Software Foundation, Inc.,
  19. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. * http://www.gnu.org/copyleft/gpl.html
  21. *
  22. * @file
  23. */
  24. /**
  25. * @ingroup API
  26. */
  27. class ApiUserrights extends ApiBase {
  28. private $mUser = null;
  29. /**
  30. * Get a UserrightsPage object, or subclass.
  31. * @return UserrightsPage
  32. */
  33. protected function getUserRightsPage() {
  34. return new UserrightsPage;
  35. }
  36. /**
  37. * Get all available groups.
  38. * @return array
  39. */
  40. protected function getAllGroups() {
  41. return User::getAllGroups();
  42. }
  43. public function execute() {
  44. $pUser = $this->getUser();
  45. // Deny if the user is blocked and doesn't have the full 'userrights' permission.
  46. // This matches what Special:UserRights does for the web UI.
  47. if ( !$this->getPermissionManager()->userHasRight( $pUser, 'userrights' ) ) {
  48. $block = $pUser->getBlock();
  49. if ( $block && $block->isSitewide() ) {
  50. $this->dieBlocked( $block );
  51. }
  52. }
  53. $params = $this->extractRequestParams();
  54. // Figure out expiry times from the input
  55. // $params['expiry'] is not set in CentralAuth's ApiGlobalUserRights subclass
  56. if ( isset( $params['expiry'] ) ) {
  57. $expiry = (array)$params['expiry'];
  58. } else {
  59. $expiry = [ 'infinity' ];
  60. }
  61. $add = (array)$params['add'];
  62. if ( !$add ) {
  63. $expiry = [];
  64. } elseif ( count( $expiry ) !== count( $add ) ) {
  65. if ( count( $expiry ) === 1 ) {
  66. $expiry = array_fill( 0, count( $add ), $expiry[0] );
  67. } else {
  68. $this->dieWithError( [
  69. 'apierror-toofewexpiries',
  70. count( $expiry ),
  71. count( $add )
  72. ] );
  73. }
  74. }
  75. // Validate the expiries
  76. $groupExpiries = [];
  77. foreach ( $expiry as $index => $expiryValue ) {
  78. $group = $add[$index];
  79. $groupExpiries[$group] = UserrightsPage::expiryToTimestamp( $expiryValue );
  80. if ( $groupExpiries[$group] === false ) {
  81. $this->dieWithError( [ 'apierror-invalidexpiry', wfEscapeWikiText( $expiryValue ) ] );
  82. }
  83. // not allowed to have things expiring in the past
  84. if ( $groupExpiries[$group] && $groupExpiries[$group] < wfTimestampNow() ) {
  85. $this->dieWithError( [ 'apierror-pastexpiry', wfEscapeWikiText( $expiryValue ) ] );
  86. }
  87. }
  88. $user = $this->getUrUser( $params );
  89. $tags = $params['tags'];
  90. // Check if user can add tags
  91. if ( $tags !== null ) {
  92. $ableToTag = ChangeTags::canAddTagsAccompanyingChange( $tags, $pUser );
  93. if ( !$ableToTag->isOK() ) {
  94. $this->dieStatus( $ableToTag );
  95. }
  96. }
  97. $form = $this->getUserRightsPage();
  98. $form->setContext( $this->getContext() );
  99. $r = [];
  100. $r['user'] = $user->getName();
  101. $r['userid'] = $user->getId();
  102. list( $r['added'], $r['removed'] ) = $form->doSaveUserGroups(
  103. // Don't pass null to doSaveUserGroups() for array params, cast to empty array
  104. $user, (array)$add, (array)$params['remove'],
  105. $params['reason'], (array)$tags, $groupExpiries
  106. );
  107. $result = $this->getResult();
  108. ApiResult::setIndexedTagName( $r['added'], 'group' );
  109. ApiResult::setIndexedTagName( $r['removed'], 'group' );
  110. $result->addValue( null, $this->getModuleName(), $r );
  111. }
  112. /**
  113. * @param array $params
  114. * @return User
  115. */
  116. private function getUrUser( array $params ) {
  117. if ( $this->mUser !== null ) {
  118. return $this->mUser;
  119. }
  120. $this->requireOnlyOneParameter( $params, 'user', 'userid' );
  121. $user = $params['user'] ?? '#' . $params['userid'];
  122. $form = $this->getUserRightsPage();
  123. $form->setContext( $this->getContext() );
  124. $status = $form->fetchUser( $user );
  125. if ( !$status->isOK() ) {
  126. $this->dieStatus( $status );
  127. }
  128. $this->mUser = $status->value;
  129. return $status->value;
  130. }
  131. public function mustBePosted() {
  132. return true;
  133. }
  134. public function isWriteMode() {
  135. return true;
  136. }
  137. public function getAllowedParams() {
  138. $a = [
  139. 'user' => [
  140. ApiBase::PARAM_TYPE => 'user',
  141. ],
  142. 'userid' => [
  143. ApiBase::PARAM_TYPE => 'integer',
  144. ],
  145. 'add' => [
  146. ApiBase::PARAM_TYPE => $this->getAllGroups(),
  147. ApiBase::PARAM_ISMULTI => true
  148. ],
  149. 'expiry' => [
  150. ApiBase::PARAM_ISMULTI => true,
  151. ApiBase::PARAM_ALLOW_DUPLICATES => true,
  152. ApiBase::PARAM_DFLT => 'infinite',
  153. ],
  154. 'remove' => [
  155. ApiBase::PARAM_TYPE => $this->getAllGroups(),
  156. ApiBase::PARAM_ISMULTI => true
  157. ],
  158. 'reason' => [
  159. ApiBase::PARAM_DFLT => ''
  160. ],
  161. 'token' => [
  162. // Standard definition automatically inserted
  163. ApiBase::PARAM_HELP_MSG_APPEND => [ 'api-help-param-token-webui' ],
  164. ],
  165. 'tags' => [
  166. ApiBase::PARAM_TYPE => 'tags',
  167. ApiBase::PARAM_ISMULTI => true
  168. ],
  169. ];
  170. // CentralAuth's ApiGlobalUserRights subclass can't handle expiries
  171. if ( !$this->getUserRightsPage()->canProcessExpiries() ) {
  172. unset( $a['expiry'] );
  173. }
  174. return $a;
  175. }
  176. public function needsToken() {
  177. return 'userrights';
  178. }
  179. protected function getWebUITokenSalt( array $params ) {
  180. return $this->getUrUser( $params )->getName();
  181. }
  182. protected function getExamplesMessages() {
  183. $a = [
  184. 'action=userrights&user=FooBot&add=bot&remove=sysop|bureaucrat&token=123ABC'
  185. => 'apihelp-userrights-example-user',
  186. 'action=userrights&userid=123&add=bot&remove=sysop|bureaucrat&token=123ABC'
  187. => 'apihelp-userrights-example-userid',
  188. ];
  189. if ( $this->getUserRightsPage()->canProcessExpiries() ) {
  190. $a['action=userrights&user=SometimeSysop&add=sysop&expiry=1%20month&token=123ABC']
  191. = 'apihelp-userrights-example-expiry';
  192. }
  193. return $a;
  194. }
  195. public function getHelpUrls() {
  196. return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:User_group_membership';
  197. }
  198. }