Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
79.49% covered (warning)
79.49%
31 / 39
33.33% covered (danger)
33.33%
1 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiZObjectEditor
79.49% covered (warning)
79.49%
31 / 39
33.33% covered (danger)
33.33%
1 / 3
15.69
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 run
80.56% covered (warning)
80.56%
29 / 36
0.00% covered (danger)
0.00%
0 / 1
7.36
 mustBePosted
n/a
0 / 0
n/a
0 / 0
1
 isWriteMode
n/a
0 / 0
n/a
0 / 0
1
 needsToken
n/a
0 / 0
n/a
0 / 0
1
 isInternal
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAllowedParams
n/a
0 / 0
n/a
0 / 0
1
 getExamplesMessages
n/a
0 / 0
n/a
0 / 0
1
1<?php
2/**
3 * WikiLambda ZObject creating/editing API
4 *
5 * @file
6 * @ingroup Extensions
7 * @copyright 2020– Abstract Wikipedia team; see AUTHORS.txt
8 * @license MIT
9 */
10
11namespace MediaWiki\Extension\WikiLambda\ActionAPI;
12
13use MediaWiki\Api\ApiMain;
14use MediaWiki\Extension\WikiLambda\HttpStatus;
15use MediaWiki\Extension\WikiLambda\Registry\ZErrorTypeRegistry;
16use MediaWiki\Extension\WikiLambda\Registry\ZTypeRegistry;
17use MediaWiki\Extension\WikiLambda\WikiLambdaServices;
18use MediaWiki\Extension\WikiLambda\ZErrorFactory;
19use MediaWiki\Title\Title;
20use Wikimedia\ParamValidator\ParamValidator;
21
22class ApiZObjectEditor extends WikiLambdaApiBase {
23
24    public function __construct( ApiMain $mainModule, string $moduleName ) {
25        parent::__construct( $mainModule, $moduleName );
26
27        $this->setUp();
28    }
29
30    /**
31     * @inheritDoc
32     */
33    protected function run(): void {
34        // Exit if we're running in non-repo mode (e.g. on a client wiki)
35        if ( !$this->getConfig()->get( 'WikiLambdaEnableRepoMode' ) ) {
36            WikiLambdaApiBase::dieWithZError(
37                ZErrorFactory::createZErrorInstance(
38                    ZErrorTypeRegistry::Z_ERROR_USER_CANNOT_RUN,
39                    []
40                ),
41                HttpStatus::BAD_REQUEST
42            );
43        }
44
45        $user = $this->getUser();
46        $params = $this->extractRequestParams();
47
48        $summary = $params[ 'summary' ];
49        $zobject = $params[ 'zobject' ];
50
51        // If zid is set, we should be editing it, if empty or Z0, we are creating a new zobject
52        $zid = $params[ 'zid' ];
53
54        $zObjectStore = WikiLambdaServices::getZObjectStore();
55
56        if ( !$zid || $zid === ZTypeRegistry::Z_NULL_REFERENCE ) {
57            // Create a new ZObject
58            $response = $zObjectStore->createNewZObject( $this, $zobject, $summary, $user );
59        } else {
60            // Check if the ZObject exists (i.e. someone's making an edit), and pass the correct edit flag
61            if ( Title::newFromText( $zid )->exists() ) {
62                $editFlag = EDIT_UPDATE;
63            } else {
64                // … but only for very-priviledged users, as this can cause major issues if e.g. Z99999999 was created
65                if ( !$user->isAllowed( 'wikilambda-create-arbitrary-zid' ) ) {
66                    $zError = ZErrorFactory::createAuthorizationZError( 'wikilambda-edit', EDIT_NEW );
67                    WikiLambdaApiBase::dieWithZError( $zError, HttpStatus::FORBIDDEN );
68                }
69                $editFlag = EDIT_NEW;
70            }
71
72            // Edit an existing ZObject
73            $response = $zObjectStore->updateZObject( $this, $zid, $zobject, $summary, $user, $editFlag );
74        }
75
76        if ( !$response->isOK() ) {
77            WikiLambdaApiBase::dieWithZError( $response->getErrors(), HttpStatus::BAD_REQUEST );
78        }
79
80        $title = $response->getTitle();
81        $this->getResult()->addValue(
82            null,
83            $this->getModuleName(),
84            [
85                'success' => true,
86                'articleId' => $title->getArticleID(),
87                'title' => $title->getBaseText(),
88                'page' => $title->getBaseTitle()
89            ]
90        );
91    }
92
93    /**
94     * @inheritDoc
95     * @codeCoverageIgnore
96     */
97    public function mustBePosted() {
98        return true;
99    }
100
101    /**
102     * @inheritDoc
103     * @codeCoverageIgnore
104     */
105    public function isWriteMode() {
106        return true;
107    }
108
109    /**
110     * @see ApiBase::needsToken
111     * @return string
112     * @codeCoverageIgnore
113     */
114    public function needsToken(): string {
115        return 'csrf';
116    }
117
118    /**
119     * Mark as internal. This isn't meant to be user-facing, and can change at any time.
120     * @return bool
121     */
122    public function isInternal() {
123        return true;
124    }
125
126    /**
127     * @inheritDoc
128     * @codeCoverageIgnore
129     */
130    protected function getAllowedParams(): array {
131        return [
132            'summary' => [
133                ParamValidator::PARAM_TYPE => 'string',
134                ParamValidator::PARAM_REQUIRED => false,
135                ParamValidator::PARAM_DEFAULT => '',
136            ],
137            'zid' => [
138                ParamValidator::PARAM_TYPE => 'string',
139                ParamValidator::PARAM_REQUIRED => false,
140                ParamValidator::PARAM_DEFAULT => null,
141            ],
142            'zobject' => [
143                ParamValidator::PARAM_TYPE => 'text',
144                ParamValidator::PARAM_REQUIRED => true,
145            ]
146        ];
147    }
148
149    /**
150     * @see ApiBase::getExamplesMessages()
151     * @return array
152     * @codeCoverageIgnore
153     */
154    protected function getExamplesMessages() {
155        return [
156            'action=wikilambda_edit&format=json&summary=New%20zobject&zobject='
157                . urlencode( '{"Z1K1":"Z2","Z2K1":{"Z1K1":"Z6","Z6K1":"Z0"},"Z2K2":"string value",'
158                . '"Z2K3":{"Z1K1":"Z12","Z12K1":["Z11", {"Z1K1":"Z11","Z11K1":"Z1002","Z11K2":"label"}]}}' )
159            => 'apihelp-wikilambda_edit-example-create',
160            'action=wikilambda_edit&format=json&summary=Edit%20zobject&zid=Z01&zobject='
161                . urlencode( '{"Z1K1":"Z2","Z2K1":{"Z1K1":"Z6","Z6K1":"Z01"},"Z2K2":"string value"}' )
162            => 'apihelp-wikilambda_edit-example-edit-incorrect'
163        ];
164    }
165}