Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 43 |
|
0.00% |
0 / 2 |
CRAP | |
0.00% |
0 / 1 |
| RecentEditEntrypointRegistrationHandler | |
0.00% |
0 / 43 |
|
0.00% |
0 / 2 |
182 | |
0.00% |
0 / 1 |
| __construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| onBeforePageDisplay | |
0.00% |
0 / 42 |
|
0.00% |
0 / 1 |
156 | |||
| 1 | <?php |
| 2 | |
| 3 | declare( strict_types=1 ); |
| 4 | |
| 5 | namespace ContentTranslation\HookHandler; |
| 6 | |
| 7 | use ContentTranslation\Service\WikidataIdFetcher; |
| 8 | use ContentTranslation\SiteMapper; |
| 9 | use ContentTranslation\Store\RecentSignificantEditStore; |
| 10 | use MediaWiki\MediaWikiServices; |
| 11 | use MediaWiki\Output\Hook\BeforePageDisplayHook; |
| 12 | use MediaWiki\Output\OutputPage; |
| 13 | use MediaWiki\Registration\ExtensionRegistry; |
| 14 | use MediaWiki\Skin\Skin; |
| 15 | use MobileContext; |
| 16 | |
| 17 | class RecentEditEntrypointRegistrationHandler implements BeforePageDisplayHook { |
| 18 | |
| 19 | public function __construct( |
| 20 | private readonly RecentSignificantEditStore $significantEditStore, |
| 21 | private readonly WikidataIdFetcher $wikidataIdFetcher |
| 22 | ) { |
| 23 | } |
| 24 | |
| 25 | /** |
| 26 | * This hook adds "ext.cx.entrypoints.recentedit" module, to support |
| 27 | * entrypoint inside articles, that encourages users to translate |
| 28 | * a section, they recently edited for the same page in another language. |
| 29 | * |
| 30 | * To support this entrypoint, a table named "cx_significant_edits" |
| 31 | * has been created, that stores the 10 latest "significant" edits, |
| 32 | * that affect at least one non-lead section, for each user. |
| 33 | * |
| 34 | * If such edits exist for the current article, then the |
| 35 | * "ext.cx.entrypoints.recentedit" module is added and |
| 36 | * "wgSectionTranslationRecentlyEditedSections" JS variable |
| 37 | * is set, containing an array of objects containing the page title |
| 38 | * and the sections edited for each language: |
| 39 | * ([{ "language": "en", page: "Moon", "sections": ["Formation"] }]). |
| 40 | * |
| 41 | * @param OutputPage $out |
| 42 | * @param Skin $skin |
| 43 | */ |
| 44 | public function onBeforePageDisplay( $out, $skin ): void { |
| 45 | $isMobileView = false; |
| 46 | if ( ExtensionRegistry::getInstance()->isLoaded( 'MobileFrontend' ) ) { |
| 47 | /** @var MobileContext $mobileContext */ |
| 48 | $mobileContext = MediaWikiServices::getInstance()->getService( 'MobileFrontend.Context' ); |
| 49 | $isMobileView = $mobileContext->shouldDisplayMobileView(); |
| 50 | } |
| 51 | |
| 52 | // This entrypoint should only be enabled for mobile web version |
| 53 | if ( !$isMobileView ) { |
| 54 | return; |
| 55 | } |
| 56 | |
| 57 | // This entrypoint should only be enabled for logged-in users |
| 58 | $user = $out->getUser(); |
| 59 | if ( !$user->isNamed() ) { |
| 60 | return; |
| 61 | } |
| 62 | |
| 63 | // This entrypoint should only be enabled for article pages |
| 64 | $isContentPage = $out->getTitle()->isContentPage(); |
| 65 | if ( !$isContentPage ) { |
| 66 | return; |
| 67 | } |
| 68 | |
| 69 | $currentLanguageCode = SiteMapper::getCurrentLanguageCode(); |
| 70 | // This entrypoint should only be enabled for wikis that have SectionTranslation enabled |
| 71 | $enabledLanguages = $out->getConfig()->get( 'SectionTranslationTargetLanguages' ); |
| 72 | $isSXEnabled = is_array( $enabledLanguages ) && in_array( $currentLanguageCode, $enabledLanguages ); |
| 73 | if ( !$isSXEnabled ) { |
| 74 | return; |
| 75 | } |
| 76 | |
| 77 | // If current wiki family is not supported for this entrypoint, return |
| 78 | if ( !$this->significantEditStore->isCurrentWikiFamilySupported() ) { |
| 79 | return; |
| 80 | } |
| 81 | |
| 82 | $title = $out->getTitle(); |
| 83 | $qid = $this->wikidataIdFetcher->getWikidataId( $title->getPrefixedDBkey(), $currentLanguageCode ); |
| 84 | |
| 85 | if ( !$qid ) { |
| 86 | wfDebugLog( 'cx-entrypoints-recent-edit', 'qid not found' ); |
| 87 | return; |
| 88 | } |
| 89 | // get integer from Q id ("Q123") |
| 90 | $wikidataId = (int)filter_var( $qid, FILTER_SANITIZE_NUMBER_INT ); |
| 91 | |
| 92 | /** |
| 93 | * Fetch recent edits that satisfy the below conditions: |
| 94 | * 1. Were made by the current user |
| 95 | * 2. Were done to an article with the current wikidata page id |
| 96 | * 3. Were done in a language different from the current one |
| 97 | */ |
| 98 | $edits = $this->significantEditStore->findEditsForPotentialSuggestions( |
| 99 | $user->getId(), |
| 100 | $wikidataId, |
| 101 | SiteMapper::getCurrentLanguageCode() |
| 102 | ); |
| 103 | |
| 104 | if ( !$edits ) { |
| 105 | return; |
| 106 | } |
| 107 | |
| 108 | // We want to group the edited sections by language. For that reason, group the above |
| 109 | // RecentSignificantEdit instances to an associative array, that follow the below form: |
| 110 | // [ |
| 111 | // "en" => [ "language" => "en", "page" => "Moon", "sections" => ["Formation"] ], |
| 112 | // "es" => [ "language" => "es", "page" => "Luna", "sections" => ["Formación"] ] |
| 113 | // ] |
| 114 | $recentUserEdits = []; |
| 115 | foreach ( $edits as $edit ) { |
| 116 | $editLanguage = $edit->getLanguage(); |
| 117 | $recentUserEdits[$editLanguage]['language'] = $editLanguage; |
| 118 | $recentUserEdits[$editLanguage]['page'] = $edit->getPageTitle(); |
| 119 | |
| 120 | foreach ( $edit->getSectionTitles() as $sectionTitle ) { |
| 121 | $recentUserEdits[$editLanguage]['sections'][] = $sectionTitle; |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | // If all the above conditions are met, add 'ext.cx.entrypoints.recentedit' entrypoint |
| 126 | $out->addModules( 'ext.cx.entrypoints.recentedit' ); |
| 127 | |
| 128 | // Add Javascript variable that will contain an array of objects containing |
| 129 | // the edited sections, the respective page title and the respective language. |
| 130 | $out->addJsConfigVars( 'wgSectionTranslationRecentlyEditedSections', |
| 131 | array_values( $recentUserEdits ) ); |
| 132 | } |
| 133 | } |