diff options
Diffstat (limited to 'bin/reevotech/vendor/addwiki/mediawiki-api-base')
45 files changed, 4181 insertions, 0 deletions
diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/.gitignore b/bin/reevotech/vendor/addwiki/mediawiki-api-base/.gitignore new file mode 100644 index 00000000..9c16bff2 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/.gitignore @@ -0,0 +1,6 @@ +.idea +vendor +composer.lock +test.php +docs/_build +phpunit.xml diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/.phan/config.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/.phan/config.php new file mode 100644 index 00000000..28c1f4ad --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/.phan/config.php @@ -0,0 +1,40 @@ +<?php + +/** + * This configuration will be read and overlaid on top of the + * default configuration. Command line arguments will be applied + * after this file is read. + */ +return [ + + /** + * A list of directories that should be parsed for class and + * method information. After excluding the directories + * defined in exclude_analysis_directory_list, the remaining + * files will be statically analyzed for errors. + * + * Thus, both first-party and third-party code being used by + * your application should be included in this list. + */ + 'directory_list' => [ + 'src', + 'vendor', + ], + + /** + * A directory list that defines files that will be excluded + * from static analysis, but whose class and method + * information should be included. + * + * Generally, you'll want to include the directories for + * third-party code (such as "vendor/") in this list. + * + * n.b.: If you'd like to parse but not analyze 3rd + * party code, directories containing that code + * should be added to the `directory_list` as + * to `exclude_analysis_directory_list`. + */ + "exclude_analysis_directory_list" => [ + 'vendor/' + ], +]; diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/.scrutinizer.yml b/bin/reevotech/vendor/addwiki/mediawiki-api-base/.scrutinizer.yml new file mode 100644 index 00000000..ffc976e3 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/.scrutinizer.yml @@ -0,0 +1,13 @@ +inherit: true + +tools: + php_code_sniffer: true + php_cpd: true + php_cs_fixer: true + php_loc: true + php_mess_detector: true + php_pdepend: true + php_analyzer: true + sensiolabs_security_checker: true + external_code_coverage: + timeout: 300
\ No newline at end of file diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/.travis.yml b/bin/reevotech/vendor/addwiki/mediawiki-api-base/.travis.yml new file mode 100644 index 00000000..cb3e7641 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/.travis.yml @@ -0,0 +1,61 @@ +language: php + +php: + - hhvm + - 5.5 + - 5.6 + - 7.0 + - 7.1 + +env: + - MW=master + +matrix: + include: + - php: 7.1 + env: MW=REL1_28 + - php: 7.1 + env: MW=REL1_27 + - php: 7.1 + env: MW=REL1_26 + - php: 7.1 + env: MW=REL1_25 + - php: 7.1 + env: MW=REL1_24 + allow_failures: + - env: MW=REL1_24 + +addons: + mariadb: '10.0' + +before_install: + - bash ./build/travis/install-mediawiki.sh + +install: + - travis_retry composer install + +before_script: + - bash ./build/travis/run-webserver.sh + - export ADDWIKI_MW_API='http://localhost:8080/w/api.php' + - export ADDWIKI_MW_USER='CIUser' + - export ADDWIKI_MW_PASSWORD='CIPass' + +script: + - composer lint + - composer phpcs + - composer phpunit-coverage + +after_success: + - travis_retry wget https://scrutinizer-ci.com/ocular.phar + - php ocular.phar code-coverage:upload --format=php-clover coverage.clover + +cache: + directories: + - $HOME/.composer/cache + +notifications: + irc: + channels: + - "chat.freenode.net##add" + on_success: change + on_failure: always diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/LICENSE.md b/bin/reevotech/vendor/addwiki/mediawiki-api-base/LICENSE.md new file mode 100644 index 00000000..0671f06a --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/LICENSE.md @@ -0,0 +1,264 @@ +The GNU General Public License, Version 2, June 1991 (GPLv2) +============================================================ + +> Copyright (C) 1989, 1991 Free Software Foundation, Inc. +> 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + + +Preamble +-------- + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public License is intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. This General Public License applies to most +of the Free Software Foundation's software and to any other program whose +authors commit to using it. (Some other Free Software Foundation software is +covered by the GNU Library General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom to +distribute copies of free software (and charge for this service if you wish), +that you receive source code or can get it if you want it, that you can change +the software or use pieces of it in new free programs; and that you know you can +do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny +you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of the +software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for a +fee, you must give the recipients all the rights that you have. You must make +sure that they, too, receive or can get the source code. And you must show them +these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) offer +you this license which gives you legal permission to copy, distribute and/or +modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If the +software is modified by someone else and passed on, we want its recipients to +know that what they have is not the original, so that any problems introduced by +others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We wish +to avoid the danger that redistributors of a free program will individually +obtain patent licenses, in effect making the program proprietary. To prevent +this, we have made it clear that any patent must be licensed for everyone's free +use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + + +Terms And Conditions For Copying, Distribution And Modification +--------------------------------------------------------------- + +**0.** This License applies to any program or other work which contains a notice +placed by the copyright holder saying it may be distributed under the terms of +this General Public License. The "Program", below, refers to any such program or +work, and a "work based on the Program" means either the Program or any +derivative work under copyright law: that is to say, a work containing the +Program or a portion of it, either verbatim or with modifications and/or +translated into another language. (Hereinafter, translation is included without +limitation in the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered by +this License; they are outside its scope. The act of running the Program is not +restricted, and the output from the Program is covered only if its contents +constitute a work based on the Program (independent of having been made by +running the Program). Whether that is true depends on what the Program does. + +**1.** You may copy and distribute verbatim copies of the Program's source code +as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this License +and to the absence of any warranty; and give any other recipients of the Program +a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may at +your option offer warranty protection in exchange for a fee. + +**2.** You may modify your copy or copies of the Program or any portion of it, +thus forming a work based on the Program, and copy and distribute such +modifications or work under the terms of Section 1 above, provided that you also +meet all of these conditions: + +* **a)** You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change. + +* **b)** You must cause any work that you distribute or publish, that in whole + or in part contains or is derived from the Program or any part thereof, to + be licensed as a whole at no charge to all third parties under the terms of + this License. + +* **c)** If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive use in the + most ordinary way, to print or display an announcement including an + appropriate copyright notice and a notice that there is no warranty (or + else, saying that you provide a warranty) and that users may redistribute + the program under these conditions, and telling the user how to view a copy + of this License. (Exception: if the Program itself is interactive but does + not normally print such an announcement, your work based on the Program is + not required to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be reasonably +considered independent and separate works in themselves, then this License, and +its terms, do not apply to those sections when you distribute them as separate +works. But when you distribute the same sections as part of a whole which is a +work based on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the entire whole, +and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise the +right to control the distribution of derivative or collective works based on the +Program. + +In addition, mere aggregation of another work not based on the Program with the +Program (or with a work based on the Program) on a volume of a storage or +distribution medium does not bring the other work under the scope of this +License. + +**3.** You may copy and distribute the Program (or a work based on it, under +Section 2) in object code or executable form under the terms of Sections 1 and 2 +above provided that you also do one of the following: + +* **a)** Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 above on + a medium customarily used for software interchange; or, + +* **b)** Accompany it with a written offer, valid for at least three years, to + give any third party, for a charge no more than your cost of physically + performing source distribution, a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of Sections 1 + and 2 above on a medium customarily used for software interchange; or, + +* **c)** Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed only for + noncommercial distribution and only if you received the program in object + code or executable form with such an offer, in accord with Subsection b + above.) + +The source code for a work means the preferred form of the work for making +modifications to it. For an executable work, complete source code means all the +source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and installation +of the executable. However, as a special exception, the source code distributed +need not include anything that is normally distributed (in either source or +binary form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component itself +accompanies the executable. + +If distribution of executable or object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the source code +from the same place counts as distribution of the source code, even though third +parties are not compelled to copy the source along with the object code. + +**4.** You may not copy, modify, sublicense, or distribute the Program except as +expressly provided under this License. Any attempt otherwise to copy, modify, +sublicense or distribute the Program is void, and will automatically terminate +your rights under this License. However, parties who have received copies, or +rights, from you under this License will not have their licenses terminated so +long as such parties remain in full compliance. + +**5.** You are not required to accept this License, since you have not signed +it. However, nothing else grants you permission to modify or distribute the +Program or its derivative works. These actions are prohibited by law if you do +not accept this License. Therefore, by modifying or distributing the Program (or +any work based on the Program), you indicate your acceptance of this License to +do so, and all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +**6.** Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the original +licensor to copy, distribute or modify the Program subject to these terms and +conditions. You may not impose any further restrictions on the recipients' +exercise of the rights granted herein. You are not responsible for enforcing +compliance by third parties to this License. + +**7.** If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), conditions +are imposed on you (whether by court order, agreement or otherwise) that +contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot distribute so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not distribute the Program at all. +For example, if a patent license would not permit royalty-free redistribution of +the Program by all those who receive copies directly or indirectly through you, +then the only way you could satisfy both it and this License would be to refrain +entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply and the +section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or +other property right claims or to contest validity of any such claims; this +section has the sole purpose of protecting the integrity of the free software +distribution system, which is implemented by public license practices. Many +people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose that +choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +**8.** If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original copyright +holder who places the Program under this License may add an explicit +geographical distribution limitation excluding those countries, so that +distribution is permitted only in or among countries not thus excluded. In such +case, this License incorporates the limitation as if written in the body of this +License. + +**9.** The Free Software Foundation may publish revised and/or new versions of +the General Public License from time to time. Such new versions will be similar +in spirit to the present version, but may differ in detail to address new +problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies +a version number of this License which applies to it and "any later version", +you have the option of following the terms and conditions either of that version +or of any later version published by the Free Software Foundation. If the +Program does not specify a version number of this License, you may choose any +version ever published by the Free Software Foundation. + +**10.** If you wish to incorporate parts of the Program into other free programs +whose distribution conditions are different, write to the author to ask for +permission. For software which is copyrighted by the Free Software Foundation, +write to the Free Software Foundation; we sometimes make exceptions for this. +Our decision will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse of +software generally. + + +No Warranty +----------- + +**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR +INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA +BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER +OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/README.md b/bin/reevotech/vendor/addwiki/mediawiki-api-base/README.md new file mode 100644 index 00000000..ea2a7d4b --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/README.md @@ -0,0 +1,16 @@ +# mediawiki-api-base + +[![Build Status](https://travis-ci.org/addwiki/mediawiki-api-base.svg?branch=master)](https://travis-ci.org/addwiki/mediawiki-api-base) +[![Code Coverage](https://scrutinizer-ci.com/g/addwiki/mediawiki-api-base/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/addwiki/mediawiki-api-base/?branch=master) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/addwiki/mediawiki-api-base/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/addwiki/mediawiki-api-base/?branch=master) +[![Dependency Status](https://www.versioneye.com/php/addwiki:mediawiki-api-base/badge?style=flat-square)](https://www.versioneye.com/php/addwiki:mediawiki-api-base) + +[![Tested Against](http://php-eye.com/badge/addwiki/mediawiki-api-base/tested.svg)](https://php-eye.com/package/addwiki/mediawiki-api-base) + +[![Latest Stable Version](https://poser.pugx.org/addwiki/mediawiki-api-base/version.png)](https://packagist.org/packages/addwiki/mediawiki-api-base) +[![Download count](https://poser.pugx.org/addwiki/mediawiki-api-base/d/total.png)](https://packagist.org/packages/addwiki/mediawiki-api-base) +[![Reference Status](https://www.versioneye.com/php/addwiki:mediawiki-api-base/reference_badge.svg?style=flat-square)](https://www.versioneye.com/php/addwiki:mediawiki-api-base/references) + +Issue tracker: https://phabricator.wikimedia.org/project/profile/1490/ + +Documentation: https://addwiki.readthedocs.io
\ No newline at end of file diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/RELEASENOTES.md b/bin/reevotech/vendor/addwiki/mediawiki-api-base/RELEASENOTES.md new file mode 100644 index 00000000..a84b19cc --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/RELEASENOTES.md @@ -0,0 +1,95 @@ +These are the release notes for the [mediawiki-api-base](README.md) library. + +## Version 2.4.0 (2 November 2017) +* New MultipartRequest class added. PR [#38](https://github.com/addwiki/mediawiki-api-base/pull/38). + +## Version 2.3.1 (3 May 2017) +* Don't fail on libxml errors if the RSD URL can still be found. PR [#35](https://github.com/addwiki/mediawiki-api-base/pull/35), Fixes [T163527](https://phabricator.wikimedia.org/T163527). + +## Version 2.3.0 (27 April 2017) + +* All guzzle configuration settings can now be overridden in `ClientFactory`. [#27](https://github.com/addwiki/mediawiki-api-base/pull/27) +* Requests that fail due to maxlag will be automatically retried. [#28](https://github.com/addwiki/mediawiki-api-base/pull/28). Fixes [T143193](https://phabricator.wikimedia.org/T143193). +* Added `MediawikiApi::getApiUrl`. [#24](https://github.com/addwiki/mediawiki-api-base/pull/24) +* Debugging infomation now logged when login fails. [#26](https://github.com/addwiki/mediawiki-api-base/pull/26) +* UsageException messages now include the error code and result the API returned. [#31](https://github.com/addwiki/mediawiki-api-base/pull/31) +* Both formatversion=2 and old style API results supported [#33](https://github.com/addwiki/mediawiki-api-base/pull/33) +* Fix [MediawikiApi::newFromPage() fails on non-XML HTML](https://phabricator.wikimedia.org/T163527). [#34](https://github.com/addwiki/mediawiki-api-base/pull/34) +* Various CI improvements. + +## Version 2.2.1 (3 August 2016) + +* Cast SimpleXMLElements attributes as string in `MediawikiApi::newFromPage()` + +## Version 2.2.0 (18 January 2016) + +* Added `MediawikiApiInterface`, now implemented by `MediawikiApi` +* Added `ApiRequester`, now implemented by `MediawikiApi` +* Added `AsyncApiRequester`, now implemented by `MediawikiApi` +* The constructor of `MediawikiApi` was made package public + +## Version 2.1.0 (29 December 2015) + +* Retry throttled actions that return a failed-save code and anti-abuse message +* Added delay between retried requests +* Added and used `Guzzle/ClientFactory` + +## Version 2.0.0 (18 December 2015) + +* Added `MediawikiApi::newFromApiEndpoint` and `MediawikiApi::newFromPage` +* MediawikiApi constructor access marked as private (please use static factory methods) +* Added async methods to MediawikiApi `getRequestAsync` & `postRequestAsync` +* Requires "guzzlehttp/guzzle": "~6.0" ( From "guzzle/guzzle": "~5.2" ) +* Requires "guzzlehttp/promises": "~1.0" + +## Version 1.1.1 (20 July 2016) + +* Issue with README fixed + +## Version 1.1.0 (5 September 2015) + +* Requests that encounter a connection exception are now retried +* Requests that result in non blocking mediawiki api error codes are now retried (ratelimited, readonly, internal_api_error_DBQueryError) +* MediawikiApi now implements PSR-3 LoggerAwareInterface +* MediawikiSession now implements PSR-3 LoggerAwareInterface +* MediawikiApi no longer raises PHP warnings, instead it logs warnings + +## Version 1.0.0 (23 August 2015) + +* Added `FluentRequest` object +* Requires "guzzlehttp/retry-subscriber": "~2.0" + +## Version 0.3 (1 June 2015) + +* UsageExceptions can now contain the full api result array +* No longer uses addwiki/guzzle-mediawiki-client +* Now using "guzzlehttp/guzzle": "~5.0" ( From "guzzle/guzzle": "~3.2" ) +* Added getHeaders method to Request interface +* ApiUser now accepts a domain + +## Version 0.2 (13 January 2015) + +### Compatibility changes + +* Session objects now use action=query&meta=tokens to get tokens when possible. +NOTE: [Token names have changed between versions](//www.mediawiki.org/wiki/API:Tokens) + +### Deprecations + +* MediawikiApi getAction and postAction methods have been deprecated in favour of getRequest and postRequest + +### New features + +* If warnings are present in API results E_USER_WARNING errors are triggered +* The Request interface and SimpleRequest class have been added +* MediawikiApi now has a getRequest and postRequest method +* MediawikiApi now has a getVersion method +* Unsuccessful logins now throw a UsageException with extra details + +## Version 0.1.2 (25 May 2014) + +* Fix issue where API tokens were not returned + +## Version 0.1 (12 May 2014) + +* Initial release after split from mediawiki-api lib diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/build/travis/install-mediawiki.sh b/bin/reevotech/vendor/addwiki/mediawiki-api-base/build/travis/install-mediawiki.sh new file mode 100644 index 00000000..59d29ba4 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/build/travis/install-mediawiki.sh @@ -0,0 +1,29 @@ +#! /bin/bash + +set -x + +originalDirectory=$(pwd) + +if [[ $TRAVIS_PHP_VERSION == *"hhvm"* ]] +then + PHPINI=/etc/hhvm/php.ini + echo "hhvm.enable_zend_compat = true" >> $PHPINI +fi + +mkdir ./../web +cd ./../web + +wget https://github.com/wikimedia/mediawiki/archive/$MW.tar.gz +tar -zxf $MW.tar.gz +mv mediawiki-$MW w +ln -s ./w ./wiki + +cd w + +composer self-update +composer install + +mysql -e 'CREATE DATABASE mediawiki;' +php maintenance/install.php --dbtype mysql --dbuser root --dbname mediawiki --dbpath $(pwd) --pass CIPass TravisWiki CIUser + +cd $originalDirectory diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/build/travis/run-webserver.sh b/bin/reevotech/vendor/addwiki/mediawiki-api-base/build/travis/run-webserver.sh new file mode 100644 index 00000000..2412031c --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/build/travis/run-webserver.sh @@ -0,0 +1,25 @@ +#! /bin/bash + +set -x + +# HHVM doesn't have a built in web server +# We can't guarantee any single PHP version is always installed on Travis hosts +# So list the versions and try to pick the latest PHP version +# Also the web server on 7.1 seems to have issues, so don't use that? +if [[ $TRAVIS_PHP_VERSION == *"hhvm"* ]] || [[ $TRAVIS_PHP_VERSION == *"7.1"* ]] +then + WEBSERVERPHPVERSION=`phpenv versions | grep -v system | grep -v hhvm | grep -v 7.1 | tail -n 1 | xargs` + phpenv global $WEBSERVERPHPVERSION + php --version +fi + +# Run a web server for MediaWiki and wait until it is up +nohup php -S 0.0.0.0:8080 -t ./../web > /dev/null 2>&1 & +until curl -s localhost:8080; do true; done > /dev/null 2>&1 + +# Switch back to the actual php version requested for this build if needed +if [ -v $WEBSERVERPHPVERSION ] +then + phpenv global $TRAVIS_PHP_VERSION + php --version +fi diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/composer.json b/bin/reevotech/vendor/addwiki/mediawiki-api-base/composer.json new file mode 100644 index 00000000..c83fca09 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/composer.json @@ -0,0 +1,52 @@ +{ + "name": "addwiki/mediawiki-api-base", + "type": "library", + "description": "A basic Mediawiki api base library", + "keywords": ["Mediawiki"], + "license": "GPL-2.0+", + "authors": [ + { "name": "Addshore" } + ], + "require": { + "php": ">=5.5", + "guzzlehttp/guzzle": "~6.0", + "guzzlehttp/promises": "~1.0", + "psr/log": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8.0|~5.3.0", + "jakub-onderka/php-parallel-lint": "0.9.2", + "mediawiki/mediawiki-codesniffer": "^13.0" + }, + "suggest": { + "etsy/phan": "Allows running static analysis on the package (requires PHP 7+)" + }, + "scripts": { + "lint": "parallel-lint . --exclude vendor", + "phpunit": "phpunit", + "phpunit-unit": "phpunit --testsuite unit", + "phpunit-integration": "phpunit --testsuite integration", + "phpunit-coverage": "phpunit --coverage-clover=coverage.clover", + "phpcs": "phpcs -ps", + "test": [ + "@lint", + "@phpcs", + "@phpunit" + ] + }, + "autoload": { + "psr-4": { + "Mediawiki\\Api\\": "src/" + } + }, + "autoload-dev": { + "files": [ + "tests/Integration/TestEnvironment.php" + ] + }, + "extra": { + "branch-alias": { + "dev-master": "2.4.x-dev" + } + } +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/Makefile b/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/Makefile new file mode 100644 index 00000000..54002b3b --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/Makefile @@ -0,0 +1,225 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help +help: + @echo "Please use \`make <target>' where <target> is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/mediawiki-api-base.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/mediawiki-api-base.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/mediawiki-api-base" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/mediawiki-api-base" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/conf.py b/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/conf.py new file mode 100644 index 00000000..cb3ce592 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/conf.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + +import sys, os +from sphinx.highlighting import lexers +from pygments.lexers.web import PhpLexer + +lexers['php'] = PhpLexer(startinline=True, linenos=1) +lexers['php-annotations'] = PhpLexer(startinline=True, linenos=1) +primary_domain = 'php' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'mediawiki-api-base' +copyright = '2016, addwiki' +author = 'addwiki' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '2.2' +# The full version, including alpha/beta/rc tags. +release = '2.2.1' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'default' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Output file base name for HTML help builder. +htmlhelp_basename = 'mediawiki-api-basedoc' diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/index.rst b/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/index.rst new file mode 100644 index 00000000..ac4860ce --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/index.rst @@ -0,0 +1,17 @@ +Welcome to mediawiki-api-base's documentation! +============================================== + +.. toctree:: + :maxdepth: 3 + + overview + quickstart + multipart + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/make.bat b/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/make.bat new file mode 100644 index 00000000..7ce5e397 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/make.bat @@ -0,0 +1,281 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^<target^>` where ^<target^> is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. epub3 to make an epub3 + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + echo. coverage to run coverage check of the documentation if enabled + echo. dummy to check syntax errors of document sources + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +REM Check if sphinx-build is available and fallback to Python version if any +%SPHINXBUILD% 1>NUL 2>NUL +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +:sphinx_ok + + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\mediawiki-api-base.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\mediawiki-api-base.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "epub3" ( + %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "coverage" ( + %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage + if errorlevel 1 exit /b 1 + echo. + echo.Testing of coverage in the sources finished, look at the ^ +results in %BUILDDIR%/coverage/python.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +if "%1" == "dummy" ( + %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. Dummy builder generates no files. + goto end +) + +:end diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/multipart.rst b/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/multipart.rst new file mode 100644 index 00000000..1b438c71 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/multipart.rst @@ -0,0 +1,28 @@ +================== +Multipart requests +================== + +The MultipartRequest class can be used if you need a FluentRequest that has more parameters to be set on individual parts of a multipart request. + +The name is a slight misnomer, because either of the other two Request classes (SimpleRequest and FluentRequest) +will also end up being multipart requests if you pass any parameters of type Resource_. + +.. _Resource: http://php.net/manual/en/resource.php + +To use a MultipartRequest you must first set the main parameters, and then you can add additional "multipart parameters" to any of the parameters you've set. +(You will get an Exception if you try to set a multipart parameter for a main parameter that doesn't exist yet.) + +For example, to add a ``Content-Disposition`` header to a parameter named ``param1``:: + + $contentDisposition = 'form-data; name="param1"; filename="a_filename.png"'; + $request = MultipartRequest::factory() + ->setParams( [ 'param1' => 'Lorem ipsum' ] ) + ->setAction( 'actionname' ) + ->setMultipartParams( [ + 'param1' => [ + 'headers' => [ 'Content-Disposition' => $contentDisposition ], + ], + ] ); + $response = $api->postRequest( $request ); + +(For details of creating the ``$api`` object in this example, see :ref:`quickstart`.) diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/overview.rst b/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/overview.rst new file mode 100644 index 00000000..0e83549d --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/overview.rst @@ -0,0 +1,129 @@ +======== +Overview +======== + +addwiki/mediawiki-api-base is a PHP HTTP client wrapped around guzzle that makes it easy to interest with a mediawiki installation. + +#. Uses PSR-3 interfaces for logging +#. Handles Mediawiki login, sessions, cookies and tokens +#. Handles response errors by throwing catchable UsageExceptions +#. Retries failed requests where possible +#. Allows Async requests + +Requirements +======================== + +#. PHP 5.5.0 +#. Guzzle HTTP library ~6.0 + +.. _installation: + +Installation +======================== + +The recommended way to install this library is with +`Composer <http://getcomposer.org>`_. Composer is a dependency management tool +for PHP that allows you to declare the dependencies your project needs and +installs them into your project. + +.. code-block:: bash + + # Install Composer + curl -sS https://getcomposer.org/installer | php + +You can add addwiki/mediawiki-api-base as a dependency using the composer.phar CLI: + +.. code-block:: bash + + php composer.phar require addwiki/mediawiki-api-base:~2.0 + +Alternatively, you can specify addwiki/mediawiki-api-base as a dependency in your project's +existing composer.json file: + +.. code-block:: js + + { + "require": { + "addwiki/mediawiki-api-base": "~2.0" + } + } + +After installing, you need to require Composer's autoloader: + +.. code-block:: php + + require 'vendor/autoload.php'; + +You can find out more on how to install Composer, configure autoloading, and +other best-practices for defining dependencies at `getcomposer.org <http://getcomposer.org>`_. + + +Bleeding edge +-------------------------- + +During your development, you can keep up with the latest changes on the master +branch by setting the version requirement for addwiki/mediawiki-api-base to ``~2.0@dev``. + +.. code-block:: js + + { + "require": { + "addwiki/mediawiki-api-base": "~2.0@dev" + } + } + + +License +=================== + +Licensed using the `GPL-2.0+ <https://opensource.org/licenses/GPL-2.0>`_. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +Contributing +======================== + +Running the tests +----------------- + +In order to contribute, you'll need to checkout the source from GitHub and +install the dependencies using Composer: + +.. code-block:: bash + + git clone https://github.com/addwiki/mediawiki-api-base.git + cd mediawiki-api-base + curl -s http://getcomposer.org/installer | php + ./composer.phar install --dev + +The library is tested with a combination of linters and phpunit. Run all of the tests as follows: + +.. code-block:: bash + + ./composer.phar test + +You can choose to run each part of the whole test suite individually using the following commands: + +.. code-block:: bash + + # Run the linting only + ./composer.phar lint + # Run phpunit only + ./composer.phar phpunit + # Run only the phpunit unit tests + ./composer.phar phpunit-unit + # Run only the phpunit integration tests + ./composer.phar phpunit-integration
\ No newline at end of file diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/quickstart.rst b/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/quickstart.rst new file mode 100644 index 00000000..5db0601f --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/docs/quickstart.rst @@ -0,0 +1,87 @@ +.. _quickstart: + +========== +Quickstart +========== + +This page provides a quick introduction to this library and introductory examples. +If you have not already installed the library head over to the :ref:`installation` +page. + +Getting an API object +---------------------------------- + +You can get an api object by simply passing the api endpoint: + +.. code-block:: php + + use \Mediawiki\Api\MediawikiApi; + + $api = MediawikiApi::newFromApiEndpoint( 'https://en.wikipedia.org/w/api.php' ); + +You can even just pass a page: + +.. code-block:: php + + use \Mediawiki\Api\MediawikiApi; + + $api = MediawikiApi::newFromPage( 'https://en.wikipedia.org/wiki/Berlin' ); + +Logging in and out +---------------------------------- + +.. code-block:: php + + use \MediawikiApi\Api\ApiUser; + + $api->login( new ApiUser( 'username', 'password' ) ); + $api->logout(); + +Making request objects +---------------------------------- + +The library provides two different way of constructing requests. + +.. code-block:: php + + use Mediawiki\Api\SimpleRequest; + use Mediawiki\Api\FluentRequest; + + $purgeRequest = new SimpleRequest( 'purge', array( 'titles' => 'Berlin' ) ); + // or + $purgeRequest = FluentRequest::factory()->setAction( 'purge' )->setParam( 'titles', 'Berlin' ) ); + +Sending requests +---------------------------------- + +.. code-block:: php + + $api->postRequest( $purgeRequest ); + + $queryResponse = $api->getRequest( FluentRequest::factory()->setAction( 'query' )->setParam( 'meta', 'siteinfo' ) ); + + try{ + $api->postRequest( new SimpleRequest( 'FooBarBaz' ) ); + } + catch ( UsageException $e ) { + echo "The api returned an error!"; + } + + +Making async requests +---------------------------------- + +.. code-block:: php + + // Initiate each request but do not block + $requestPromises = array( + 'Page1' => $api->postRequestAsync( FluentRequest::factory()->setAction( 'purge' )->setParam( 'titles', 'Page1' ) ), + 'Page2' => $api->postRequestAsync( FluentRequest::factory()->setAction( 'purge' )->setParam( 'titles', 'Page2' ) ), + 'Page3' => $api->postRequestAsync( FluentRequest::factory()->setAction( 'purge' )->setParam( 'titles', 'Page3' ) ), + ); + + // Wait on all of the requests to complete. + $results = GuzzleHttp\Promise\unwrap( $requestPromises ); + + // You can access each result using the key provided to the unwrap function. + print_r( $results['Page1'], $results['Page2'], $results['Page3'] ) diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/phpcs.xml b/bin/reevotech/vendor/addwiki/mediawiki-api-base/phpcs.xml new file mode 100755 index 00000000..c4ca4081 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/phpcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0"?> +<ruleset name="MediaWiki"> + <rule ref="vendor/mediawiki/mediawiki-codesniffer/MediaWiki"/> + <file>.</file> + <exclude-pattern>vendor/</exclude-pattern> +</ruleset> diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/phpunit.xml.dist b/bin/reevotech/vendor/addwiki/mediawiki-api-base/phpunit.xml.dist new file mode 100644 index 00000000..a5874032 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/phpunit.xml.dist @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<phpunit colors="true"> + <testsuites> + <testsuite name="unit"> + <directory suffix="Test.php">./tests/Unit</directory> + </testsuite> + <testsuite name="integration"> + <directory suffix="Test.php">./tests/Integration</directory> + </testsuite> + </testsuites> + <filter> + <whitelist addUncoveredFilesFromWhitelist="true"> + <directory suffix=".php">./src</directory> + </whitelist> + </filter> +</phpunit>
\ No newline at end of file diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/ApiRequester.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/ApiRequester.php new file mode 100644 index 00000000..cc3c8bcf --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/ApiRequester.php @@ -0,0 +1,31 @@ +<?php + +namespace Mediawiki\Api; + +/** + * @since 2.2 + * @licence GNU GPL v2+ + * @author Addshore + * @author Jeroen De Dauw < jeroendedauw@gmail.com > + */ +interface ApiRequester { + + /** + * @since 2.2 + * + * @param Request $request The GET request to send. + * + * @return mixed Normally an array + */ + public function getRequest( Request $request ); + + /** + * @since 2.2 + * + * @param Request $request The POST request to send. + * + * @return mixed Normally an array + */ + public function postRequest( Request $request ); + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/ApiUser.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/ApiUser.php new file mode 100644 index 00000000..b2f59153 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/ApiUser.php @@ -0,0 +1,90 @@ +<?php + +namespace Mediawiki\Api; + +use InvalidArgumentException; + +/** + * @since 0.1 + * + * @author Addshore + * @author RobinR1 + * @author Bene + * + * Represents a user that can log in to the api + */ +class ApiUser { + + /** + * @var string + */ + private $password; + + /** + * @var string + */ + private $username; + + /** + * @var string + */ + private $domain; + + /** + * @param string $username The username. + * @param string $password The user's password. + * @param string|null $domain The domain (for authentication systems that support domains). + * + * @throws \InvalidArgumentException + */ + public function __construct( $username, $password, $domain = null ) { + $domainIsStringOrNull = ( is_string( $domain ) || is_null( $domain ) ); + if ( !is_string( $username ) || !is_string( $password ) || !$domainIsStringOrNull ) { + throw new InvalidArgumentException( 'Username, Password and Domain must all be strings' ); + } + if ( empty( $username ) || empty( $password ) ) { + throw new InvalidArgumentException( 'Username and Password are not allowed to be empty' ); + } + $this->username = $username; + $this->password = $password; + $this->domain = $domain; + } + + /** + * @since 0.1 + * @return string + */ + public function getUsername() { + return $this->username; + } + + /** + * @since 0.1 + * @return string + */ + public function getPassword() { + return $this->password; + } + + /** + * @since 0.1 + * @return string + */ + public function getDomain() { + return $this->domain; + } + + /** + * @since 0.1 + * @param mixed $other Another ApiUser object to compare with. + * + * @return bool + */ + public function equals( $other ) { + return $other instanceof self + && $this->username == $other->getUsername() + && $this->password == $other->getPassword() + && $this->domain == $other->getDomain(); + } + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/AsyncApiRequester.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/AsyncApiRequester.php new file mode 100644 index 00000000..6190ac7e --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/AsyncApiRequester.php @@ -0,0 +1,37 @@ +<?php + +namespace Mediawiki\Api; + +use GuzzleHttp\Promise\PromiseInterface; + +/** + * @since 2.2 + * @licence GNU GPL v2+ + * @author Addshore + * @author Jeroen De Dauw < jeroendedauw@gmail.com > + */ +interface AsyncApiRequester { + + /** + * @since 2.2 + * + * @param Request $request The GET request to send. + * + * @return PromiseInterface + * Normally promising an array, though can be mixed (json_decode result) + * Can throw UsageExceptions or RejectionExceptions + */ + public function getRequestAsync( Request $request ); + + /** + * @since 2.2 + * + * @param Request $request The POST request to send. + * + * @return PromiseInterface + * Normally promising an array, though can be mixed (json_decode result) + * Can throw UsageExceptions or RejectionExceptions + */ + public function postRequestAsync( Request $request ); + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/FluentRequest.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/FluentRequest.php new file mode 100644 index 00000000..0d10553b --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/FluentRequest.php @@ -0,0 +1,118 @@ +<?php + +namespace Mediawiki\Api; + +/** + * @since 1.0 + * + * @author Addshore + */ +class FluentRequest implements Request { + + /** + * @var array + */ + private $params = []; + + /** + * @var array + */ + private $headers = []; + + /** + * @since 1.0 + * + * @return array + */ + public function getParams() { + return $this->params; + } + + /** + * @since 1.0 + * + * @return array + */ + public function getHeaders() { + return $this->headers; + } + + /** + * @since 1.0 + * + * @return static + */ + public static function factory() { + return new static(); + } + + /** + * @since 1.0 + * + * @param string $action The action name. + * + * @return $this + */ + public function setAction( $action ) { + $this->setParam( 'action', $action ); + return $this; + } + + /** + * Totally overwrite any previously set params + * + * @since 1.0 + * + * @param array $params New parameters. + * + * @return $this + */ + public function setParams( array $params ) { + $this->params = $params; + return $this; + } + + /** + * Totally overwrite any previously set params + * + * @since 1.0 + * + * @param array $params Additional parameters. + * + * @return $this + */ + public function addParams( array $params ) { + $this->params = array_merge( $this->params, $params ); + return $this; + } + + /** + * Set a single parameter. + * + * @since 1.0 + * + * @param string $param The parameter name. + * @param string $value The parameter value. + * + * @return $this + */ + public function setParam( $param, $value ) { + $this->params[$param] = $value; + return $this; + } + + /** + * Totally overwrite any previously set HTTP headers. + * + * @since 1.0 + * + * @param array $headers New headers. + * + * @return $this + */ + public function setHeaders( $headers ) { + $this->headers = $headers; + return $this; + } + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/Guzzle/ClientFactory.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/Guzzle/ClientFactory.php new file mode 100644 index 00000000..704a1660 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/Guzzle/ClientFactory.php @@ -0,0 +1,96 @@ +<?php + +namespace Mediawiki\Api\Guzzle; + +use GuzzleHttp\Client; +use GuzzleHttp\Handler\CurlHandler; +use GuzzleHttp\HandlerStack; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; + +/** + * @since 2.1 + * + * @author Addshore + */ +class ClientFactory implements LoggerAwareInterface { + + private $client; + private $logger; + private $config; + + /** + * @since 2.1 + * + * @param array $config All configuration settings supported by Guzzle, and these: + * middleware => array of extra middleware to pass to guzzle + * user-agent => string default user agent to use for requests + */ + public function __construct( array $config = [] ) { + $this->logger = new NullLogger(); + $this->config = $config; + } + + /** + * @since 2.1 + * + * @return Client + */ + public function getClient() { + if ( $this->client === null ) { + $this->client = $this->newClient(); + } + return $this->client; + } + + /** + * @return Client + */ + private function newClient() { + $this->config += [ + 'cookies' => true, + 'headers' => [], + 'middleware' => [], + ]; + + if ( !array_key_exists( 'User-Agent', $this->config['headers'] ) ) { + if ( array_key_exists( 'user-agent', $this->config ) ) { + $this->config['headers']['User-Agent'] = $this->config['user-agent']; + } else { + $this->config['headers']['User-Agent'] = 'Addwiki - mediawiki-api-base'; + } + } + unset( $this->config['user-agent'] ); + + if ( !array_key_exists( 'handler', $this->config ) ) { + $this->config['handler'] = HandlerStack::create( new CurlHandler() ); + } + + $middlewareFactory = new MiddlewareFactory(); + $middlewareFactory->setLogger( $this->logger ); + + $this->config['middleware'][] = $middlewareFactory->retry(); + + foreach ( $this->config['middleware'] as $name => $middleware ) { + $this->config['handler']->push( $middleware ); + } + unset( $this->config['middleware'] ); + + return new Client( $this->config ); + } + + /** + * Sets a logger instance on the object + * + * @since 2.1 + * + * @param LoggerInterface $logger The new Logger object. + * + * @return null + */ + public function setLogger( LoggerInterface $logger ) { + $this->logger = $logger; + } + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/Guzzle/MiddlewareFactory.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/Guzzle/MiddlewareFactory.php new file mode 100644 index 00000000..9e03c02f --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/Guzzle/MiddlewareFactory.php @@ -0,0 +1,158 @@ +<?php + +namespace Mediawiki\Api\Guzzle; + +use GuzzleHttp\Exception\ConnectException; +use GuzzleHttp\Exception\RequestException; +use GuzzleHttp\Middleware; +use GuzzleHttp\Psr7\Request; +use GuzzleHttp\Psr7\Response; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; + +/** + * @access private + * + * @author Addshore + */ +class MiddlewareFactory implements LoggerAwareInterface { + + /** + * @var LoggerInterface + */ + private $logger; + + public function __construct() { + $this->logger = new NullLogger(); + } + + /** + * @param LoggerInterface $logger The new Logger object. + */ + public function setLogger( LoggerInterface $logger ) { + $this->logger = $logger; + } + + /** + * @access private + * + * @param bool $delay default to true, can be false to speed up tests + * + * @return callable + */ + public function retry( $delay = true ) { + if ( $delay ) { + return Middleware::retry( $this->newRetryDecider(), $this->getRetryDelay() ); + } else { + return Middleware::retry( $this->newRetryDecider() ); + } + } + + /** + * Returns a method that takes the number of retries and returns the number of miliseconds + * to wait + * + * @return callable + */ + private function getRetryDelay() { + return function ( $numberOfRetries, Response $response = null ) { + // The $response argument is only passed as of Guzzle 6.2.2. + if ( $response !== null ) { + // Retry-After may be a number of seconds or an absolute date (RFC 7231, + // section 7.1.3). + $retryAfter = $response->getHeaderLine( 'Retry-After' ); + + if ( is_numeric( $retryAfter ) ) { + return 1000 * $retryAfter; + } + + if ( $retryAfter ) { + $seconds = strtotime( $retryAfter ) - time(); + return 1000 * max( 1, $seconds ); + } + } + + return 1000 * $numberOfRetries; + }; + } + + /** + * @return callable + */ + private function newRetryDecider() { + return function ( + $retries, + Request $request, + Response $response = null, + RequestException $exception = null + ) { + // Don't retry if we have run out of retries + if ( $retries >= 5 ) { + return false; + } + + $shouldRetry = false; + + // Retry connection exceptions + if ( $exception instanceof ConnectException ) { + $shouldRetry = true; + } + + if ( $response ) { + $data = json_decode( $response->getBody(), true ); + + // Retry on server errors + if ( $response->getStatusCode() >= 500 ) { + $shouldRetry = true; + } + + foreach ( $response->getHeader( 'Mediawiki-Api-Error' ) as $mediawikiApiErrorHeader ) { + if ( + // Retry if the API explicitly tells us to: + // https://www.mediawiki.org/wiki/Manual:Maxlag_parameter + $response->getHeaderLine( 'Retry-After' ) + || + // Retry if we have a response with an API error worth retrying + in_array( + $mediawikiApiErrorHeader, + [ + 'ratelimited', + 'maxlag', + 'readonly', + 'internal_api_error_DBQueryError', + ] + ) + || + // Or if we have been stopped from saving as an 'anti-abuse measure' + // Note: this tries to match "actionthrottledtext" i18n messagae for mediawiki + ( + $mediawikiApiErrorHeader == 'failed-save' && + strstr( $data['error']['info'], 'anti-abuse measure' ) + ) + ) { + $shouldRetry = true; + } + + } + } + + // Log if we are retrying + if ( $shouldRetry ) { + $this->logger->warning( + sprintf( + 'Retrying %s %s %s/5, %s', + $request->getMethod(), + $request->getUri(), + $retries + 1, + $response ? 'status code: ' . $response->getStatusCode() : + $exception->getMessage() + ) + ); + } + + return $shouldRetry; + }; + } + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/MediawikiApi.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/MediawikiApi.php new file mode 100644 index 00000000..0c6c4fe3 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/MediawikiApi.php @@ -0,0 +1,507 @@ +<?php + +namespace Mediawiki\Api; + +use DOMDocument; +use DOMXPath; +use GuzzleHttp\Client; +use GuzzleHttp\ClientInterface; +use GuzzleHttp\Exception\RequestException; +use GuzzleHttp\Promise\PromiseInterface; +use InvalidArgumentException; +use Mediawiki\Api\Guzzle\ClientFactory; +use Psr\Http\Message\ResponseInterface; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; +use Psr\Log\NullLogger; +use SimpleXMLElement; + +/** + * Main class for this library + * + * @since 0.1 + * + * @author Addshore + */ +class MediawikiApi implements MediawikiApiInterface, LoggerAwareInterface { + + /** + * @var ClientInterface|null Should be accessed through getClient + */ + private $client = null; + + /** + * @var bool|string + */ + private $isLoggedIn; + + /** + * @var MediawikiSession + */ + private $session; + + /** + * @var string + */ + private $version; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @var string + */ + private $apiUrl; + + /** + * @since 2.0 + * + * @param string $apiEndpoint e.g. https://en.wikipedia.org/w/api.php + * + * @return self returns a MediawikiApi instance using $apiEndpoint + */ + public static function newFromApiEndpoint( $apiEndpoint ) { + return new self( $apiEndpoint ); + } + + /** + * Create a new MediawikiApi object from a URL to any page in a MediaWiki website. + * + * @since 2.0 + * @see https://en.wikipedia.org/wiki/Really_Simple_Discovery + * + * @param string $url e.g. https://en.wikipedia.org OR https://de.wikipedia.org/wiki/Berlin + * @return self returns a MediawikiApi instance using the apiEndpoint provided by the RSD + * file accessible on all Mediawiki pages + * @throws RsdException If the RSD URL could not be found in the page's HTML. + */ + public static function newFromPage( $url ) { + // Set up HTTP client and HTML document. + $tempClient = new Client( [ 'headers' => [ 'User-Agent' => 'addwiki-mediawiki-client' ] ] ); + $pageHtml = $tempClient->get( $url )->getBody(); + $pageDoc = new DOMDocument(); + + // Try to load the HTML (turn off errors temporarily; most don't matter, and if they do get + // in the way of finding the API URL, will be reported in the RsdException below). + $internalErrors = libxml_use_internal_errors( true ); + $pageDoc->loadHTML( $pageHtml ); + $libXmlErrors = libxml_get_errors(); + libxml_use_internal_errors( $internalErrors ); + + // Extract the RSD link. + $xpath = 'head/link[@type="application/rsd+xml"][@href]'; + $link = ( new DOMXpath( $pageDoc ) )->query( $xpath ); + if ( $link->length === 0 ) { + // Format libxml errors for display. + $libXmlErrorStr = array_reduce( $libXmlErrors, function ( $prevErr, $err ) { + return $prevErr . ', ' . $err->message . ' (line '.$err->line . ')'; + } ); + if ( $libXmlErrorStr ) { + $libXmlErrorStr = "In addition, libxml had the following errors: $libXmlErrorStr"; + } + throw new RsdException( "Unable to find RSD URL in page: $url $libXmlErrorStr" ); + } + $rsdUrl = $link->item( 0 )->attributes->getnamedItem( 'href' )->nodeValue; + + // Then get the RSD XML, and return the API link. + $rsdXml = new SimpleXMLElement( $tempClient->get( $rsdUrl )->getBody() ); + return self::newFromApiEndpoint( (string)$rsdXml->service->apis->api->attributes()->apiLink ); + } + + /** + * @param string $apiUrl The API Url + * @param ClientInterface|null $client Guzzle Client + * @param MediawikiSession|null $session Inject a custom session here + */ + public function __construct( $apiUrl, ClientInterface $client = null, + MediawikiSession $session = null ) { + if ( !is_string( $apiUrl ) ) { + throw new InvalidArgumentException( '$apiUrl must be a string' ); + } + if ( $session === null ) { + $session = new MediawikiSession( $this ); + } + + $this->apiUrl = $apiUrl; + $this->client = $client; + $this->session = $session; + + $this->logger = new NullLogger(); + } + + /** + * Get the API URL (the URL to which API requests are sent, usually ending in api.php). + * This is useful if you've created this object via MediawikiApi::newFromPage(). + * + * @since 2.3 + * + * @return string The API URL. + */ + public function getApiUrl() { + return $this->apiUrl; + } + + /** + * @return ClientInterface + */ + private function getClient() { + if ( $this->client === null ) { + $clientFactory = new ClientFactory(); + $clientFactory->setLogger( $this->logger ); + $this->client = $clientFactory->getClient(); + } + return $this->client; + } + + /** + * Sets a logger instance on the object + * + * @since 1.1 + * + * @param LoggerInterface $logger The new Logger object. + * + * @return null + */ + public function setLogger( LoggerInterface $logger ) { + $this->logger = $logger; + $this->session->setLogger( $logger ); + } + + /** + * @since 2.0 + * + * @param Request $request The GET request to send. + * + * @return PromiseInterface + * Normally promising an array, though can be mixed (json_decode result) + * Can throw UsageExceptions or RejectionExceptions + */ + public function getRequestAsync( Request $request ) { + $promise = $this->getClient()->requestAsync( + 'GET', + $this->apiUrl, + $this->getClientRequestOptions( $request, 'query' ) + ); + + return $promise->then( function ( ResponseInterface $response ) { + return call_user_func( [ $this, 'decodeResponse' ], $response ); + } ); + } + + /** + * @since 2.0 + * + * @param Request $request The POST request to send. + * + * @return PromiseInterface + * Normally promising an array, though can be mixed (json_decode result) + * Can throw UsageExceptions or RejectionExceptions + */ + public function postRequestAsync( Request $request ) { + $promise = $this->getClient()->requestAsync( + 'POST', + $this->apiUrl, + $this->getClientRequestOptions( $request, $this->getPostRequestEncoding( $request ) ) + ); + + return $promise->then( function ( ResponseInterface $response ) { + return call_user_func( [ $this, 'decodeResponse' ], $response ); + } ); + } + + /** + * @since 0.2 + * + * @param Request $request The GET request to send. + * + * @return mixed Normally an array + */ + public function getRequest( Request $request ) { + $response = $this->getClient()->request( + 'GET', + $this->apiUrl, + $this->getClientRequestOptions( $request, 'query' ) + ); + + return $this->decodeResponse( $response ); + } + + /** + * @since 0.2 + * + * @param Request $request The POST request to send. + * + * @return mixed Normally an array + */ + public function postRequest( Request $request ) { + $response = $this->getClient()->request( + 'POST', + $this->apiUrl, + $this->getClientRequestOptions( $request, $this->getPostRequestEncoding( $request ) ) + ); + + return $this->decodeResponse( $response ); + } + + /** + * @param ResponseInterface $response + * + * @return mixed + * @throws UsageException + */ + private function decodeResponse( ResponseInterface $response ) { + $resultArray = json_decode( $response->getBody(), true ); + + $this->logWarnings( $resultArray ); + $this->throwUsageExceptions( $resultArray ); + + return $resultArray; + } + + /** + * @param Request $request + * + * @return string + */ + private function getPostRequestEncoding( Request $request ) { + if ( $request instanceof MultipartRequest ) { + return 'multipart'; + } + foreach ( $request->getParams() as $value ) { + if ( is_resource( $value ) ) { + return 'multipart'; + } + } + return 'form_params'; + } + + /** + * @param Request $request + * @param string $paramsKey either 'query' or 'multipart' + * + * @throws RequestException + * + * @return array as needed by ClientInterface::get and ClientInterface::post + */ + private function getClientRequestOptions( Request $request, $paramsKey ) { + $params = array_merge( $request->getParams(), [ 'format' => 'json' ] ); + if ( $paramsKey === 'multipart' ) { + $params = $this->encodeMultipartParams( $request, $params ); + } + + return [ + $paramsKey => $params, + 'headers' => array_merge( $this->getDefaultHeaders(), $request->getHeaders() ), + ]; + } + + /** + * Turn the normal key-value array of request parameters into a multipart array where each + * parameter is a new array with a 'name' and 'contents' elements (and optionally more, if the + * request is a MultipartRequest). + * + * @param Request $request The request to which the parameters belong. + * @param string[] $params The existing parameters. Not the same as $request->getParams(). + * + * @return array + */ + private function encodeMultipartParams( Request $request, $params ) { + // See if there are any multipart parameters in this request. + $multipartParams = ( $request instanceof MultipartRequest ) + ? $request->getMultipartParams() + : []; + return array_map( + function ( $name, $value ) use ( $multipartParams ) { + $partParams = [ + 'name' => $name, + 'contents' => $value, + ]; + if ( isset( $multipartParams[ $name ] ) ) { + // If extra parameters have been set for this part, use them. + $partParams = array_merge( $multipartParams[ $name ], $partParams ); + } + return $partParams; + }, + array_keys( $params ), + $params + ); + } + + /** + * @return array + */ + private function getDefaultHeaders() { + return [ + 'User-Agent' => $this->getUserAgent(), + ]; + } + + private function getUserAgent() { + $loggedIn = $this->isLoggedin(); + if ( $loggedIn ) { + return 'addwiki-mediawiki-client/' . $loggedIn; + } + return 'addwiki-mediawiki-client'; + } + + /** + * @param $result + */ + private function logWarnings( $result ) { + if ( is_array( $result ) && array_key_exists( 'warnings', $result ) ) { + foreach ( $result['warnings'] as $module => $warningData ) { + // Accomodate both formatversion=2 and old-style API results + $logPrefix = $module . ': '; + if ( isset( $warningData['*'] ) ) { + $this->logger->warning( $logPrefix . $warningData['*'], [ 'data' => $warningData ] ); + } else { + $this->logger->warning( $logPrefix . $warningData['warnings'], [ 'data' => $warningData ] ); + } + } + } + } + + /** + * @param array $result + * + * @throws UsageException + */ + private function throwUsageExceptions( $result ) { + if ( is_array( $result ) && array_key_exists( 'error', $result ) ) { + throw new UsageException( + $result['error']['code'], + $result['error']['info'], + $result + ); + } + } + + /** + * @since 0.1 + * + * @return bool|string false or the name of the current user + */ + public function isLoggedin() { + return $this->isLoggedIn; + } + + /** + * @since 0.1 + * + * @param ApiUser $apiUser The ApiUser to log in as. + * + * @throws UsageException + * @return bool success + */ + public function login( ApiUser $apiUser ) { + $this->logger->log( LogLevel::DEBUG, 'Logging in' ); + $credentials = $this->getLoginParams( $apiUser ); + $result = $this->postRequest( new SimpleRequest( 'login', $credentials ) ); + if ( $result['login']['result'] == "NeedToken" ) { + $params = array_merge( [ 'lgtoken' => $result['login']['token'] ], $credentials ); + $result = $this->postRequest( new SimpleRequest( 'login', $params ) ); + } + if ( $result['login']['result'] == "Success" ) { + $this->isLoggedIn = $apiUser->getUsername(); + return true; + } + + $this->isLoggedIn = false; + $this->logger->log( LogLevel::DEBUG, 'Login failed.', $result ); + $this->throwLoginUsageException( $result ); + return false; + } + + /** + * @param ApiUser $apiUser + * + * @return string[] + */ + private function getLoginParams( ApiUser $apiUser ) { + $params = [ + 'lgname' => $apiUser->getUsername(), + 'lgpassword' => $apiUser->getPassword(), + ]; + + if ( !is_null( $apiUser->getDomain() ) ) { + $params['lgdomain'] = $apiUser->getDomain(); + } + return $params; + } + + /** + * @param array $result + * + * @throws UsageException + */ + private function throwLoginUsageException( $result ) { + $loginResult = $result['login']['result']; + + throw new UsageException( + 'login-' . $loginResult, + array_key_exists( 'reason', $result['login'] ) + ? $result['login']['reason'] + : 'No Reason given', + $result + ); + } + + /** + * @since 0.1 + * + * @return bool success + */ + public function logout() { + $this->logger->log( LogLevel::DEBUG, 'Logging out' ); + $result = $this->postRequest( new SimpleRequest( 'logout' ) ); + if ( $result === [] ) { + $this->isLoggedIn = false; + $this->clearTokens(); + return true; + } + return false; + } + + /** + * @since 0.1 + * + * @param string $type The token type to get. + * + * @return string + */ + public function getToken( $type = 'csrf' ) { + return $this->session->getToken( $type ); + } + + /** + * Clear all tokens stored by the API. + * + * @since 0.1 + */ + public function clearTokens() { + $this->session->clearTokens(); + } + + /** + * @return string + */ + public function getVersion() { + if ( !isset( $this->version ) ) { + $result = $this->getRequest( new SimpleRequest( 'query', [ + 'meta' => 'siteinfo', + 'continue' => '', + ] ) ); + preg_match( + '/\d+(?:\.\d+)+/', + $result['query']['general']['generator'], + $versionParts + ); + $this->version = $versionParts[0]; + } + return $this->version; + } + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/MediawikiApiInterface.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/MediawikiApiInterface.php new file mode 100644 index 00000000..83580676 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/MediawikiApiInterface.php @@ -0,0 +1,60 @@ +<?php + +namespace Mediawiki\Api; + +/** + * @since 2.2 + * @licence GNU GPL v2+ + * @author Addshore + * @author Jeroen De Dauw < jeroendedauw@gmail.com > + */ +interface MediawikiApiInterface extends ApiRequester, AsyncApiRequester { + + /** + * @since 2.2 + * + * @return bool|string false or the name of the current user + */ + public function isLoggedin(); + + /** + * @since 2.2 + * + * @param ApiUser $apiUser The ApiUser to log in as. + * + * @throws UsageException + * @return bool success + */ + public function login( ApiUser $apiUser ); + + /** + * @since 2.2 + * + * @return bool success + */ + public function logout(); + + /** + * @since 2.2 + * + * @param string $type The type of token to get. + * + * @return string + */ + public function getToken( $type = 'csrf' ); + + /** + * @since 2.2 + * + * Clears all tokens stored by the api + */ + public function clearTokens(); + + /** + * @since 2.2 + * + * @return string + */ + public function getVersion(); + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/MediawikiSession.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/MediawikiSession.php new file mode 100644 index 00000000..c430695c --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/MediawikiSession.php @@ -0,0 +1,168 @@ +<?php + +namespace Mediawiki\Api; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; +use Psr\Log\NullLogger; + +/** + * @since 0.1 + * + * @author Addshore + */ +class MediawikiSession implements LoggerAwareInterface { + + /** + * @var array + */ + private $tokens = []; + + /** + * @var MediawikiApi + */ + private $api; + + /** + * @var bool if this session is running against mediawiki version pre 1.25 + */ + private $usePre125TokensModule = false; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @param MediawikiApi $api The API object to use for this session. + */ + public function __construct( MediawikiApi $api ) { + $this->api = $api; + $this->logger = new NullLogger(); + } + + /** + * Sets a logger instance on the object + * + * @since 1.1 + * + * @param LoggerInterface $logger The new Logger object. + * + * @return null + */ + public function setLogger( LoggerInterface $logger ) { + $this->logger = $logger; + } + + /** + * Tries to get the specified token from the API + * + * @since 0.1 + * + * @param string $type The type of token to get. + * + * @return string + */ + public function getToken( $type = 'csrf' ) { + // If we don't already have the token that we want + if ( !array_key_exists( $type, $this->tokens ) ) { + $this->logger->log( LogLevel::DEBUG, 'Getting fresh token', [ 'type' => $type ] ); + + // If we know that we don't have the new module mw<1.25 + if ( $this->usePre125TokensModule ) { + return $this->reallyGetPre125Token( $type ); + } else { + return $this->reallyGetToken( $type ); + } + + } + + return $this->tokens[$type]; + } + + private function reallyGetPre125Token( $type ) { + // Suppress deprecation warning + $result = @$this->api->postRequest( // @codingStandardsIgnoreLine + new SimpleRequest( 'tokens', [ 'type' => $this->getOldTokenType( $type ) ] ) + ); + $this->tokens[$type] = array_pop( $result['tokens'] ); + + return $this->tokens[$type]; + } + + private function reallyGetToken( $type ) { + // We suppress errors on this call so the user doesn't get get a warning that isn't their fault. + $result = @$this->api->postRequest( // @codingStandardsIgnoreLine + new SimpleRequest( 'query', [ + 'meta' => 'tokens', + 'type' => $this->getNewTokenType( $type ), + 'continue' => '', + ] ) + ); + // If mw<1.25 (no new module) + $metaWarning = "Unrecognized value for parameter 'meta': tokens"; + if ( isset( $result['warnings']['query']['*'] ) + && false !== strpos( $result['warnings']['query']['*'], $metaWarning ) ) { + $this->usePre125TokensModule = true; + $this->logger->log( LogLevel::DEBUG, 'Falling back to pre 1.25 token system' ); + $this->tokens[$type] = $this->reallyGetPre125Token( $type ); + } else { + $this->tokens[$type] = array_pop( $result['query']['tokens'] ); + } + + return $this->tokens[$type]; + } + + /** + * Tries to guess a new token type from an old token type + * + * @param string $type + * + * @return string + */ + private function getNewTokenType( $type ) { + switch ( $type ) { + case 'edit': + case 'delete': + case 'protect': + case 'move': + case 'block': + case 'unblock': + case 'email': + case 'import': + case 'options': + return 'csrf'; + } + // Return the same type, don't know what to do with this.. + return $type; + } + + /** + * Tries to guess an old token type from a new token type + * + * @param $type + * + * @return string + */ + private function getOldTokenType( $type ) { + switch ( $type ) { + // Guess that we want an edit token, this may not always work as we might be trying to + // use it for something else... + case 'csrf': + return 'edit'; + } + return $type; + } + + /** + * Clears all tokens stored by the api + * + * @since 0.2 + */ + public function clearTokens() { + $this->logger->log( LogLevel::DEBUG, 'Clearing session tokens', [ 'tokens' => $this->tokens ] ); + $this->tokens = []; + } + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/MultipartRequest.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/MultipartRequest.php new file mode 100644 index 00000000..8d3fbdf4 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/MultipartRequest.php @@ -0,0 +1,77 @@ +<?php + +namespace Mediawiki\Api; + +use Exception; + +/** + * A MultipartRequest is the same as a FluentRequest with additional support for setting request + * parameters (both normal parameters and headers) on multipart requests. + * + * @link http://docs.guzzlephp.org/en/stable/request-options.html#multipart + * + * @since 2.4.0 + */ +class MultipartRequest extends FluentRequest { + + /** @var mixed[] */ + protected $multipartParams = []; + + /** + * Check the structure of a multipart parameter array. + * + * @param mixed[] $params The multipart parameters to check. + * + * @throws Exception + */ + protected function checkMultipartParams( $params ) { + foreach ( $params as $key => $val ) { + if ( !is_array( $val ) ) { + throw new Exception( "Parameter '$key' must be an array." ); + } + if ( !in_array( $key, array_keys( $this->getParams() ) ) ) { + throw new Exception( "Parameter '$key' is not already set on this request." ); + } + } + } + + /** + * Set all multipart parameters, replacing all existing ones. + * + * Each key of the array passed in here must be the name of a parameter already set on this + * request object. + * + * @param mixed[] $params The multipart parameters to use. + * @return $this + */ + public function setMultipartParams( $params ) { + $this->checkMultipartParams( $params ); + $this->multipartParams = $params; + return $this; + } + + /** + * Add extra multipart parameters. + * + * Each key of the array passed in here must be the name of a parameter already set on this + * request object. + * + * @param mixed[] $params The multipart parameters to add to any already present. + * + * @return $this + */ + public function addMultipartParams( $params ) { + $this->checkMultipartParams( $params ); + $this->multipartParams = array_merge( $this->multipartParams, $params ); + return $this; + } + + /** + * Get all multipart request parameters. + * + * @return mixed[] + */ + public function getMultipartParams() { + return $this->multipartParams; + } +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/Request.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/Request.php new file mode 100644 index 00000000..0daace2a --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/Request.php @@ -0,0 +1,30 @@ +<?php + +namespace Mediawiki\Api; + +/** + * @since 0.2 + * + * @author Addshore + */ +interface Request { + + /** + * @since 0.2 + * + * @return array + */ + public function getParams(); + + /** + * Associative array of headers to add to the request. + * Each key is the name of a header, and each value is a string or array of strings representing + * the header field values. + * + * @since 0.3 + * + * @return array + */ + public function getHeaders(); + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/RsdException.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/RsdException.php new file mode 100644 index 00000000..b304f574 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/RsdException.php @@ -0,0 +1,12 @@ +<?php + +namespace Mediawiki\Api; + +use Exception; + +/** + * An exception raised when an issue is encountered with Really Simple Discovery. + * @see https://en.wikipedia.org/wiki/Really_Simple_Discovery + */ +class RsdException extends Exception { +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/SimpleRequest.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/SimpleRequest.php new file mode 100644 index 00000000..1e33348d --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/SimpleRequest.php @@ -0,0 +1,61 @@ +<?php + +namespace Mediawiki\Api; + +use InvalidArgumentException; + +/** + * Please consider using a FluentRequest object + * + * @since 0.2 + * + * @author Addshore + */ +class SimpleRequest implements Request { + + /** + * @var string + */ + private $action; + + /** + * @var array + */ + private $params; + + /** + * @var array + */ + private $headers; + + /** + * @param string $action The API action. + * @param array $params The parameters for the action. + * @param array $headers Any extra HTTP headers to send. + * + * @throws InvalidArgumentException + */ + public function __construct( $action, array $params = [], array $headers = [] ) { + if ( !is_string( $action ) ) { + throw new InvalidArgumentException( '$action must be string' ); + } + $this->action = $action; + $this->params = $params; + $this->headers = $headers; + } + + /** + * @return string[] + */ + public function getParams() { + return array_merge( [ 'action' => $this->action ], $this->params ); + } + + /** + * @return string[] + */ + public function getHeaders() { + return $this->headers; + } + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/UsageException.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/UsageException.php new file mode 100644 index 00000000..77148f1b --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/src/UsageException.php @@ -0,0 +1,75 @@ +<?php + +namespace Mediawiki\Api; + +use Exception; + +/** + * Class representing a Mediawiki Api UsageException + * + * @since 0.1 + * + * @author Addshore + */ +class UsageException extends Exception { + + /** + * @var string + */ + private $apiCode; + + /** + * @var array + */ + private $result; + + /** + * @var string + */ + private $rawMessage; + + /** + * @since 0.1 + * + * @param string $apiCode The API error code. + * @param string $message The API error message. + * @param array $result the result the exception was generated from + */ + public function __construct( $apiCode = '', $message = '', $result = [] ) { + $this->apiCode = $apiCode; + $this->result = $result; + $this->rawMessage = $message; + $message = 'Code: ' . $apiCode . PHP_EOL . + 'Message: ' . $message . PHP_EOL . + 'Result: ' . json_encode( $result ); + parent::__construct( $message, 0, null ); + } + + /** + * @since 0.1 + * + * @return string + */ + public function getApiCode() { + return $this->apiCode; + } + + /** + * @since 0.3 + * + * @return array + */ + public function getApiResult() { + return $this->result; + } + + /** + * @since 2.3.0 + * + * @return string + */ + public function getRawMessage() { + return $this->rawMessage; + } + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Integration/MediawikiApiTest.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Integration/MediawikiApiTest.php new file mode 100644 index 00000000..da6683e4 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Integration/MediawikiApiTest.php @@ -0,0 +1,103 @@ +<?php + +namespace Mediawiki\Api\Test\Integration; + +use Mediawiki\Api\MediawikiApi; +use Mediawiki\Api\SimpleRequest; + +/** + * @author Addshore + */ +class MediawikiApiTest extends \PHPUnit_Framework_TestCase { + + /** + * @covers Mediawiki\Api\MediawikiApi::newFromPage + */ + public function testNewFromPage() { + $api = MediawikiApi::newFromPage( TestEnvironment::newInstance()->getPageUrl() ); + $this->assertInstanceOf( 'Mediawiki\Api\MediawikiApi', $api ); + } + + /** + * @covers Mediawiki\Api\MediawikiApi::newFromPage + * @expectedException Mediawiki\Api\RsdException + * @expectedExceptionMessageRegExp |Unable to find RSD URL in page.*| + */ + public function testNewFromPageInvalidHtml() { + // This could be any URL that doesn't contain the RSD link, but the README URL + // is a test-accessible one that doesn't return 404. + $nonWikiPage = str_replace( 'api.php', 'README', TestEnvironment::newInstance()->getApiUrl() ); + MediawikiApi::newFromPage( $nonWikiPage ); + } + + /** + * Duplicate element IDs break DOMDocument::loadHTML + * @see https://phabricator.wikimedia.org/T163527#3219833 + * @covers Mediawiki\Api\MediawikiApi::newFromPage + */ + public function testNewFromPageWithDuplicateId() { + $testPageName = __METHOD__; + $testEnv = TestEnvironment::newInstance(); + $wikiPageUrl = str_replace( 'api.php', "index.php?title=$testPageName", $testEnv->getApiUrl() ); + + // Test with no duplicate IDs. + $testEnv->savePage( $testPageName, '<p id="unique-id"></p>' ); + $api1 = MediawikiApi::newFromPage( $wikiPageUrl ); + $this->assertInstanceOf( MediawikiApi::class, $api1 ); + + // Test with duplicate ID. + $wikiText = '<p id="duplicated-id"></p><div id="duplicated-id"></div>'; + $testEnv->savePage( $testPageName, $wikiText ); + $api2 = MediawikiApi::newFromPage( $wikiPageUrl ); + $this->assertInstanceOf( MediawikiApi::class, $api2 ); + } + + /** + * @covers Mediawiki\Api\MediawikiApi::getRequest + * @covers Mediawiki\Api\MediawikiApi::getClientRequestOptions + * @covers Mediawiki\Api\MediawikiApi::decodeResponse + * @covers Mediawiki\Api\MediawikiApi::getClient + */ + public function testQueryGetResponse() { + $api = TestEnvironment::newInstance()->getApi(); + $response = $api->getRequest( new SimpleRequest( 'query' ) ); + $this->assertInternalType( 'array', $response ); + } + + /** + * @covers Mediawiki\Api\MediawikiApi::getRequestAsync + * @covers Mediawiki\Api\MediawikiApi::getClientRequestOptions + * @covers Mediawiki\Api\MediawikiApi::decodeResponse + * @covers Mediawiki\Api\MediawikiApi::getClient + */ + public function testQueryGetResponseAsync() { + $api = TestEnvironment::newInstance()->getApi(); + $response = $api->getRequestAsync( new SimpleRequest( 'query' ) ); + $this->assertInternalType( 'array', $response->wait() ); + } + + /** + * @covers Mediawiki\Api\MediawikiApi::postRequest + * @covers Mediawiki\Api\MediawikiApi::getClientRequestOptions + * @covers Mediawiki\Api\MediawikiApi::decodeResponse + * @covers Mediawiki\Api\MediawikiApi::getClient + */ + public function testQueryPostResponse() { + $api = TestEnvironment::newInstance()->getApi(); + $response = $api->postRequest( new SimpleRequest( 'query' ) ); + $this->assertInternalType( 'array', $response ); + } + + /** + * @covers Mediawiki\Api\MediawikiApi::postRequestAsync + * @covers Mediawiki\Api\MediawikiApi::getClientRequestOptions + * @covers Mediawiki\Api\MediawikiApi::decodeResponse + * @covers Mediawiki\Api\MediawikiApi::getClient + */ + public function testQueryPostResponseAsync() { + $api = TestEnvironment::newInstance()->getApi(); + $response = $api->postRequestAsync( new SimpleRequest( 'query' ) ); + $this->assertInternalType( 'array', $response->wait() ); + } + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Integration/TestEnvironment.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Integration/TestEnvironment.php new file mode 100644 index 00000000..cb781508 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Integration/TestEnvironment.php @@ -0,0 +1,92 @@ +<?php + +namespace Mediawiki\Api\Test\Integration; + +use Exception; +use Mediawiki\Api\MediawikiApi; +use Mediawiki\Api\SimpleRequest; + +/** + * @author Addshore + */ +class TestEnvironment { + + /** + * Get a new TestEnvironment. + * This is identical to calling self::__construct() but is useful for fluent construction. + * + * @return TestEnvironment + */ + public static function newInstance() { + return new self(); + } + + /** @var MediawikiApi */ + private $api; + + /** @var string */ + private $apiUrl; + + /** @var string */ + private $pageUrl; + + /** + * Set up the test environment by creating a new API object pointing to a + * MediaWiki installation on localhost (or elsewhere as specified by the + * ADDWIKI_MW_API environment variable). + * + * @throws Exception If the ADDWIKI_MW_API environment variable does not end in 'api.php' + */ + public function __construct() { + $apiUrl = getenv( 'ADDWIKI_MW_API' ); + + if ( substr( $apiUrl, -7 ) !== 'api.php' ) { + $msg = "URL incorrect: $apiUrl" + ." (Set the ADDWIKI_MW_API environment variable correctly)"; + throw new Exception( $msg ); + } + + $this->apiUrl = $apiUrl; + $this->pageUrl = str_replace( 'api.php', 'index.php?title=Special:SpecialPages', $apiUrl ); + $this->api = MediawikiApi::newFromApiEndpoint( $this->apiUrl ); + } + + /** + * Get the url of the api to test against, based on the MEDIAWIKI_API_URL environment variable. + * @return string + */ + public function getApiUrl() { + return $this->apiUrl; + } + + /** + * Get the url of a page on the wiki to test against, based on the api url. + * @return string + */ + public function getPageUrl() { + return $this->pageUrl; + } + + /** + * Get the MediawikiApi to test against + * @return MediawikiApi + */ + public function getApi() { + return $this->api; + } + + /** + * Save a wiki page. + * @param string $title The title of the page. + * @param string $content The complete page text to save. + */ + public function savePage( $title, $content ) { + $params = [ + 'title' => $title, + 'text' => $content, + 'md5' => md5( $content ), + 'token' => $this->api->getToken(), + ]; + $this->api->postRequest( new SimpleRequest( 'edit', $params ) ); + } +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Integration/TokenHandlingTest.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Integration/TokenHandlingTest.php new file mode 100644 index 00000000..68ec52be --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Integration/TokenHandlingTest.php @@ -0,0 +1,28 @@ +<?php + +namespace Mediawiki\Api\Test\Integration; + +/** + * @author Addshore + */ +class TokenHandlingTest extends \PHPUnit_Framework_TestCase { + + /** + * @dataProvider provideTokenTypes + * + * @covers Mediawiki\Api\MediawikiApi::getToken + * @covers Mediawiki\Api\MediawikiSession::getToken + */ + public function testGetAnonUserToken() { + $api = TestEnvironment::newInstance()->getApi(); + $this->assertEquals( '+\\', $api->getToken() ); + } + + public function provideTokenTypes() { + return [ + [ 'csrf' ], + [ 'edit' ], + ]; + } + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/ApiUserTest.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/ApiUserTest.php new file mode 100644 index 00000000..7e0da7ca --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/ApiUserTest.php @@ -0,0 +1,71 @@ +<?php + +namespace Mediawiki\Api\Test\Unit; + +use Mediawiki\Api\ApiUser; + +/** + * @author Addshore + * + * @covers Mediawiki\Api\ApiUser + */ +class ApiUserTest extends \PHPUnit_Framework_TestCase { + + /** + * @dataProvider provideValidConstruction + */ + public function testValidConstruction( $user, $pass, $domain = null ) { + $apiUser = new ApiUser( $user, $pass, $domain ); + $this->assertSame( $user, $apiUser->getUsername() ); + $this->assertSame( $pass, $apiUser->getPassword() ); + $this->assertSame( $domain, $apiUser->getDomain() ); + } + + public function provideValidConstruction() { + return [ + [ 'user', 'pass' ], + [ 'user', 'pass', 'domain' ], + ]; + } + + /** + * @dataProvider provideInvalidConstruction + */ + public function testInvalidConstruction( $user, $pass, $domain = null ) { + $this->setExpectedException( 'InvalidArgumentException' ); + new ApiUser( $user, $pass, $domain ); + } + + public function provideInvalidConstruction() { + return [ + [ 'user', '' ], + [ '', 'pass' ], + [ '', '' ], + [ 'user', [] ], + [ 'user', 455667 ], + [ 34567, 'pass' ], + [ [], 'pass' ], + [ 'user', 'pass', [] ], + ]; + } + + /** + * @dataProvider provideTestEquals + */ + public function testEquals( ApiUser $user1, ApiUser $user2, $shouldEqual ) { + $this->assertSame( $shouldEqual, $user1->equals( $user2 ) ); + $this->assertSame( $shouldEqual, $user2->equals( $user1 ) ); + } + + public function provideTestEquals() { + return [ + [ new ApiUser( 'usera', 'passa' ), new ApiUser( 'usera', 'passa' ), true ], + [ new ApiUser( 'usera', 'passa', 'domain' ), new ApiUser( 'usera', 'passa', 'domain' ), true ], + [ new ApiUser( 'DIFF', 'passa' ), new ApiUser( 'usera', 'passa' ), false ], + [ new ApiUser( 'usera', 'DIFF' ), new ApiUser( 'usera', 'passa' ), false ], + [ new ApiUser( 'usera', 'passa' ), new ApiUser( 'DIFF', 'passa' ), false ], + [ new ApiUser( 'usera', 'passa' ), new ApiUser( 'usera', 'DIFF' ), false ], + ]; + } + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/FluentRequestTest.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/FluentRequestTest.php new file mode 100644 index 00000000..93af921e --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/FluentRequestTest.php @@ -0,0 +1,69 @@ +<?php + +namespace Mediawiki\Api\Test\Unit; + +use Mediawiki\Api\FluentRequest; +use PHPUnit_Framework_TestCase; + +/** + * @author Addshore + * + * @covers Mediawiki\Api\FluentRequest + */ +class FluentRequestTest extends PHPUnit_Framework_TestCase { + + public function testFactory() { + $this->assertInstanceOf( 'Mediawiki\Api\FluentRequest', FluentRequest::factory() ); + } + + public function testConstructionDefaults() { + $request = new FluentRequest(); + + $this->assertEquals( [], $request->getParams() ); + $this->assertEquals( [], $request->getHeaders() ); + } + + public function testSetParams() { + $request = new FluentRequest(); + + $params = [ 'foo', 'bar' ]; + $request->setParams( $params ); + + $this->assertEquals( $params, $request->getParams() ); + } + + public function testSetParam() { + $request = new FluentRequest(); + + $request->setParam( 'paramName', 'fooValue' ); + + $this->assertEquals( [ 'paramName' => 'fooValue' ], $request->getParams() ); + } + + public function testAddParams() { + $request = new FluentRequest(); + + $params = [ 'a' => 'foo', 'b' => 'bar' ]; + $request->addParams( $params ); + + $this->assertEquals( $params, $request->getParams() ); + } + + public function testSetHeaders() { + $request = new FluentRequest(); + + $params = [ 'foo', 'bar' ]; + $request->setHeaders( $params ); + + $this->assertEquals( $params, $request->getHeaders() ); + } + + public function testSetAction() { + $request = new FluentRequest(); + + $request->setAction( 'fooAction' ); + + $this->assertEquals( [ 'action' => 'fooAction' ], $request->getParams() ); + } + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/Guzzle/ClientFactoryTest.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/Guzzle/ClientFactoryTest.php new file mode 100644 index 00000000..d84d0333 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/Guzzle/ClientFactoryTest.php @@ -0,0 +1,91 @@ +<?php + +namespace Mediawiki\Api\Test\Unit\Guzzle; + +use GuzzleHttp\HandlerStack; +use Mediawiki\Api\Guzzle\ClientFactory; +use Psr\Http\Message\RequestInterface; + +/** + * @author Christian Schmidt + * + * @covers Mediawiki\Api\Guzzle\ClientFactory + */ +class ClientFactoryTest extends \PHPUnit_Framework_TestCase { + + public function testNoConfig() { + $clientFactory = new ClientFactory(); + + $client = $clientFactory->getClient(); + + $this->assertSame( $client, $clientFactory->getClient() ); + + $config = $client->getConfig(); + $this->assertEquals( $config['headers']['User-Agent'], 'Addwiki - mediawiki-api-base' ); + + $this->assertFalse( empty( $config['cookies'] ) ); + } + + public function testUserAgent() { + $clientFactory = new ClientFactory( [ 'user-agent' => 'Foobar' ] ); + + $client = $clientFactory->getClient(); + + $this->assertNull( $client->getConfig( 'user-agent' ) ); + + $config = $client->getConfig(); + $this->assertEquals( $config['headers']['User-Agent'], 'Foobar' ); + } + + public function testHeaders() { + $clientFactory = new ClientFactory( [ + 'headers' => [ + 'User-Agent' => 'Foobar', + 'X-Foo' => 'Bar', + ] + ] ); + + $client = $clientFactory->getClient(); + + $headers = $client->getConfig( 'headers' ); + $this->assertCount( 2, $headers ); + $this->assertEquals( $headers['User-Agent'], 'Foobar' ); + $this->assertEquals( $headers['X-Foo'], 'Bar' ); + } + + public function testHandler() { + $handler = HandlerStack::create(); + + $clientFactory = new ClientFactory( [ 'handler' => $handler ] ); + + $client = $clientFactory->getClient(); + + $this->assertSame( $handler, $client->getConfig( 'handler' ) ); + } + + public function testMiddleware() { + $invoked = false; + $middleware = function () use ( &$invoked ) { + return function () use ( &$invoked ) { + $invoked = true; + }; + }; + + $clientFactory = new ClientFactory( [ 'middleware' => [ $middleware ] ] ); + + $client = $clientFactory->getClient(); + + $this->assertNull( $client->getConfig( 'middleware' ) ); + + $request = $this->getMockBuilder( RequestInterface::class )->getMock(); + + $handler = $client->getConfig( 'handler' ); + $handler->remove( 'http_errors' ); + $handler->remove( 'allow_redirects' ); + $handler->remove( 'cookies' ); + $handler->remove( 'prepare_body' ); + $handler( $request, [] ); + + $this->assertTrue( $invoked ); + } +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/Guzzle/MiddlewareFactoryTest.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/Guzzle/MiddlewareFactoryTest.php new file mode 100644 index 00000000..1cf7270a --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/Guzzle/MiddlewareFactoryTest.php @@ -0,0 +1,214 @@ +<?php + +namespace Mediawiki\Api\Test\Unit\Guzzle; + +use GuzzleHttp\Client; +use GuzzleHttp\Exception\ConnectException; +use GuzzleHttp\Handler\MockHandler; +use GuzzleHttp\HandlerStack; +use GuzzleHttp\Psr7\Request; +use GuzzleHttp\Psr7\Response; +use Mediawiki\Api\Guzzle\MiddlewareFactory; + +/** + * @author Addshore + * + * @todo test interaction with logger + * + * @covers Mediawiki\Api\Guzzle\MiddlewareFactory + */ +class MiddlewareFactoryTest extends \PHPUnit_Framework_TestCase { + + public function testRetriesConnectException() { + $queue = [ + new ConnectException( 'Error 1', new Request( 'GET', 'test' ) ), + new Response( 200, [ 'X-Foo' => 'Bar' ] ), + ]; + + $client = $this->getClient( $queue, $delays ); + $response = $client->request( 'GET', '/' ); + + $this->assertEquals( 200, $response->getStatusCode() ); + $this->assertEquals( [ 1000 ], $delays ); + } + + public function testRetries500Errors() { + $queue = [ + new Response( 500 ), + new Response( 200 ), + ]; + + $client = $this->getClient( $queue, $delays ); + $response = $client->request( 'GET', '/' ); + + $this->assertEquals( 200, $response->getStatusCode() ); + $this->assertEquals( [ 1000 ], $delays ); + } + + public function testRetriesSomeMediawikiApiErrorHeaders() { + $queue = [ + new Response( 200, [ 'mediawiki-api-error' => 'ratelimited' ] ), + new Response( 200, [ 'mediawiki-api-error' => 'maxlag' ] ), + new Response( 200, [ 'mediawiki-api-error' => 'readonly' ] ), + new Response( 200, [ 'mediawiki-api-error' => 'internal_api_error_DBQueryError' ] ), + new Response( 200, [ 'mediawiki-api-error' => 'DoNotRetryThisHeader' ] ), + ]; + + $client = $this->getClient( $queue, $delays ); + $response = $client->request( 'GET', '/' ); + + $this->assertEquals( 200, $response->getStatusCode() ); + $this->assertEquals( + [ 'DoNotRetryThisHeader' ], + $response->getHeader( 'mediawiki-api-error' ) + ); + $this->assertEquals( [ 1000, 2000, 3000, 4000 ], $delays ); + } + + public function testRetryAntiAbuseMeasure() { + $antiAbusejson = json_encode( + [ + 'error' => [ + 'info' => 'anti-abuse measure' + ] + ] + ); + + $queue = [ + new Response( 200, [ 'mediawiki-api-error' => 'failed-save' ], $antiAbusejson ), + new Response( 200, [ 'mediawiki-api-error' => 'DoNotRetryThisHeader' ] ), + ]; + + $client = $this->getClient( $queue, $delays ); + $response = $client->request( 'GET', '/' ); + + $this->assertEquals( 200, $response->getStatusCode() ); + $this->assertEquals( 'DoNotRetryThisHeader', $response->getHeaderLine( 'mediawiki-api-error' ) ); + } + + public function testRetryLimit() { + $queue = [ + new ConnectException( 'Error 1', new Request( 'GET', 'test' ) ), + new ConnectException( 'Error 2', new Request( 'GET', 'test' ) ), + new ConnectException( 'Error 3', new Request( 'GET', 'test' ) ), + new ConnectException( 'Error 4', new Request( 'GET', 'test' ) ), + new ConnectException( 'Error 5', new Request( 'GET', 'test' ) ), + new ConnectException( 'Error 6', new Request( 'GET', 'test' ) ), + new Response( 200 ), + ]; + + $client = $this->getClient( $queue ); + + $this->setExpectedException( + 'GuzzleHttp\Exception\ConnectException', + 'Error 6' + ); + + $client->request( 'GET', '/' ); + } + + public function testConnectExceptionRetryDelay() { + $queue = [ + new ConnectException( '+1 second delay', new Request( 'GET', 'test' ) ), + new ConnectException( '+2 second delay', new Request( 'GET', 'test' ) ), + new Response( 200 ), + ]; + + $client = $this->getClient( $queue, $delays ); + $response = $client->request( 'GET', '/' ); + + $this->assertEquals( 200, $response->getStatusCode() ); + $this->assertEquals( [ 1000, 2000 ], $delays ); + } + + public function testServerErrorRetryDelay() { + $queue = [ + new Response( 500 ), + new Response( 503 ), + new Response( 200 ), + ]; + + $client = $this->getClient( $queue, $delays ); + $response = $client->request( 'GET', '/' ); + + $this->assertEquals( 200, $response->getStatusCode() ); + $this->assertEquals( [ 1000, 2000 ], $delays ); + } + + public function testRelativeRetryDelayHeaderRetryDelay() { + $queue = [ + new Response( 200, [ 'mediawiki-api-error' => 'maxlag', 'retry-after' => 10 ] ), + new Response( 200 ), + ]; + + $this->getClient( $queue, $delays )->request( 'GET', '/' ); + + $this->assertEquals( [ 10000 ], $delays ); + } + + public function testAbsoluteRetryDelayHeaderRetryDelay() { + $queue = [ + new Response( + 200, + [ + 'mediawiki-api-error' => 'maxlag', + 'retry-after' => gmdate( DATE_RFC1123, time() + 600 ), + ] + ), + new Response( 200 ), + ]; + + $client = $this->getClient( $queue, $delays ); + $response = $client->request( 'GET', '/' ); + + $this->assertEquals( 200, $response->getStatusCode() ); + $this->assertCount( 1, $delays ); + // Allow 5 second delay while running this test. + $this->assertGreaterThan( 600000 - 5000, $delays[0] ); + } + + public function testPastRetryDelayHeaderRetryDelay() { + $queue = [ + new Response( + 200, + [ + 'mediawiki-api-error' => 'maxlag', + 'retry-after' => 'Fri, 31 Dec 1999 23:59:59 GMT', + ] + ), + new Response( 200 ), + ]; + + $client = $this->getClient( $queue, $delays ); + $response = $client->request( 'GET', '/' ); + + $this->assertEquals( 200, $response->getStatusCode() ); + $this->assertEquals( [ 1000 ], $delays ); + } + + private function getClient( array $queue, &$delays = null ) { + $mock = new MockHandler( $queue ); + + $handler = HandlerStack::create( $mock ); + + $middlewareFactory = new MiddlewareFactory(); + $handler->push( $middlewareFactory->retry() ); + + $delayMocker = $this->getDelayMocker( $delays ); + $handler->push( $delayMocker ); + + return new Client( [ 'handler' => $handler ] ); + } + + private function getDelayMocker( &$delays ) { + return function ( callable $handler ) use ( &$delays ) { + return function ( $request, array $options ) use ( $handler, &$delays ) { + if ( isset( $options['delay'] ) ) { + $delays[] = $options['delay']; + unset( $options['delay'] ); + } + return $handler( $request, $options ); + }; + }; + } +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/MediawikiApiTest.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/MediawikiApiTest.php new file mode 100644 index 00000000..a55f6739 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/MediawikiApiTest.php @@ -0,0 +1,296 @@ +<?php + +namespace Mediawiki\Api\Test\Unit; + +use Mediawiki\Api\ApiUser; +use Mediawiki\Api\MediawikiApi; +use Mediawiki\Api\SimpleRequest; +use Mediawiki\Api\UsageException; +use PHPUnit_Framework_TestCase; +use stdClass; + +/** + * @author Addshore + * + * @covers Mediawiki\Api\MediawikiApi + */ +class MediawikiApiTest extends PHPUnit_Framework_TestCase { + + public function provideValidConstruction() { + return [ + [ 'localhost' ], + [ 'http://en.wikipedia.org/w/api.php' ], + [ '127.0.0.1/foo/bar/wwwwwwwww/api.php' ], + ]; + } + + /** + * @dataProvider provideValidConstruction + */ + public function testValidConstruction( $apiLocation ) { + new MediawikiApi( $apiLocation ); + $this->assertTrue( true ); + } + + public function provideInvalidConstruction() { + return [ + [ null ], + [ 12345678 ], + [ [] ], + [ new stdClass() ], + ]; + } + + /** + * @dataProvider provideInvalidConstruction + */ + public function testInvalidConstruction( $apiLocation ) { + $this->setExpectedException( 'InvalidArgumentException' ); + new MediawikiApi( $apiLocation ); + } + + private function getMockClient() { + return $this->getMock( 'GuzzleHttp\ClientInterface' ); + } + + private function getMockResponse( $responseValue ) { + $mock = $this->getMock( 'Psr\Http\Message\ResponseInterface' ); + $mock->expects( $this->any() ) + ->method( 'getBody' ) + ->will( $this->returnValue( json_encode( $responseValue ) ) ); + return $mock; + } + + private function getExpectedRequestOpts( $params, $paramsLocation ) { + return [ + $paramsLocation => array_merge( $params, [ 'format' => 'json' ] ), + 'headers' => [ 'User-Agent' => 'addwiki-mediawiki-client' ], + ]; + } + + public function testGetRequestThrowsUsageExceptionOnError() { + $client = $this->getMockClient(); + $client->expects( $this->once() ) + ->method( 'request' ) + ->will( $this->returnValue( + $this->getMockResponse( [ 'error' => [ + 'code' => 'imacode', + 'info' => 'imamsg', + ] ] ) + ) ); + $api = new MediawikiApi( '', $client ); + + try{ + $api->getRequest( new SimpleRequest( 'foo' ) ); + $this->fail( 'No Usage Exception Thrown' ); + } + catch ( UsageException $e ) { + $this->assertEquals( 'imacode', $e->getApiCode() ); + $this->assertEquals( 'imamsg', $e->getRawMessage() ); + } + } + + public function testPostRequestThrowsUsageExceptionOnError() { + $client = $this->getMockClient(); + $client->expects( $this->once() ) + ->method( 'request' ) + ->will( $this->returnValue( + $this->getMockResponse( [ 'error' => [ + 'code' => 'imacode', + 'info' => 'imamsg', + ] ] ) + ) ); + $api = new MediawikiApi( '', $client ); + + try{ + $api->postRequest( new SimpleRequest( 'foo' ) ); + $this->fail( 'No Usage Exception Thrown' ); + } + catch ( UsageException $e ) { + $this->assertSame( 'imacode', $e->getApiCode() ); + $this->assertSame( 'imamsg', $e->getRawMessage() ); + } + } + + /** + * @dataProvider provideActionsParamsResults + */ + public function testGetActionReturnsResult( $expectedResult, $action, $params = [] ) { + $client = $this->getMockClient(); + $params = array_merge( [ 'action' => $action ], $params ); + $client->expects( $this->once() ) + ->method( 'request' ) + ->with( 'GET', null, $this->getExpectedRequestOpts( $params, 'query' ) ) + ->will( $this->returnValue( $this->getMockResponse( $expectedResult ) ) ); + $api = new MediawikiApi( '', $client ); + + $result = $api->getRequest( new SimpleRequest( $action, $params ) ); + + $this->assertEquals( $expectedResult, $result ); + } + + /** + * @dataProvider provideActionsParamsResults + */ + public function testPostActionReturnsResult( $expectedResult, $action, $params = [] ) { + $client = $this->getMockClient(); + $params = array_merge( [ 'action' => $action ], $params ); + $client->expects( $this->once() ) + ->method( 'request' ) + ->with( 'POST', null, $this->getExpectedRequestOpts( $params, 'form_params' ) ) + ->will( $this->returnValue( $this->getMockResponse( $expectedResult ) ) ); + $api = new MediawikiApi( '', $client ); + + $result = $api->postRequest( new SimpleRequest( $action, $params ) ); + + $this->assertEquals( $expectedResult, $result ); + } + + private function getNullFilePointer() { + if ( !file_exists( '/dev/null' ) ) { + // windows + return fopen( 'NUL', 'r' ); + } + return fopen( '/dev/null', 'r' ); + } + + public function testPostActionWithFileReturnsResult() { + $dummyFile = $this->getNullFilePointer(); + $params = [ + 'filename' => 'foo.jpg', + 'file' => $dummyFile, + ]; + $client = $this->getMockClient(); + $client->expects( $this->once() )->method( 'request' )->with( + 'POST', + null, + [ + 'multipart' => [ + [ 'name' => 'action', 'contents' => 'upload' ], + [ 'name' => 'filename', 'contents' => 'foo.jpg' ], + [ 'name' => 'file', 'contents' => $dummyFile ], + [ 'name' => 'format', 'contents' => 'json' ], + ], + 'headers' => [ 'User-Agent' => 'addwiki-mediawiki-client' ], + ] + )->will( $this->returnValue( $this->getMockResponse( [ 'success ' => 1 ] ) ) ); + $api = new MediawikiApi( '', $client ); + + $result = $api->postRequest( new SimpleRequest( 'upload', $params ) ); + + $this->assertEquals( [ 'success ' => 1 ], $result ); + } + + public function provideActionsParamsResults() { + return [ + [ [ 'key' => 'value' ], 'logout' ], + [ [ 'key' => 'value' ], 'logout', [ 'param1' => 'v1' ] ], + [ [ 'key' => 'value', 'key2' => 1212, [] ], 'logout' ], + ]; + } + + public function testGoodLoginSequence() { + $client = $this->getMockClient(); + $user = new ApiUser( 'U1', 'P1' ); + $eq1 = [ + 'action' => 'login', + 'lgname' => 'U1', + 'lgpassword' => 'P1', + ]; + $client->expects( $this->at( 0 ) ) + ->method( 'request' ) + ->with( 'POST', null, $this->getExpectedRequestOpts( $eq1, 'form_params' ) ) + ->will( $this->returnValue( $this->getMockResponse( [ 'login' => [ + 'result' => 'NeedToken', + 'token' => 'IamLoginTK', + ] ] ) ) ); + $params = array_merge( $eq1, [ 'lgtoken' => 'IamLoginTK' ] ); + $response = $this->getMockResponse( [ 'login' => [ 'result' => 'Success' ] ] ); + $client->expects( $this->at( 1 ) ) + ->method( 'request' ) + ->with( 'POST', null, $this->getExpectedRequestOpts( $params, 'form_params' ) ) + ->will( $this->returnValue( $response ) ); + $api = new MediawikiApi( '', $client ); + + $this->assertTrue( $api->login( $user ) ); + $this->assertSame( 'U1', $api->isLoggedin() ); + } + + public function testBadLoginSequence() { + $client = $this->getMockClient(); + $user = new ApiUser( 'U1', 'P1' ); + $eq1 = [ + 'action' => 'login', + 'lgname' => 'U1', + 'lgpassword' => 'P1', + ]; + $client->expects( $this->at( 0 ) ) + ->method( 'request' ) + ->with( 'POST', null, $this->getExpectedRequestOpts( $eq1, 'form_params' ) ) + ->will( $this->returnValue( $this->getMockResponse( [ 'login' => [ + 'result' => 'NeedToken', + 'token' => 'IamLoginTK', + ] ] ) ) ); + $params = array_merge( $eq1, [ 'lgtoken' => 'IamLoginTK' ] ); + $response = $this->getMockResponse( [ 'login' => [ 'result' => 'BADTOKENorsmthin' ] ] ); + $client->expects( $this->at( 1 ) ) + ->method( 'request' ) + ->with( 'POST', null, $this->getExpectedRequestOpts( $params, 'form_params' ) ) + ->will( $this->returnValue( $response ) ); + $api = new MediawikiApi( '', $client ); + + $this->setExpectedException( 'Mediawiki\Api\UsageException' ); + $api->login( $user ); + } + + public function testLogout() { + $client = $this->getMockClient(); + $client->expects( $this->at( 0 ) ) + ->method( 'request' ) + ->with( 'POST', null, $this->getExpectedRequestOpts( [ 'action' => 'logout' ], 'form_params' ) ) + ->will( $this->returnValue( $this->getMockResponse( [] ) ) ); + $api = new MediawikiApi( '', $client ); + + $this->assertTrue( $api->logout() ); + } + + public function testLogoutOnFailure() { + $client = $this->getMockClient(); + $client->expects( $this->at( 0 ) ) + ->method( 'request' ) + ->with( 'POST', null, $this->getExpectedRequestOpts( [ 'action' => 'logout' ], 'form_params' ) ) + ->will( $this->returnValue( $this->getMockResponse( null ) ) ); + $api = new MediawikiApi( '', $client ); + + $this->assertFalse( $api->logout() ); + } + + /** + * @dataProvider provideVersions + */ + public function testGetVersion( $apiValue, $expectedVersion ) { + $client = $this->getMockClient(); + $params = [ 'action' => 'query', 'meta' => 'siteinfo', 'continue' => '' ]; + $client->expects( $this->exactly( 1 ) ) + ->method( 'request' ) + ->with( 'GET', null, $this->getExpectedRequestOpts( $params, 'query' ) ) + ->will( $this->returnValue( $this->getMockResponse( [ + 'query' => [ + 'general' => [ + 'generator' => $apiValue, + ], + ], + ] ) ) ); + $api = new MediawikiApi( '', $client ); + $this->assertEquals( $expectedVersion, $api->getVersion() ); + } + + public function provideVersions() { + return [ + [ 'MediaWiki 1.25wmf13', '1.25' ], + [ 'MediaWiki 1.24.1', '1.24.1' ], + [ 'MediaWiki 1.19', '1.19' ], + [ 'MediaWiki 1.0.0', '1.0.0' ], + ]; + } +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/MediawikiSessionTest.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/MediawikiSessionTest.php new file mode 100644 index 00000000..667a526f --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/MediawikiSessionTest.php @@ -0,0 +1,95 @@ +<?php + +namespace Mediawiki\Api\Test\Unit; + +use Mediawiki\Api\MediawikiApi; +use Mediawiki\Api\MediawikiSession; +use PHPUnit_Framework_MockObject_MockObject; +use PHPUnit_Framework_TestCase; + +/** + * @author Addshore + * + * @covers Mediawiki\Api\MediawikiSession + */ +class MediawikiSessionTest extends PHPUnit_Framework_TestCase { + + /** + * @return PHPUnit_Framework_MockObject_MockObject|MediawikiApi + */ + private function getMockApi() { + return $this->getMockBuilder( '\Mediawiki\Api\MediawikiApi' ) + ->disableOriginalConstructor() + ->getMock(); + } + + public function testConstruction() { + $session = new MediawikiSession( $this->getMockApi() ); + $this->assertInstanceOf( '\Mediawiki\Api\MediawikiSession', $session ); + } + + /** + * @dataProvider provideTokenTypes + */ + public function testGetToken( $tokenType ) { + $mockApi = $this->getMockApi(); + $mockApi->expects( $this->exactly( 2 ) ) + ->method( 'postRequest' ) + ->with( $this->isInstanceOf( '\Mediawiki\Api\SimpleRequest' ) ) + ->will( $this->returnValue( [ + 'query' => [ + 'tokens' => [ + $tokenType => 'TKN-' . $tokenType, + ] + ] + ] ) ); + + $session = new MediawikiSession( $mockApi ); + + // Although we make 2 calls to the method we assert the tokens method about is only called once + $this->assertEquals( 'TKN-' . $tokenType, $session->getToken() ); + $this->assertEquals( 'TKN-' . $tokenType, $session->getToken() ); + // Then clearing the tokens and calling again should make a second call! + $session->clearTokens(); + $this->assertEquals( 'TKN-' . $tokenType, $session->getToken() ); + } + + /** + * @dataProvider provideTokenTypes + */ + public function testGetTokenPre125( $tokenType ) { + $mockApi = $this->getMockApi(); + $mockApi->expects( $this->at( 0 ) ) + ->method( 'postRequest' ) + ->with( $this->isInstanceOf( '\Mediawiki\Api\SimpleRequest' ) ) + ->will( $this->returnValue( [ + 'warnings' => [ + 'query' => [ + '*' => "Unrecognized value for parameter 'meta': tokens", + ] + ] + ] ) ); + $mockApi->expects( $this->at( 1 ) ) + ->method( 'postRequest' ) + ->with( $this->isInstanceOf( '\Mediawiki\Api\SimpleRequest' ) ) + ->will( $this->returnValue( [ + 'tokens' => [ + $tokenType => 'TKN-' . $tokenType, + ] + ] ) ); + + $session = new MediawikiSession( $mockApi ); + + // Although we make 2 calls to the method we assert the tokens method about is only called once + $this->assertSame( 'TKN-' . $tokenType, $session->getToken() ); + $this->assertSame( 'TKN-' . $tokenType, $session->getToken() ); + } + + public function provideTokenTypes() { + return [ + [ 'csrf' ], + [ 'edit' ], + ]; + } + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/MultipartRequestTest.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/MultipartRequestTest.php new file mode 100644 index 00000000..993c29e8 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/MultipartRequestTest.php @@ -0,0 +1,44 @@ +<?php + +namespace Mediawiki\Api\Test\Unit; + +use Exception; +use Mediawiki\Api\MultipartRequest; +use PHPUnit_Framework_TestCase; + +class MultipartRequestTest extends PHPUnit_Framework_TestCase { + + public function testBasics() { + $request = new MultipartRequest(); + $this->assertEquals( [], $request->getMultipartParams() ); + + // One parameter. + $request->setParam( 'testparam', 'value' ); + $request->addMultipartParams( [ 'testparam' => [ 'lorem' => 'ipsum' ] ] ); + $this->assertEquals( + [ 'testparam' => [ 'lorem' => 'ipsum' ] ], + $request->getMultipartParams() + ); + + // Another parameter. + $request->setParam( 'testparam2', 'value' ); + $request->addMultipartParams( [ 'testparam2' => [ 'lorem2' => 'ipsum2' ] ] ); + $this->assertEquals( + [ + 'testparam' => [ 'lorem' => 'ipsum' ], + 'testparam2' => [ 'lorem2' => 'ipsum2' ], + ], + $request->getMultipartParams() + ); + } + + /** + * You are not allowed to set multipart parameters on a parameter that doesn't exist. + * @expectedException Exception + * @expectedExceptionMessage Parameter 'testparam' is not already set on this request. + */ + public function testParamNotYetSet() { + $request = new MultipartRequest(); + $request->addMultipartParams( [ 'testparam' => [] ] ); + } +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/SimpleRequestTest.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/SimpleRequestTest.php new file mode 100644 index 00000000..df979992 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/SimpleRequestTest.php @@ -0,0 +1,49 @@ +<?php + +namespace Mediawiki\Api\Test\Unit; + +use Mediawiki\Api\SimpleRequest; +use PHPUnit_Framework_TestCase; + +/** + * @author Addshore + * + * @covers Mediawiki\Api\SimpleRequest + */ +class SimpleRequestTest extends PHPUnit_Framework_TestCase { + + /** + * @dataProvider provideValidConstruction + */ + public function testValidConstruction( $action, $params, $expected, $headers = [] ) { + $request = new SimpleRequest( $action, $params, $headers ); + $this->assertEquals( $expected, $request->getParams() ); + $this->assertEquals( $headers, $request->getHeaders() ); + } + + public function provideValidConstruction() { + return [ + [ 'action', [], [ 'action' => 'action' ] ], + [ '1123', [], [ 'action' => '1123' ] ], + [ 'a', [ 'b' => 'c' ], [ 'action' => 'a', 'b' => 'c' ] ], + [ 'a', [ 'b' => 'c', 'd' => 'e' ], [ 'action' => 'a', 'b' => 'c', 'd' => 'e' ] ], + [ 'a', [ 'b' => 'c|d|e|f' ], [ 'action' => 'a', 'b' => 'c|d|e|f' ] ], + [ 'foo', [], [ 'action' => 'foo' ] ,[ 'foo' => 'bar' ] ], + ]; + } + + /** + * @dataProvider provideInvalidConstruction + */ + public function testInvalidConstruction( $action, $params ) { + $this->setExpectedException( 'InvalidArgumentException' ); + new SimpleRequest( $action, $params ); + } + + public function provideInvalidConstruction() { + return [ + [ [], [] ], + ]; + } + +} diff --git a/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/UsageExceptionTest.php b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/UsageExceptionTest.php new file mode 100644 index 00000000..2b7d6072 --- /dev/null +++ b/bin/reevotech/vendor/addwiki/mediawiki-api-base/tests/Unit/UsageExceptionTest.php @@ -0,0 +1,39 @@ +<?php + +namespace Mediawiki\Api\Test\Unit; + +use Mediawiki\Api\UsageException; +use PHPUnit_Framework_TestCase; + +/** + * @author Addshore + * + * @covers Mediawiki\Api\UsageException + */ +class UsageExceptionTest extends PHPUnit_Framework_TestCase { + + public function testUsageExceptionWithNoParams() { + $e = new UsageException(); + $this->assertSame( + 'Code: ' . PHP_EOL . + 'Message: ' . PHP_EOL . + 'Result: []', + $e->getMessage() + ); + $this->assertSame( '', $e->getApiCode() ); + $this->assertEquals( [], $e->getApiResult() ); + } + + public function testUsageExceptionWithParams() { + $e = new UsageException( 'imacode', 'imamsg', [ 'foo' => 'bar' ] ); + $this->assertSame( 'imacode', $e->getApiCode() ); + $this->assertSame( + 'Code: imacode' . PHP_EOL . + 'Message: imamsg' . PHP_EOL . + 'Result: {"foo":"bar"}', + $e->getMessage() + ); + $this->assertEquals( [ 'foo' => 'bar' ], $e->getApiResult() ); + } + +} |