28 private JobQueueGroup $jobQueueGroup;
29 protected static string $right =
'translate-manage';
33 public function __construct(
36 JobQueueGroup $jobQueueGroup,
40 parent::__construct( $main, $action );
41 $this->jobQueueGroup = $jobQueueGroup;
42 $this->messageGroupMetadata = $messageGroupMetadata;
43 $this->aggregateGroupManager = $aggregateGroupManager;
46 public function execute():
void {
47 $this->checkUserRightsAny( self::$right );
48 $block = $this->getUser()->getBlock();
49 if ( $block && $block->isSitewide() ) {
50 $this->dieBlocked( $block );
53 $params = $this->extractRequestParams();
54 $action = $params[
'do'];
56 if ( $action ===
'associate' || $action ===
'dissociate' ) {
58 $this->requireOnlyOneParameter( $params,
'group',
'groups' );
60 if ( isset( $params[
'groups'] ) ) {
61 $subgroupIds = array_map(
'trim', $params[
'groups'] );
63 $subgroupIds = [ $params[
'group'] ];
66 if ( !isset( $params[
'aggregategroup'] ) ) {
67 $this->dieWithError( [
'apierror-missingparam',
'aggregategroup' ] );
70 $aggregateGroupId = $params[
'aggregategroup'];
73 if ( $action ===
'associate' ) {
75 $groupIdsToLog = $this->aggregateGroupManager->associate( $aggregateGroupId, $subgroupIds );
76 $output[
'groupUrls'] = [];
77 foreach ( $groupIdsToLog as $subgroupId ) {
78 $output[
'groupUrls'][ $subgroupId ] =
79 $this->aggregateGroupManager->getTargetTitleByGroupId( $subgroupId )->getFullURL();
82 $groupIdsToLog = $this->aggregateGroupManager->disassociate( $aggregateGroupId, $subgroupIds );
89 $this->dieWithException( $e );
93 'aggregategroup' => $this->messageGroupMetadata->get( $aggregateGroupId,
'name' ),
94 'aggregategroup-id' => $aggregateGroupId,
97 foreach ( $groupIdsToLog as $subgroupId ) {
98 $title = $this->aggregateGroupManager->getTargetTitleByGroupId( $subgroupId );
99 $entry =
new ManualLogEntry(
'pagetranslation', $action );
100 $entry->setPerformer( $this->getUser() );
101 $entry->setTarget( $title );
102 $entry->setParameters( $logParams );
104 $logId = $entry->insert();
105 $entry->publish( $logId );
107 } elseif ( $action ===
'remove' ) {
108 if ( !isset( $params[
'aggregategroup'] ) ) {
109 $this->dieWithError( [
'apierror-missingparam',
'aggregategroup' ] );
112 $aggregateGroupId = $params[
'aggregategroup'];
116 'apierror-translate-invalidaggregategroupname',
117 'invalidaggregategroupname'
121 $this->messageGroupMetadata->deleteGroup( $params[
'aggregategroup'] );
124 'Aggregate group {groupId} has been deleted.',
125 [
'groupId' => $aggregateGroupId ]
127 } elseif ( $action ===
'add' ) {
128 if ( !isset( $params[
'groupname'] ) ) {
129 $this->dieWithError( [
'apierror-missingparam',
'groupname' ] );
131 $name = trim( $params[
'groupname'] );
132 if ( strlen( $name ) === 0 ) {
134 'apierror-translate-invalidaggregategroupname',
135 'invalidaggregategroupname'
139 $desc = trim( $params[
'groupdescription'] );
140 $languageCode = trim( $params[
'groupsourcelanguagecode'] );
141 $languageCode = $languageCode === AggregateMessageGroup::UNDETERMINED_LANGUAGE_CODE ?
142 null : $languageCode;
144 $aggregateGroupId = $this->aggregateGroupManager->add( $name, $desc, $languageCode );
146 $this->dieWithException( $e );
150 $output[
'groups'] = $this->getIncludableGroups();
151 $output[
'aggregategroupId'] = $aggregateGroupId;
153 } elseif ( $action ===
'update' ) {
154 if ( !isset( $params[
'groupname'] ) ) {
155 $this->dieWithError( [
'apierror-missingparam',
'groupname' ] );
157 $name = trim( $params[
'groupname'] );
158 if ( strlen( $name ) === 0 ) {
160 'apierror-translate-invalidaggregategroupname',
161 'invalidaggregategroupname'
165 $aggregateGroupId = $params[
'aggregategroup'];
166 $oldName = $this->messageGroupMetadata->get( $aggregateGroupId,
'name' );
170 if ( $exists && $oldName !== $name ) {
174 $desc = trim( $params[
'groupdescription'] );
176 $newLanguageCode = trim( $params[
'groupsourcelanguagecode'] );
178 $oldDesc = $this->messageGroupMetadata->get( $aggregateGroupId,
'description' );
179 $currentLanguageCode = $this->messageGroupMetadata->get( $aggregateGroupId,
'sourcelanguagecode' );
182 $newLanguageCode !== AggregateMessageGroup::UNDETERMINED_LANGUAGE_CODE &&
183 $newLanguageCode !== $currentLanguageCode
185 $groupsWithDifferentLanguage =
186 $this->getGroupsWithDifferentLanguage( $aggregateGroupId, $newLanguageCode );
188 if ( count( $groupsWithDifferentLanguage ) ) {
189 $this->dieWithError( [
190 'translate-error-aggregategroup-source-language-mismatch',
191 implode(
', ', $groupsWithDifferentLanguage ),
193 count( $groupsWithDifferentLanguage )
200 && $oldDesc === $desc
201 && $newLanguageCode === $currentLanguageCode
203 $this->dieWithError(
'apierror-translate-invalidupdate',
'invalidupdate' );
205 $this->messageGroupMetadata->set( $aggregateGroupId,
'name', $name );
206 $this->messageGroupMetadata->set( $aggregateGroupId,
'description', $desc );
207 if ( $newLanguageCode === AggregateMessageGroup::UNDETERMINED_LANGUAGE_CODE ) {
208 $this->messageGroupMetadata->clearMetadata( $aggregateGroupId, [
'sourcelanguagecode' ] );
210 $this->messageGroupMetadata->set( $aggregateGroupId,
'sourcelanguagecode', $newLanguageCode );
215 $output[
'result'] =
'ok';
216 $this->getResult()->addValue(
null, $this->getModuleName(), $output );
218 MessageGroups::singleton()->recache();
219 $this->jobQueueGroup->push( RebuildMessageIndexJob::newJob() );
227 private function getGroupsWithDifferentLanguage(
228 string $aggregateGroupId,
229 string $sourceLanguageCode
231 $groupsWithDifferentLanguage = [];
232 $subgroups = $this->messageGroupMetadata->getSubgroups( $aggregateGroupId );
233 foreach ( $subgroups as $group ) {
235 $messageGroupLanguage = $messageGroup->getSourceLanguage();
236 if ( $messageGroupLanguage !== $sourceLanguageCode ) {
237 $groupsWithDifferentLanguage[] = $messageGroup->getLabel();
241 return $groupsWithDifferentLanguage;
244 public function isWriteMode():
bool {
248 public function needsToken():
string {
252 protected function getAllowedParams(): array {
255 ParamValidator::PARAM_TYPE => [
'associate',
'dissociate',
'remove',
'add',
'update' ],
256 ParamValidator::PARAM_REQUIRED =>
true,
258 'aggregategroup' => [
259 ParamValidator::PARAM_TYPE =>
'string',
263 ParamValidator::PARAM_TYPE =>
'string',
264 ParamValidator::PARAM_DEPRECATED =>
true,
268 ParamValidator::PARAM_TYPE =>
'string',
269 ParamValidator::PARAM_ISMULTI =>
true,
272 ParamValidator::PARAM_TYPE =>
'string',
274 'groupdescription' => [
275 ParamValidator::PARAM_TYPE =>
'string',
276 ParamValidator::PARAM_DEFAULT =>
'',
278 'groupsourcelanguagecode' => [
279 ParamValidator::PARAM_TYPE =>
'string',
280 ParamValidator::PARAM_DEFAULT => AggregateMessageGroup::UNDETERMINED_LANGUAGE_CODE,
285 protected function getExamplesMessages(): array {
287 'action=aggregategroups&do=associate&groups=groupId1|groupId2&aggregategroup=aggregateGroupId'
288 =>
'apihelp-aggregategroups-example-1',
292 private function getIncludableGroups(): array {
295 foreach ( $groups as $group ) {
296 if ( $this->aggregateGroupManager->supportsAggregation( $group ) ) {
297 $pages[$group->getId()] = $group->getLabel( $this->getContext() );