diff options
Diffstat (limited to 'www/wiki/extensions/Translate/api/ApiAggregateGroups.php')
-rw-r--r-- | www/wiki/extensions/Translate/api/ApiAggregateGroups.php | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/www/wiki/extensions/Translate/api/ApiAggregateGroups.php b/www/wiki/extensions/Translate/api/ApiAggregateGroups.php new file mode 100644 index 00000000..a8a259df --- /dev/null +++ b/www/wiki/extensions/Translate/api/ApiAggregateGroups.php @@ -0,0 +1,238 @@ +<?php +/** + * API module for managing aggregate message groups + * @file + * @author Santhosh Thottingal + * @author Niklas Laxström + * @copyright Copyright © 2012-2013, Santhosh Thottingal + * @license GPL-2.0-or-later + */ + +/** + * API module for managing aggregate message groups + * Only supports aggregate message groups defined inside the wiki. + * Aggregate message group defined in YAML configuration cannot be altered. + * + * @ingroup API TranslateAPI + */ +class ApiAggregateGroups extends ApiBase { + protected static $right = 'translate-manage'; + + public function execute() { + $this->checkUserRightsAny( self::$right ); + + $params = $this->extractRequestParams(); + $action = $params['do']; + $output = []; + if ( $action === 'associate' || $action === 'dissociate' ) { + // Group is mandatory only for these two actions + if ( !isset( $params['group'] ) ) { + $this->dieWithError( [ 'apierror-missingparam', 'group' ] ); + } + if ( !isset( $params['aggregategroup'] ) ) { + $this->dieWithError( [ 'apierror-missingparam', 'aggregategroup' ] ); + } + $aggregateGroup = $params['aggregategroup']; + $subgroups = TranslateMetadata::getSubgroups( $aggregateGroup ); + if ( !$subgroups ) { + // For newly created groups the subgroups value might be empty, + // but check that. + if ( TranslateMetadata::get( $aggregateGroup, 'name' ) === false ) { + $this->dieWithError( 'apierror-translate-invalidaggregategroup', 'invalidaggregategroup' ); + } + $subgroups = []; + } + + $subgroupId = $params['group']; + $group = MessageGroups::getGroup( $subgroupId ); + + // Add or remove from the list + if ( $action === 'associate' ) { + if ( !$group instanceof WikiPageMessageGroup ) { + $this->dieWithError( 'apierror-translate-invalidgroup', 'invalidgroup' ); + } + + $subgroups[] = $subgroupId; + $subgroups = array_unique( $subgroups ); + } elseif ( $action === 'dissociate' ) { + // Allow removal of non-existing groups + $subgroups = array_flip( $subgroups ); + unset( $subgroups[$subgroupId] ); + $subgroups = array_flip( $subgroups ); + } + + TranslateMetadata::setSubgroups( $aggregateGroup, $subgroups ); + + $logParams = [ + 'aggregategroup' => TranslateMetadata::get( $aggregateGroup, 'name' ), + 'aggregategroup-id' => $aggregateGroup, + ]; + + /* Note that to allow removing no longer existing groups from + * aggregate message groups, the message group object $group + * might not always be available. In this case we need to fake + * some title. */ + $title = $group ? + $group->getTitle() : + Title::newFromText( "Special:Translate/$subgroupId" ); + + $entry = new ManualLogEntry( 'pagetranslation', $action ); + $entry->setPerformer( $this->getUser() ); + $entry->setTarget( $title ); + // @todo + // $entry->setComment( $comment ); + $entry->setParameters( $logParams ); + + $logid = $entry->insert(); + $entry->publish( $logid ); + } elseif ( $action === 'remove' ) { + if ( !isset( $params['aggregategroup'] ) ) { + $this->dieWithError( [ 'apierror-missingparam', 'aggregategroup' ] ); + } + TranslateMetadata::deleteGroup( $params['aggregategroup'] ); + // @todo Logging + + } elseif ( $action === 'add' ) { + if ( !isset( $params['groupname'] ) ) { + $this->dieWithError( [ 'apierror-missingparam', 'groupname' ] ); + } + $name = trim( $params['groupname'] ); + if ( strlen( $name ) === 0 ) { + $this->dieWithError( + 'apierror-translate-invalidaggregategroupname', 'invalidaggregategroupname' + ); + } + + if ( !isset( $params['groupdescription'] ) ) { + $this->dieWithError( [ 'apierror-missingparam', 'groupdescription' ] ); + } + $desc = trim( $params['groupdescription'] ); + + $aggregateGroupId = self::generateAggregateGroupId( $name ); + + // Throw error if group already exists + $nameExists = MessageGroups::labelExists( $name ); + if ( $nameExists ) { + $this->dieWithError( 'apierror-translate-duplicateaggregategroup', 'duplicateaggregategroup' ); + } + + // ID already exists- Generate a new ID by adding a number to it. + $idExists = MessageGroups::getGroup( $aggregateGroupId ); + if ( $idExists ) { + $i = 1; + while ( $idExists ) { + $tempId = $aggregateGroupId . '-' . $i; + $idExists = MessageGroups::getGroup( $tempId ); + $i++; + } + $aggregateGroupId = $tempId; + } + + TranslateMetadata::set( $aggregateGroupId, 'name', $name ); + TranslateMetadata::set( $aggregateGroupId, 'description', $desc ); + TranslateMetadata::setSubgroups( $aggregateGroupId, [] ); + + // Once new aggregate group added, we need to show all the pages that can be added to that. + $output['groups'] = self::getAllPages(); + $output['aggregategroupId'] = $aggregateGroupId; + // @todo Logging + } elseif ( $action === 'update' ) { + if ( !isset( $params['groupname'] ) ) { + $this->dieWithError( [ 'apierror-missingparam', 'groupname' ] ); + } + $name = trim( $params['groupname'] ); + if ( strlen( $name ) === 0 ) { + $this->dieWithError( + 'apierror-translate-invalidaggregategroupname', 'invalidaggregategroupname' + ); + } + $desc = trim( $params['groupdescription'] ); + $aggregateGroupId = $params['aggregategroup']; + + $oldName = TranslateMetadata::get( $aggregateGroupId, 'name' ); + $oldDesc = TranslateMetadata::get( $aggregateGroupId, 'description' ); + + // Error if the label exists already + $exists = MessageGroups::labelExists( $name ); + if ( $exists && $oldName !== $name ) { + $this->dieWithError( 'apierror-translate-duplicateaggregategroup', 'duplicateaggregategroup' ); + } + + if ( $oldName === $name && $oldDesc === $desc ) { + $this->dieWithError( 'apierror-translate-invalidupdate', 'invalidupdate' ); + } + TranslateMetadata::set( $aggregateGroupId, 'name', $name ); + TranslateMetadata::set( $aggregateGroupId, 'description', $desc ); + } + + // If we got this far, nothing has failed + $output['result'] = 'ok'; + $this->getResult()->addValue( null, $this->getModuleName(), $output ); + // Cache needs to be cleared after any changes to groups + MessageGroups::singleton()->recache(); + MessageIndexRebuildJob::newJob()->insertIntoJobQueue(); + } + + protected function generateAggregateGroupId( $aggregateGroupName, $prefix = 'agg-' ) { + // The database field has maximum limit of 200 bytes + if ( strlen( $aggregateGroupName ) + strlen( $prefix ) >= 200 ) { + return $prefix . substr( sha1( $aggregateGroupName ), 0, 5 ); + } else { + $pattern = '/[\x00-\x1f\x23\x27\x2c\x2e\x3c\x3e\x5b\x5d\x7b\x7c\x7d\x7f\s]+/i'; + return $prefix . preg_replace( $pattern, '_', $aggregateGroupName ); + } + } + + public function isWriteMode() { + return true; + } + + public function needsToken() { + return 'csrf'; + } + + public function getAllowedParams() { + return [ + 'do' => [ + ApiBase::PARAM_TYPE => [ 'associate', 'dissociate', 'remove', 'add', 'update' ], + ApiBase::PARAM_REQUIRED => true, + ], + 'aggregategroup' => [ + ApiBase::PARAM_TYPE => 'string', + ], + 'group' => [ + // Not providing list of values, to allow dissociation of unknown groups + ApiBase::PARAM_TYPE => 'string', + ], + 'groupname' => [ + ApiBase::PARAM_TYPE => 'string', + ], + 'groupdescription' => [ + ApiBase::PARAM_TYPE => 'string', + ], + 'token' => [ + ApiBase::PARAM_TYPE => 'string', + ApiBase::PARAM_REQUIRED => true, + ], + ]; + } + + protected function getExamplesMessages() { + return [ + 'action=aggregategroups&do=associate&group=groupId&aggregategroup=aggregateGroupId' + => 'apihelp-aggregategroups-example-1', + ]; + } + + public static function getAllPages() { + $groups = MessageGroups::getAllGroups(); + $pages = []; + foreach ( $groups as $group ) { + if ( $group instanceof WikiPageMessageGroup ) { + $pages[$group->getId()] = $group->getTitle()->getPrefixedText(); + } + } + + return $pages; + } +} |