Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
RecentEditEntrypointRegistrationHandler
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 2
182
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onBeforePageDisplay
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
156
1<?php
2
3declare( strict_types=1 );
4
5namespace ContentTranslation\HookHandler;
6
7use ContentTranslation\Service\WikidataIdFetcher;
8use ContentTranslation\SiteMapper;
9use ContentTranslation\Store\RecentSignificantEditStore;
10use MediaWiki\MediaWikiServices;
11use MediaWiki\Output\Hook\BeforePageDisplayHook;
12use MediaWiki\Output\OutputPage;
13use MediaWiki\Registration\ExtensionRegistry;
14use MediaWiki\Skin\Skin;
15use MobileContext;
16
17class 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}