Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 77
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
ManageGroupSynchronizationCacheActionApi
0.00% covered (danger)
0.00%
0 / 77
0.00% covered (danger)
0.00%
0 / 6
210
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
72
 markAsResolved
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
6
 getAllowedParams
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
2
 isInternal
0.00% covered (danger)
0.00%
0 / 1
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
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\Synchronization;
5
6use ApiBase;
7use ApiMain;
8use Exception;
9use FormatJson;
10use MediaWiki\Extension\Translate\MessageGroupProcessing\MessageGroups;
11use MediaWiki\Logger\LoggerFactory;
12use Psr\Log\LoggerInterface;
13use Wikimedia\ParamValidator\ParamValidator;
14
15/**
16 * Api module for managing group synchronization cache
17 * @ingroup API TranslateAPI
18 * @since 2021.03
19 * @author Abijeet Patro
20 * @license GPL-2.0-or-later
21 */
22class ManageGroupSynchronizationCacheActionApi extends ApiBase {
23    private const RIGHT = 'translate-manage';
24    private const VALID_OPS = [ 'resolveMessage', 'resolveGroup' ];
25    /** @var GroupSynchronizationCache */
26    private $groupSyncCache;
27    /** @var LoggerInterface */
28    private $groupSyncLog;
29
30    public function __construct( ApiMain $mainModule, $moduleName, GroupSynchronizationCache $groupSyncCache ) {
31        parent::__construct( $mainModule, $moduleName );
32        $this->groupSyncCache = $groupSyncCache;
33        $this->groupSyncLog = LoggerFactory::getInstance( 'Translate.GroupSynchronization' );
34    }
35
36    public function execute() {
37        $this->checkUserRightsAny( self::RIGHT );
38        $block = $this->getUser()->getBlock();
39        if ( $block && $block->isSitewide() ) {
40            $this->dieBlocked( $block );
41        }
42
43        $params = $this->extractRequestParams();
44        $operation = $params['operation'];
45        $groupId = $params['group'];
46        $titleStr = $params['title'] ?? null;
47
48        $group = MessageGroups::getGroup( $groupId );
49        if ( $group === null ) {
50            $this->dieWithError( 'apierror-translate-invalidgroup', 'invalidgroup' );
51        }
52
53        try {
54            if ( $operation === 'resolveMessage' ) {
55                if ( $titleStr === null ) {
56                    $this->dieWithError( [ 'apierror-missingparam', 'title' ] );
57                }
58                $this->markAsResolved( $groupId, $titleStr );
59            } elseif ( $operation === 'resolveGroup' ) {
60                $this->markAsResolved( $groupId );
61            }
62        } catch ( Exception $e ) {
63            $data = [
64                'requestParams' => $params,
65                'exceptionMessage' => $e->getMessage()
66            ];
67
68            $this->groupSyncLog->error(
69                "Error while running: ManageGroupSynchronizationCacheActionApi::execute. Details: \n" .
70                FormatJson::encode( $data, true )
71            );
72
73            $this->dieWithError(
74                [
75                    'apierror-translate-operation-error',
76                    wfEscapeWikiText( $e->getMessage() )
77                ]
78            );
79        }
80    }
81
82    private function markAsResolved( string $groupId, ?string $messageTitle = null ): void {
83        if ( $messageTitle === null ) {
84            $currentGroupStatus = $this->groupSyncCache->markGroupAsResolved( $groupId );
85            $this->groupSyncLog->info(
86                '{user} resolved group {groupId}.',
87                [
88                    'user' => $this->getUser()->getName(),
89                    'groupId' => $groupId
90                ]
91            );
92        } else {
93            $this->groupSyncCache->markMessageAsResolved( $groupId, $messageTitle );
94            $currentGroupStatus = $this->groupSyncCache->syncGroupErrors( $groupId );
95            $this->groupSyncLog->info(
96                '{user} resolved message {messageTitle} in group {groupId}.',
97                [
98                    'user' => $this->getUser()->getName(),
99                    'groupId' => $groupId,
100                    'messageTitle' => $messageTitle
101                ]
102            );
103        }
104
105        $this->getResult()->addValue( null, $this->getModuleName(), [
106            'success' => 1,
107            'data' => [
108                'groupRemainingMessageCount' => count( $currentGroupStatus->getRemainingMessages() )
109            ]
110        ] );
111    }
112
113    protected function getAllowedParams() {
114        return [
115            'operation' => [
116                ParamValidator::PARAM_TYPE => self::VALID_OPS,
117                ParamValidator::PARAM_ISMULTI => false,
118                ParamValidator::PARAM_REQUIRED => true,
119            ],
120            'title' => [
121                ParamValidator::PARAM_TYPE => 'string',
122                ParamValidator::PARAM_REQUIRED => false
123            ],
124            'group' => [
125                ParamValidator::PARAM_TYPE => 'string',
126                ParamValidator::PARAM_REQUIRED => true
127            ]
128        ];
129    }
130
131    public function isInternal() {
132        return true;
133    }
134
135    public function needsToken() {
136        return 'csrf';
137    }
138}