31 private $jobQueueGroup;
33 protected static $right =
'translate-manage';
35 public function __construct(
38 JobQueueGroup $jobQueueGroup
40 parent::__construct( $main, $action );
41 $this->jobQueueGroup = $jobQueueGroup;
44 public function execute():
void {
45 $this->checkUserRightsAny( self::$right );
46 $block = $this->getUser()->getBlock();
47 if ( $block && $block->isSitewide() ) {
48 $this->dieBlocked( $block );
51 $params = $this->extractRequestParams();
52 $action = $params[
'do'];
54 if ( $action ===
'associate' || $action ===
'dissociate' ) {
56 if ( !isset( $params[
'group'] ) ) {
57 $this->dieWithError( [
'apierror-missingparam',
'group' ] );
59 if ( !isset( $params[
'aggregategroup'] ) ) {
60 $this->dieWithError( [
'apierror-missingparam',
'aggregategroup' ] );
62 $aggregateGroup = $params[
'aggregategroup'];
63 $subgroups = TranslateMetadata::getSubgroups( $aggregateGroup );
64 if ( $subgroups ===
null ) {
68 $this->dieWithError(
'apierror-translate-invalidaggregategroup',
'invalidaggregategroup' );
71 $subgroupId = $params[
'group'];
72 $group = MessageGroups::getGroup( $subgroupId );
75 if ( $action ===
'associate' ) {
77 $this->dieWithError(
'apierror-translate-invalidgroup',
'invalidgroup' );
80 $subgroups[] = $subgroupId;
81 $subgroups = array_unique( $subgroups );
82 } elseif ( $action ===
'dissociate' ) {
84 $subgroups = array_flip( $subgroups );
85 unset( $subgroups[$subgroupId] );
86 $subgroups = array_flip( $subgroups );
89 TranslateMetadata::setSubgroups( $aggregateGroup, $subgroups );
92 'aggregategroup' => TranslateMetadata::get( $aggregateGroup,
'name' ),
93 'aggregategroup-id' => $aggregateGroup,
102 Title::newFromText(
"Special:Translate/$subgroupId" );
104 $entry =
new ManualLogEntry(
'pagetranslation', $action );
105 $entry->setPerformer( $this->getUser() );
106 $entry->setTarget( $title );
109 $entry->setParameters( $logParams );
111 $logid = $entry->insert();
112 $entry->publish( $logid );
113 } elseif ( $action ===
'remove' ) {
114 if ( !isset( $params[
'aggregategroup'] ) ) {
115 $this->dieWithError( [
'apierror-missingparam',
'aggregategroup' ] );
118 $aggregateGroupId = $params[
'aggregategroup'];
119 $group = MessageGroups::getGroup( $aggregateGroupId );
122 'apierror-translate-invalidaggregategroupname',
'invalidaggregategroupname'
126 TranslateMetadata::deleteGroup( $params[
'aggregategroup'] );
127 $logger = LoggerFactory::getInstance(
'Translate' );
129 'Aggregate group {groupId} has been deleted.',
130 [
'groupId' => $aggregateGroupId ]
132 } elseif ( $action ===
'add' ) {
133 if ( !isset( $params[
'groupname'] ) ) {
134 $this->dieWithError( [
'apierror-missingparam',
'groupname' ] );
136 $name = trim( $params[
'groupname'] );
137 if ( strlen( $name ) === 0 ) {
139 'apierror-translate-invalidaggregategroupname',
'invalidaggregategroupname'
143 if ( !isset( $params[
'groupdescription'] ) ) {
144 $this->dieWithError( [
'apierror-missingparam',
'groupdescription' ] );
146 $desc = trim( $params[
'groupdescription'] );
148 $aggregateGroupId = self::generateAggregateGroupId( $name );
151 $nameExists = MessageGroups::labelExists( $name );
153 $this->dieWithError(
'apierror-translate-duplicateaggregategroup',
'duplicateaggregategroup' );
157 $idExists = MessageGroups::getGroup( $aggregateGroupId );
161 $tempId = $aggregateGroupId .
'-' . $i;
162 $idExists = MessageGroups::getGroup( $tempId );
164 }
while ( $idExists );
165 $aggregateGroupId = $tempId;
168 TranslateMetadata::set( $aggregateGroupId,
'name', $name );
169 TranslateMetadata::set( $aggregateGroupId,
'description', $desc );
170 TranslateMetadata::setSubgroups( $aggregateGroupId, [] );
173 $output[
'groups'] = self::getAllPages();
174 $output[
'aggregategroupId'] = $aggregateGroupId;
176 } elseif ( $action ===
'update' ) {
177 if ( !isset( $params[
'groupname'] ) ) {
178 $this->dieWithError( [
'apierror-missingparam',
'groupname' ] );
180 $name = trim( $params[
'groupname'] );
181 if ( strlen( $name ) === 0 ) {
183 'apierror-translate-invalidaggregategroupname',
'invalidaggregategroupname'
186 $desc = trim( $params[
'groupdescription'] );
187 $aggregateGroupId = $params[
'aggregategroup'];
189 $oldName = TranslateMetadata::get( $aggregateGroupId,
'name' );
190 $oldDesc = TranslateMetadata::get( $aggregateGroupId,
'description' );
193 $exists = MessageGroups::labelExists( $name );
194 if ( $exists && $oldName !== $name ) {
195 $this->dieWithError(
'apierror-translate-duplicateaggregategroup',
'duplicateaggregategroup' );
198 if ( $oldName === $name && $oldDesc === $desc ) {
199 $this->dieWithError(
'apierror-translate-invalidupdate',
'invalidupdate' );
201 TranslateMetadata::set( $aggregateGroupId,
'name', $name );
202 TranslateMetadata::set( $aggregateGroupId,
'description', $desc );
206 $output[
'result'] =
'ok';
207 $this->getResult()->addValue(
null, $this->getModuleName(), $output );
209 MessageGroups::singleton()->recache();
210 $this->jobQueueGroup->push( MessageIndexRebuildJob::newJob() );
213 protected function generateAggregateGroupId(
string $aggregateGroupName,
string $prefix =
'agg-' ):
string {
215 if ( strlen( $aggregateGroupName ) + strlen( $prefix ) >= 200 ) {
216 return $prefix . substr( sha1( $aggregateGroupName ), 0, 5 );
218 $pattern =
'/[\x00-\x1f\x23\x27\x2c\x2e\x3c\x3e\x5b\x5d\x7b\x7c\x7d\x7f\s]+/i';
219 return $prefix . preg_replace( $pattern,
'_', $aggregateGroupName );
223 public function isWriteMode():
bool {
227 public function needsToken():
string {
231 protected function getAllowedParams(): array {
234 ParamValidator::PARAM_TYPE => [
'associate',
'dissociate',
'remove',
'add',
'update' ],
235 ParamValidator::PARAM_REQUIRED =>
true,
237 'aggregategroup' => [
238 ParamValidator::PARAM_TYPE =>
'string',
242 ParamValidator::PARAM_TYPE =>
'string',
245 ParamValidator::PARAM_TYPE =>
'string',
247 'groupdescription' => [
248 ParamValidator::PARAM_TYPE =>
'string',
251 ParamValidator::PARAM_TYPE =>
'string',
252 ParamValidator::PARAM_REQUIRED =>
true,
257 protected function getExamplesMessages(): array {
259 'action=aggregategroups&do=associate&group=groupId&aggregategroup=aggregateGroupId'
260 =>
'apihelp-aggregategroups-example-1',
264 public static function getAllPages(): array {
265 $groups = MessageGroups::getAllGroups();
267 foreach ( $groups as $group ) {
269 $pages[$group->getId()] = $group->getTitle()->getPrefixedText();
Wraps the translatable page sections into a message group.