From 67042a70994f6676d8c479b902fbbbb44ef07a0d Mon Sep 17 00:00:00 2001 From: Martin Urbanec Date: Mon, 11 Mar 2024 17:36:05 +0100 Subject: [PATCH] Add GEUseCommunityConfigurationExtension feature flag Why: The Growth team works on the CommunityConfiguration extension, which re-implements the ability for administrators to edit MediaWiki configuration on-wiki in a different way. This patch allows developers to switch from the GE-specific implementation of community configuration (so-called CC1.0) into the new dedicated implementation that CommunityConfiguration represents. The patch is meant to make GrowthExperiments stop use any of its CC1.0 implementation if GEUseCommunityConfigurationExtension is true, including the editing form. Notes: CommunityConfiguration expects client extensions to use a single Config object (=the one provided by CommunityConfiguration) for all config needs. This enables client extensions to seamlessly switch between configurable and non-configurable fields (it is a matter of changing the scmea), without having to review their usage across their whole repository. To fully benefit from this expectation, we need to change how we approach config within GrowthExperiments. What: * Introduce `GEUseCommunityConfigurationExtension` config flag, which is false by default. * Create `GrowthExperimentsCommunityConfig`, which either returns the `GrowthExperimentsMultiConfig` service or the CommunityConfiguration provided service, depending on the feature flag. * Switch SpecialEditGrowthConfig's registration to a conditional one, based on the feature flag value. * Move two schemas from CommunityConfigurationExample to GrowthExperiments Bug: T359124 Depends-On: If9db50b8ba8dc835a7d5e1c49de83e7ff2941c01 Change-Id: I2b6e3436c08100442baf4ed65582d0bc17fd449c --- .phan/config.php | 2 + ServiceWiring.php | 13 ++++++ extension.json | 45 ++++++++++++------- i18n/extension/en.json | 17 ++++++- i18n/extension/qqq.json | 17 ++++++- includes/Config/ConfigHooks.php | 35 ++++++++++++++- includes/Config/Schemas/MentorshipSchema.php | 41 +++++++++++++++++ includes/GrowthExperimentsServices.php | 2 +- includes/HomepageHooks.php | 4 +- .../SpecialEditGrowthConfigRedirect.php | 28 ++++++++++++ 10 files changed, 181 insertions(+), 23 deletions(-) create mode 100644 includes/Config/Schemas/MentorshipSchema.php create mode 100644 includes/Specials/SpecialEditGrowthConfigRedirect.php diff --git a/.phan/config.php b/.phan/config.php index e535768a7..d0d371555 100644 --- a/.phan/config.php +++ b/.phan/config.php @@ -9,6 +9,7 @@ $cfg['directory_list'] = array_merge( [ '../../extensions/CentralAuth', '../../extensions/CirrusSearch', + '../../extensions/CommunityConfiguration', '../../extensions/Echo', '../../extensions/EventBus', '../../extensions/EventLogging', @@ -28,6 +29,7 @@ $cfg['exclude_analysis_directory_list'] = array_merge( [ '../../extensions/CentralAuth', '../../extensions/CirrusSearch', + '../../extensions/CommunityConfiguration', '../../extensions/Echo', '../../extensions/EventBus', '../../extensions/EventLogging', diff --git a/ServiceWiring.php b/ServiceWiring.php index 991101035..2cdafae75 100644 --- a/ServiceWiring.php +++ b/ServiceWiring.php @@ -166,6 +166,19 @@ return [ return $services->getConfigFactory()->makeConfig( 'GrowthExperiments' ); }, + 'GrowthExperimentsCommunityConfig' => static function ( MediaWikiServices $services ): Config { + $geServices = GrowthExperimentsServices::wrap( $services ); + + if ( + ExtensionRegistry::getInstance()->isLoaded( 'CommunityConfiguration' ) && + $geServices->getGrowthConfig()->get( 'GEUseCommunityConfigurationExtension' ) + ) { + return $services->get( 'CommunityConfiguration.WikiPageConfigReader' ); + } else { + return $services->get( 'GrowthExperimentsMultiConfig' ); + } + }, + 'GrowthExperimentsConfigValidatorFactory' => static function ( MediaWikiServices $services ): ConfigValidatorFactory { diff --git a/extension.json b/extension.json index 306aa1d8e..9183ac5f2 100644 --- a/extension.json +++ b/extension.json @@ -101,7 +101,7 @@ "growthsetmenteestatus": { "class": "GrowthExperiments\\Api\\ApiSetMenteeStatus", "services": [ - "GrowthExperimentsMultiConfig", + "GrowthExperimentsCommunityConfig", "GrowthExperimentsMentorManager", "GrowthExperimentsMentorStore" ] @@ -319,7 +319,7 @@ "class": "GrowthExperiments\\HelpPanelHooks", "services": [ "MainConfig", - "GrowthExperimentsMultiConfig", + "GrowthExperimentsCommunityConfig", "GenderCache", "UserEditTracker", "UserOptionsManager", @@ -384,7 +384,7 @@ "class": "GrowthExperiments\\Mentorship\\Hooks\\MentorHooks", "services": [ "MainConfig", - "GrowthExperimentsMultiConfig", + "GrowthExperimentsCommunityConfig", "UserIdentityLookup", "GenderCache", "GrowthExperimentsMentorManager", @@ -583,6 +583,7 @@ ], "SpecialCreateAccountBenefits": "variant", "SpecialPage_initList": [ + "config", "homepage", "welcomeSurvey" ], @@ -652,6 +653,25 @@ ] } } + }, + "CommunityConfiguration": { + "Providers": { + "Mentorship": { + "store": { + "type": "wikipage", + "args": [ + "MediaWiki:GrowthExperimentsMentorship.json" + ] + }, + "validator": { + "type": "jsonschema", + "args": [ + "GrowthExperiments\\Config\\Schemas\\MentorshipSchema" + ] + }, + "type": "mw-config" + } + } } }, "ResourceModules": { @@ -2431,6 +2451,10 @@ "description": "If set to false, on-wiki configuration will be ignored. WARNING: This will fallback to PHP-globals for all config. By setting this to false, you can break most of the features.", "value": true }, + "GEUseCommunityConfigurationExtension": { + "description": "If set to true, the CommunityConfiguration extension is used to power on-wiki config.", + "value": false + }, "GEHelpPanelReadingModeNamespaces": { "description": "Numerical IDs of the MediaWiki namespaces in which to show the help panel in reading mode. Specifying a namespace will also include its talk namespace. Defaults to NS_PROJECT and NS_HELP namespaces.", "value": [ @@ -2835,19 +2859,6 @@ "JobQueueGroupFactory" ] }, - "EditGrowthConfig": { - "class": "GrowthExperiments\\Specials\\SpecialEditGrowthConfig", - "services": [ - "TitleFactory", - "RevisionLookup", - "PageProps", - "DBLoadBalancer", - "ReadOnlyMode", - "GrowthExperimentsWikiPageConfigLoader", - "GrowthExperimentsWikiPageConfigWriterFactory", - "GrowthExperimentsMultiConfig" - ] - }, "ManageMentors": { "class": "GrowthExperiments\\Specials\\SpecialManageMentors", "services": [ @@ -2862,7 +2873,7 @@ "EnrollAsMentor": { "class": "GrowthExperiments\\Specials\\SpecialEnrollAsMentor", "services": [ - "GrowthExperimentsMultiConfig", + "GrowthExperimentsCommunityConfig", "GrowthExperimentsMentorProvider", "GrowthExperimentsMentorWriter" ] diff --git a/i18n/extension/en.json b/i18n/extension/en.json index f54fcc946..ddbd03aff 100644 --- a/i18n/extension/en.json +++ b/i18n/extension/en.json @@ -100,5 +100,20 @@ "growthexperiments-edit-config-try-suggested-edits-notification-title": "Try Suggested edits notification", "growthexperiments-edit-config-try-suggested-edits-notification-description": "Maximum number of edits a newcomer can have to qualify for receiving this notification. If set to 0, no newcomers
will receive this notification. The higher the number, the more newcomers will receive this notification.
This notification is only sent to newcomers who have not completed Suggested edits.", "growthexperiments-edit-config-keep-going-notification-title": "Keep going notification", - "growthexperiments-edit-config-keep-going-notification-description": "Maximum number of suggested edits a newcomer can complete to qualify for receiving this notification. If set to 0,
no newcomers will receive this notification. The higher the number, the more newcomers will receive this notification.
This notification is only sent to newcomers who have already completed at least one Suggested edit." + "growthexperiments-edit-config-keep-going-notification-description": "Maximum number of suggested edits a newcomer can complete to qualify for receiving this notification. If set to 0,
no newcomers will receive this notification. The higher the number, the more newcomers will receive this notification.
This notification is only sent to newcomers who have already completed at least one Suggested edit.", + "communityconfiguration-mentorship-title": "Mentorship", + "communityconfiguration-mentorship-description": "Customize mentorship settings and eligibility, while adjusting edit minimums and timeframes for mentors and praise-worthy mentees.", + "communityconfiguration-mentorship-gementorshipautomaticeligibility-label": "Should users be automatically eligible for mentorship?", + "communityconfiguration-mentorship-gementorshipautomaticeligibility-control-label": "x", + "communityconfiguration-mentorship-gementorshipenabled-label": "Are mentorship features enabled?", + "communityconfiguration-mentorship-gementorshipenabled-control-label": "x", + "communityconfiguration-mentorship-gementorshipminimumage-label": "Minimum number of days a user must be registered to sign up as a mentor", + "communityconfiguration-mentorship-gementorshipminimumeditcount-label": "Minimum number of edits a user must have made (on any namespace) to sign up as a mentor", + "communityconfiguration-mentorship-gepersonalizedpraisedays-label": "Number of days that are considered when evaluating mentee's praiseworthiness", + "communityconfiguration-mentorship-gepersonalizedpraisedays-help-text": "Mentors can change this option for their own user in the Mentor dashboard.", + "communityconfiguration-mentorship-gepersonalizedpraisedefaultnotificationsfrequency-label": "By default, how often should mentors receive notifications to remind them to send encouragement to mentees who are editing successfully?", + "communityconfiguration-mentorship-gepersonalizedpraisedefaultnotificationsfrequency-help-text": "Mentors can change this option for their own user in the Mentor dashboard.", + "communityconfiguration-mentorship-gepersonalizedpraisemaxedits-label": "Maximum number of edits an user can have to be considered praiseworthy", + "communityconfiguration-mentorship-gepersonalizedpraiseminedits-label": "Default minimum number of edits a mentee must have to be praiseworthy", + "communityconfiguration-mentorship-gepersonalizedpraiseminedits-help-text": "Mentors can change this option for their own user in the Mentor dashboard." } diff --git a/i18n/extension/qqq.json b/i18n/extension/qqq.json index d32a848f8..5b2192914 100644 --- a/i18n/extension/qqq.json +++ b/i18n/extension/qqq.json @@ -113,5 +113,20 @@ "growthexperiments-edit-config-try-suggested-edits-notification-title": "Subheader in Special:EditGrowthConfig\n\n{{doc-growthexperiments-community-configuration}}", "growthexperiments-edit-config-try-suggested-edits-notification-description": "Description of trying suggested edits notification section in Special:EditGrowthConfig\n\n{{doc-growthexperiments-community-configuration}}", "growthexperiments-edit-config-keep-going-notification-title": "Subheader in Special:EditGrowthConfig. \"Keep going\" should be consistent with {{msg-mw|Growthexperiments-levelingup-keepgoing-notification-header}}.\n\n{{doc-growthexperiments-community-configuration}}", - "growthexperiments-edit-config-keep-going-notification-description": "Description of keep going notification section in Special:EditGrowthConfig\n\n{{doc-growthexperiments-community-configuration}}" + "growthexperiments-edit-config-keep-going-notification-description": "Description of keep going notification section in Special:EditGrowthConfig\n\n{{doc-growthexperiments-community-configuration}}", + "communityconfiguration-mentorship-title": "Headline of the Community configuration module for mentorship", + "communityconfiguration-mentorship-description": "Description of the Community configuration module for mentorship", + "communityconfiguration-mentorship-gementorshipautomaticeligibility-label": "Field label for mentorship in Community configuration", + "communityconfiguration-mentorship-gementorshipautomaticeligibility-control-label": "Field label for mentorship in Community configuration", + "communityconfiguration-mentorship-gementorshipenabled-label": "Field label for mentorship in Community configuration", + "communityconfiguration-mentorship-gementorshipenabled-control-label": "Field label for mentorship in Community configuration", + "communityconfiguration-mentorship-gementorshipminimumage-label": "Field label for mentorship in Community configuration", + "communityconfiguration-mentorship-gementorshipminimumeditcount-label": "Field label for mentorship in Community configuration", + "communityconfiguration-mentorship-gepersonalizedpraisedays-label": "Field label for mentorship in Community configuration", + "communityconfiguration-mentorship-gepersonalizedpraisedays-help-text": "Help text for mentorship in Community configuration", + "communityconfiguration-mentorship-gepersonalizedpraisedefaultnotificationsfrequency-label": "Field label for mentorship in Community configuration", + "communityconfiguration-mentorship-gepersonalizedpraisedefaultnotificationsfrequency-help-text": "Help text for mentorship in Community configuration", + "communityconfiguration-mentorship-gepersonalizedpraisemaxedits-label": "Field label for mentorship in Community configuration", + "communityconfiguration-mentorship-gepersonalizedpraiseminedits-label": "Field label for mentorship in Community configuration", + "communityconfiguration-mentorship-gepersonalizedpraiseminedits-help-text": "Help text for mentorship in Community configuration" } diff --git a/includes/Config/ConfigHooks.php b/includes/Config/ConfigHooks.php index d931ef679..c1cbd73e1 100644 --- a/includes/Config/ConfigHooks.php +++ b/includes/Config/ConfigHooks.php @@ -3,8 +3,11 @@ namespace GrowthExperiments\Config; use Content; +use ExtensionRegistry; use FormatJson; use GrowthExperiments\Config\Validation\ConfigValidatorFactory; +use GrowthExperiments\Specials\SpecialEditGrowthConfig; +use GrowthExperiments\Specials\SpecialEditGrowthConfigRedirect; use IContextSource; use JsonContent; use MediaWiki\Config\Config; @@ -13,6 +16,7 @@ use MediaWiki\Deferred\DeferredUpdates; use MediaWiki\Hook\EditFilterMergedContentHook; use MediaWiki\Hook\SkinTemplateNavigation__UniversalHook; use MediaWiki\Page\PageIdentity; +use MediaWiki\SpecialPage\Hook\SpecialPage_initListHook; use MediaWiki\SpecialPage\SpecialPage; use MediaWiki\Status\Status; use MediaWiki\Storage\Hook\PageSaveCompleteHook; @@ -26,7 +30,8 @@ class ConfigHooks implements EditFilterMergedContentHook, JsonValidateSaveHook, PageSaveCompleteHook, - SkinTemplateNavigation__UniversalHook + SkinTemplateNavigation__UniversalHook, + SpecialPage_initListHook { private ConfigValidatorFactory $configValidatorFactory; private WikiPageConfigLoader $configLoader; @@ -159,4 +164,32 @@ class ConfigHooks implements } } } + + /** + * @inheritDoc + */ + public function onSpecialPage_initList( &$list ) { + if ( + ExtensionRegistry::getInstance()->isLoaded( 'CommunityConfiguration' ) && + $this->config->get( 'GEUseCommunityConfigurationExtension' ) + ) { + $list['EditGrowthConfig'] = [ + 'class' => SpecialEditGrowthConfigRedirect::class, + ]; + } else { + $list['EditGrowthConfig'] = [ + 'class' => SpecialEditGrowthConfig::class, + 'services' => [ + 'TitleFactory', + 'RevisionLookup', + 'PageProps', + 'DBLoadBalancer', + 'ReadOnlyMode', + 'GrowthExperimentsWikiPageConfigLoader', + 'GrowthExperimentsWikiPageConfigWriterFactory', + 'GrowthExperimentsCommunityConfig' + ] + ]; + } + } } diff --git a/includes/Config/Schemas/MentorshipSchema.php b/includes/Config/Schemas/MentorshipSchema.php new file mode 100644 index 000000000..5b7fadf48 --- /dev/null +++ b/includes/Config/Schemas/MentorshipSchema.php @@ -0,0 +1,41 @@ + self::TYPE_BOOLEAN, + self::DEFAULT => true, + ]; + public const GEMentorshipEnabled = [ + self::TYPE => self::TYPE_BOOLEAN, + self::DEFAULT => false, + ]; + public const GEMentorshipMinimumAge = [ + self::TYPE => self::TYPE_NUMBER, + self::DEFAULT => 90, + ]; + public const GEMentorshipMinimumEditcount = [ + self::TYPE => self::TYPE_NUMBER, + self::DEFAULT => 500, + ]; + public const GEPersonalizedPraiseDays = [ + self::TYPE => self::TYPE_NUMBER, + self::DEFAULT => 7, + ]; + public const GEPersonalizedPraiseDefaultNotificationsFrequency = [ + self::TYPE => self::TYPE_NUMBER, + self::DEFAULT => 168, + ]; + public const GEPersonalizedPraiseMaxEdits = [ + self::TYPE => self::TYPE_NUMBER, + self::DEFAULT => 500, + ]; + public const GEPersonalizedPraiseMinEdits = [ + self::TYPE => self::TYPE_NUMBER, + self::DEFAULT => 8, + ]; +} diff --git a/includes/GrowthExperimentsServices.php b/includes/GrowthExperimentsServices.php index acded2a52..9eff65992 100644 --- a/includes/GrowthExperimentsServices.php +++ b/includes/GrowthExperimentsServices.php @@ -105,7 +105,7 @@ class GrowthExperimentsServices { } public function getGrowthWikiConfig(): Config { - return $this->coreServices->get( 'GrowthExperimentsMultiConfig' ); + return $this->coreServices->get( 'GrowthExperimentsCommunityConfig' ); } public function getLoadBalancer(): ILoadBalancer { diff --git a/includes/HomepageHooks.php b/includes/HomepageHooks.php index ce4e885ad..24c0a0ba2 100644 --- a/includes/HomepageHooks.php +++ b/includes/HomepageHooks.php @@ -279,7 +279,7 @@ class HomepageHooks implements 'PerDbNameStatsdDataFactory', 'GrowthExperimentsExperimentUserManager', 'GrowthExperimentsMentorManager', - 'GrowthExperimentsMultiConfig', + 'GrowthExperimentsCommunityConfig', 'UserOptionsManager', 'TitleFactory', ] @@ -300,7 +300,7 @@ class HomepageHooks implements 'services' => [ 'GrowthExperimentsMentorProvider', 'GrowthExperimentsChangeMentorFactory', - 'GrowthExperimentsMultiConfig' + 'GrowthExperimentsCommunityConfig' ] ]; diff --git a/includes/Specials/SpecialEditGrowthConfigRedirect.php b/includes/Specials/SpecialEditGrowthConfigRedirect.php new file mode 100644 index 000000000..51114ec1a --- /dev/null +++ b/includes/Specials/SpecialEditGrowthConfigRedirect.php @@ -0,0 +1,28 @@ +getOutput()->redirect( + $this->getSpecialPageFactory() + ->getTitleForAlias( 'CommunityConfiguration' ) + ->getLinkURL() + ); + } +}