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