Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiEchoMute
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 9
506
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
72
 lookupIds
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
56
 parsePref
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 serializePref
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAllowedParams
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
2
 needsToken
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 mustBePosted
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isWriteMode
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Extension\Notifications\Api;
4
5use ApiBase;
6use ApiMain;
7use MediaWiki\Cache\LinkBatchFactory;
8use MediaWiki\Title\Title;
9use MediaWiki\User\CentralId\CentralIdLookup;
10use MediaWiki\User\Options\UserOptionsManager;
11use Wikimedia\ParamValidator\ParamValidator;
12
13class ApiEchoMute extends ApiBase {
14
15    /** @var CentralIdLookup */
16    private $centralIdLookup;
17
18    /** @var LinkBatchFactory */
19    private $linkBatchFactory;
20
21    /** @var UserOptionsManager */
22    private $userOptionsManager;
23
24    /** @var string[][] */
25    private const MUTE_LISTS = [
26        'user' => [
27            'pref' => 'echo-notifications-blacklist',
28            'type' => 'user',
29        ],
30        'page-linked-title' => [
31            'pref' => 'echo-notifications-page-linked-title-muted-list',
32            'type' => 'title'
33        ],
34    ];
35
36    /**
37     * @param ApiMain $main
38     * @param string $action
39     * @param CentralIdLookup $centralIdLookup
40     * @param LinkBatchFactory $linkBatchFactory
41     * @param UserOptionsManager $userOptionsManager
42     */
43    public function __construct(
44        ApiMain $main,
45        $action,
46        CentralIdLookup $centralIdLookup,
47        LinkBatchFactory $linkBatchFactory,
48        UserOptionsManager $userOptionsManager
49    ) {
50        parent::__construct( $main, $action );
51
52        $this->centralIdLookup = $centralIdLookup;
53        $this->linkBatchFactory = $linkBatchFactory;
54        $this->userOptionsManager = $userOptionsManager;
55    }
56
57    public function execute() {
58        $user = $this->getUser();
59        if ( !$user || !$user->isRegistered() ) {
60            $this->dieWithError(
61                [ 'apierror-mustbeloggedin', $this->msg( 'action-editmyoptions' ) ],
62                'notloggedin'
63            );
64        }
65
66        $this->checkUserRightsAny( 'editmyoptions' );
67
68        $params = $this->extractRequestParams();
69        $mutelistInfo = self::MUTE_LISTS[ $params['type'] ];
70        $prefValue = $this->userOptionsManager->getOption( $user, $mutelistInfo['pref'] );
71        $ids = $this->parsePref( $prefValue );
72        $targetsToMute = $params['mute'] ?? [];
73        $targetsToUnmute = $params['unmute'] ?? [];
74
75        $changed = false;
76        $addIds = $this->lookupIds( $targetsToMute, $mutelistInfo['type'] );
77        foreach ( $addIds as $id ) {
78            if ( !in_array( $id, $ids ) ) {
79                $ids[] = $id;
80                $changed = true;
81            }
82        }
83        $removeIds = $this->lookupIds( $targetsToUnmute, $mutelistInfo['type'] );
84        foreach ( $removeIds as $id ) {
85            $index = array_search( $id, $ids );
86            if ( $index !== false ) {
87                array_splice( $ids, $index, 1 );
88                $changed = true;
89            }
90        }
91
92        if ( $changed ) {
93            $this->userOptionsManager->setOption(
94                $user,
95                $mutelistInfo['pref'],
96                $this->serializePref( $ids )
97            );
98            $this->userOptionsManager->saveOptions( $user );
99        }
100
101        $this->getResult()->addValue( null, $this->getModuleName(), 'success' );
102    }
103
104    private function lookupIds( $names, $type ) {
105        if ( $type === 'title' ) {
106            $linkBatch = $this->linkBatchFactory->newLinkBatch();
107            foreach ( $names as $name ) {
108                $linkBatch->addObj( Title::newFromText( $name ) );
109            }
110            $linkBatch->execute();
111
112            $ids = [];
113            foreach ( $names as $name ) {
114                $title = Title::newFromText( $name );
115                if ( $title instanceof Title && $title->getArticleID() > 0 ) {
116                    $ids[] = $title->getArticleID();
117                }
118            }
119            return $ids;
120        } elseif ( $type === 'user' ) {
121            return $this->centralIdLookup->centralIdsFromNames( $names, CentralIdLookup::AUDIENCE_PUBLIC );
122        }
123    }
124
125    private function parsePref( $prefValue ) {
126        return preg_split( '/\n/', $prefValue, -1, PREG_SPLIT_NO_EMPTY );
127    }
128
129    private function serializePref( $ids ) {
130        return implode( "\n", $ids );
131    }
132
133    public function getAllowedParams( $flags = 0 ) {
134        return [
135            'type' => [
136                ParamValidator::PARAM_REQUIRED => true,
137                ParamValidator::PARAM_TYPE => array_keys( self::MUTE_LISTS ),
138            ],
139            'mute' => [
140                ParamValidator::PARAM_ISMULTI => true,
141            ],
142            'unmute' => [
143                ParamValidator::PARAM_ISMULTI => true,
144            ]
145        ];
146    }
147
148    public function needsToken() {
149        return 'csrf';
150    }
151
152    public function mustBePosted() {
153        return true;
154    }
155
156    public function isWriteMode() {
157        return true;
158    }
159
160}