summaryrefslogtreecommitdiff
path: root/bin/wiki/vendor/addwiki/mediawiki-api-base
diff options
context:
space:
mode:
Diffstat (limited to 'bin/wiki/vendor/addwiki/mediawiki-api-base')
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/.gitignore6
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/.phan/config.php40
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/.scrutinizer.yml13
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/.travis.yml61
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/LICENSE.md264
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/README.md16
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/RELEASENOTES.md95
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/build/travis/install-mediawiki.sh29
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/build/travis/run-webserver.sh25
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/composer.json52
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/docs/Makefile225
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/docs/conf.py80
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/docs/index.rst17
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/docs/make.bat281
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/docs/multipart.rst28
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/docs/overview.rst129
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/docs/quickstart.rst87
-rwxr-xr-xbin/wiki/vendor/addwiki/mediawiki-api-base/phpcs.xml6
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/phpunit.xml.dist16
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/src/ApiRequester.php31
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/src/ApiUser.php90
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/src/AsyncApiRequester.php37
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/src/FluentRequest.php118
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle/ClientFactory.php96
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle/MiddlewareFactory.php158
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/src/MediawikiApi.php507
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/src/MediawikiApiInterface.php60
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/src/MediawikiSession.php168
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/src/MultipartRequest.php77
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/src/Request.php30
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/src/RsdException.php12
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/src/SimpleRequest.php61
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/src/UsageException.php75
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Integration/MediawikiApiTest.php103
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Integration/TestEnvironment.php92
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Integration/TokenHandlingTest.php28
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/ApiUserTest.php71
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/FluentRequestTest.php69
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/Guzzle/ClientFactoryTest.php91
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/Guzzle/MiddlewareFactoryTest.php214
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/MediawikiApiTest.php296
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/MediawikiSessionTest.php95
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/MultipartRequestTest.php44
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/SimpleRequestTest.php49
-rw-r--r--bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/UsageExceptionTest.php39
45 files changed, 4181 insertions, 0 deletions
diff --git a/bin/wiki/vendor/addwiki/mediawiki-api-base/.gitignore b/bin/wiki/vendor/addwiki/mediawiki-api-base/.gitignore
new file mode 100644
index 00000000..9c16bff2
--- /dev/null
+++ b/bin/wiki/vendor/addwiki/mediawiki-api-base/.gitignore
@@ -0,0 +1,6 @@
+.idea
+vendor
+composer.lock
+test.php
+docs/_build
+phpunit.xml
diff --git a/bin/wiki/vendor/addwiki/mediawiki-api-base/.phan/config.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/.phan/config.php
new file mode 100644
index 00000000..28c1f4ad
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/.scrutinizer.yml b/bin/wiki/vendor/addwiki/mediawiki-api-base/.scrutinizer.yml
new file mode 100644
index 00000000..ffc976e3
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/.travis.yml b/bin/wiki/vendor/addwiki/mediawiki-api-base/.travis.yml
new file mode 100644
index 00000000..cb3e7641
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/LICENSE.md b/bin/wiki/vendor/addwiki/mediawiki-api-base/LICENSE.md
new file mode 100644
index 00000000..0671f06a
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/README.md b/bin/wiki/vendor/addwiki/mediawiki-api-base/README.md
new file mode 100644
index 00000000..ea2a7d4b
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/RELEASENOTES.md b/bin/wiki/vendor/addwiki/mediawiki-api-base/RELEASENOTES.md
new file mode 100644
index 00000000..a84b19cc
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/build/travis/install-mediawiki.sh b/bin/wiki/vendor/addwiki/mediawiki-api-base/build/travis/install-mediawiki.sh
new file mode 100644
index 00000000..59d29ba4
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/build/travis/run-webserver.sh b/bin/wiki/vendor/addwiki/mediawiki-api-base/build/travis/run-webserver.sh
new file mode 100644
index 00000000..2412031c
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/composer.json b/bin/wiki/vendor/addwiki/mediawiki-api-base/composer.json
new file mode 100644
index 00000000..c83fca09
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/docs/Makefile b/bin/wiki/vendor/addwiki/mediawiki-api-base/docs/Makefile
new file mode 100644
index 00000000..54002b3b
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/docs/conf.py b/bin/wiki/vendor/addwiki/mediawiki-api-base/docs/conf.py
new file mode 100644
index 00000000..cb3ce592
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/docs/index.rst b/bin/wiki/vendor/addwiki/mediawiki-api-base/docs/index.rst
new file mode 100644
index 00000000..ac4860ce
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/docs/make.bat b/bin/wiki/vendor/addwiki/mediawiki-api-base/docs/make.bat
new file mode 100644
index 00000000..7ce5e397
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/docs/multipart.rst b/bin/wiki/vendor/addwiki/mediawiki-api-base/docs/multipart.rst
new file mode 100644
index 00000000..1b438c71
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/docs/overview.rst b/bin/wiki/vendor/addwiki/mediawiki-api-base/docs/overview.rst
new file mode 100644
index 00000000..0e83549d
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/docs/quickstart.rst b/bin/wiki/vendor/addwiki/mediawiki-api-base/docs/quickstart.rst
new file mode 100644
index 00000000..5db0601f
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/phpcs.xml b/bin/wiki/vendor/addwiki/mediawiki-api-base/phpcs.xml
new file mode 100755
index 00000000..c4ca4081
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/phpunit.xml.dist b/bin/wiki/vendor/addwiki/mediawiki-api-base/phpunit.xml.dist
new file mode 100644
index 00000000..a5874032
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/src/ApiRequester.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/ApiRequester.php
new file mode 100644
index 00000000..cc3c8bcf
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/src/ApiUser.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/ApiUser.php
new file mode 100644
index 00000000..b2f59153
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/src/AsyncApiRequester.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/AsyncApiRequester.php
new file mode 100644
index 00000000..6190ac7e
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/src/FluentRequest.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/FluentRequest.php
new file mode 100644
index 00000000..0d10553b
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle/ClientFactory.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle/ClientFactory.php
new file mode 100644
index 00000000..704a1660
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle/MiddlewareFactory.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle/MiddlewareFactory.php
new file mode 100644
index 00000000..9e03c02f
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/src/MediawikiApi.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/MediawikiApi.php
new file mode 100644
index 00000000..0c6c4fe3
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/src/MediawikiApiInterface.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/MediawikiApiInterface.php
new file mode 100644
index 00000000..83580676
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/src/MediawikiSession.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/MediawikiSession.php
new file mode 100644
index 00000000..c430695c
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/src/MultipartRequest.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/MultipartRequest.php
new file mode 100644
index 00000000..8d3fbdf4
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/src/Request.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/Request.php
new file mode 100644
index 00000000..0daace2a
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/src/RsdException.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/RsdException.php
new file mode 100644
index 00000000..b304f574
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/src/SimpleRequest.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/SimpleRequest.php
new file mode 100644
index 00000000..1e33348d
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/src/UsageException.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/UsageException.php
new file mode 100644
index 00000000..77148f1b
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/tests/Integration/MediawikiApiTest.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Integration/MediawikiApiTest.php
new file mode 100644
index 00000000..da6683e4
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/tests/Integration/TestEnvironment.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Integration/TestEnvironment.php
new file mode 100644
index 00000000..cb781508
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/tests/Integration/TokenHandlingTest.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Integration/TokenHandlingTest.php
new file mode 100644
index 00000000..68ec52be
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/ApiUserTest.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/ApiUserTest.php
new file mode 100644
index 00000000..7e0da7ca
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/FluentRequestTest.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/FluentRequestTest.php
new file mode 100644
index 00000000..93af921e
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/Guzzle/ClientFactoryTest.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/Guzzle/ClientFactoryTest.php
new file mode 100644
index 00000000..d84d0333
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/Guzzle/MiddlewareFactoryTest.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/Guzzle/MiddlewareFactoryTest.php
new file mode 100644
index 00000000..1cf7270a
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/MediawikiApiTest.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/MediawikiApiTest.php
new file mode 100644
index 00000000..a55f6739
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/MediawikiSessionTest.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/MediawikiSessionTest.php
new file mode 100644
index 00000000..667a526f
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/MultipartRequestTest.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/MultipartRequestTest.php
new file mode 100644
index 00000000..993c29e8
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/SimpleRequestTest.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/SimpleRequestTest.php
new file mode 100644
index 00000000..df979992
--- /dev/null
+++ b/bin/wiki/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/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/UsageExceptionTest.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/tests/Unit/UsageExceptionTest.php
new file mode 100644
index 00000000..2b7d6072
--- /dev/null
+++ b/bin/wiki/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() );
+ }
+
+}