Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
ReviewTranslationActionApi.php
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\TranslatorInterface;
5
6use ApiBase;
7use ApiMain;
8use ManualLogEntry;
11use MediaWiki\Revision\RevisionLookup;
12use MediaWiki\Revision\RevisionRecord;
13use MediaWiki\Status\Status;
14use MediaWiki\User\User;
15use TitleFormatter;
16use Wikimedia\ParamValidator\ParamValidator;
17use Wikimedia\Rdbms\ILoadBalancer;
18
25class ReviewTranslationActionApi extends ApiBase {
26 protected static $right = 'translate-messagereview';
27 private RevisionLookup $revisionLookup;
28 private TitleFormatter $titleFormatter;
29 private ILoadBalancer $loadBalancer;
30 private HookRunner $hookRunner;
31
32 public function __construct(
33 ApiMain $main,
34 string $moduleName,
35 RevisionLookup $revisionLookup,
36 TitleFormatter $titleFormatter,
37 ILoadBalancer $loadBalancer,
38 HookRunner $hookRunner
39 ) {
40 parent::__construct( $main, $moduleName );
41 $this->revisionLookup = $revisionLookup;
42 $this->titleFormatter = $titleFormatter;
43 $this->loadBalancer = $loadBalancer;
44 $this->hookRunner = $hookRunner;
45 }
46
47 public function execute() {
48 $this->checkUserRightsAny( self::$right );
49
50 $params = $this->extractRequestParams();
51
52 $revRecord = $this->revisionLookup->getRevisionById( $params['revision'] );
53 if ( !$revRecord ) {
54 $this->dieWithError( [ 'apierror-nosuchrevid', $params['revision'] ], 'invalidrevision' );
55 }
56
57 $status = $this->getReviewBlockers( $this->getUser(), $revRecord );
58 if ( !$status->isGood() ) {
59 if ( $status->hasMessage( 'blocked' ) ) {
60 $this->dieBlocked( $this->getUser()->getBlock() );
61 } else {
62 $this->dieStatus( $status );
63 }
64 }
65
66 $ok = $this->doReview( $this->getUser(), $revRecord );
67 if ( !$ok ) {
68 $this->addWarning( 'apiwarn-translate-alreadyreviewedbyyou' );
69 }
70
71 $prefixedText = $this->titleFormatter->getPrefixedText( $revRecord->getPageAsLinkTarget() );
72 $output = [ 'review' => [
73 'title' => $prefixedText,
74 'pageid' => $revRecord->getPageId(),
75 'revision' => $revRecord->getId()
76 ] ];
77
78 $this->getResult()->addValue( null, $this->getModuleName(), $output );
79 }
80
85 private function doReview( User $user, RevisionRecord $revRecord ): bool {
86 $dbw = $this->loadBalancer->getConnection( DB_PRIMARY );
87 $table = 'translate_reviews';
88 $row = [
89 'trr_user' => $user->getId(),
90 'trr_page' => $revRecord->getPageId(),
91 'trr_revision' => $revRecord->getId(),
92 ];
93 $options = [ 'IGNORE' ];
94 $dbw->insert( $table, $row, __METHOD__, $options );
95
96 if ( !$dbw->affectedRows() ) {
97 return false;
98 }
99
100 $title = $revRecord->getPageAsLinkTarget();
101
102 $entry = new ManualLogEntry( 'translationreview', 'message' );
103 $entry->setPerformer( $user );
104 $entry->setTarget( $title );
105 $entry->setParameters( [
106 '4::revision' => $revRecord->getId(),
107 ] );
108
109 $logid = $entry->insert();
110 $entry->publish( $logid );
111
112 $handle = new MessageHandle( $title );
113 $this->hookRunner->onTranslateEventTranslationReview( $handle );
114
115 return true;
116 }
117
122 private function getReviewBlockers( User $user, RevisionRecord $revRecord ): Status {
123 if ( !$user->isAllowed( self::$right ) ) {
124 return Status::newFatal( 'apierror-permissiondenied-generic' );
125 }
126
127 if ( $user->getBlock() ) {
128 return Status::newFatal( 'blocked' );
129 }
130
131 $title = $revRecord->getPageAsLinkTarget();
132 $handle = new MessageHandle( $title );
133 if ( !$handle->isValid() ) {
134 return Status::newFatal( 'apierror-translate-unknownmessage' );
135 }
136
137 if ( $user->equals( $revRecord->getUser() ) ) {
138 return Status::newFatal( 'apierror-translate-owntranslation' );
139 }
140
141 if ( $handle->isFuzzy() ) {
142 return Status::newFatal( 'apierror-translate-fuzzymessage' );
143 }
144
145 return Status::newGood();
146 }
147
148 public function isWriteMode(): bool {
149 return true;
150 }
151
152 public function needsToken(): string {
153 return 'csrf';
154 }
155
156 protected function getAllowedParams(): array {
157 return [
158 'revision' => [
159 ParamValidator::PARAM_TYPE => 'integer',
160 ParamValidator::PARAM_REQUIRED => true,
161 ],
162 'token' => [
163 ParamValidator::PARAM_TYPE => 'string',
164 ParamValidator::PARAM_REQUIRED => true,
165 ],
166 ];
167 }
168
169 protected function getExamplesMessages(): array {
170 return [
171 'action=translationreview&revision=1&token=foo'
172 => 'apihelp-translationreview-example-1',
173 ];
174 }
175}
Hook runner for the Translate extension.
Class for pointing to messages, like Title class is for titles.