Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
RecentTranslationEntrypointRegistrationHandler
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 2
132
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 onBeforePageDisplay
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
110
1<?php
2
3declare( strict_types=1 );
4
5namespace ContentTranslation\HookHandler;
6
7use ContentTranslation\SiteMapper;
8use ContentTranslation\Store\TranslationStore;
9use MediaWiki\MediaWikiServices;
10use MediaWiki\Output\Hook\BeforePageDisplayHook;
11use MediaWiki\Output\OutputPage;
12use MediaWiki\Registration\ExtensionRegistry;
13use MediaWiki\Revision\RevisionStore;
14use MobileContext;
15use Skin;
16use Wikimedia\Rdbms\ILoadBalancer;
17
18class RecentTranslationEntrypointRegistrationHandler implements BeforePageDisplayHook {
19    /** @var ILoadBalancer */
20    private $loadBalancer;
21
22    /** @var RevisionStore */
23    private $revisionStore;
24
25    /** @var TranslationStore */
26    private $translationStore;
27
28    public function __construct(
29        ILoadBalancer $loadBalancer,
30        RevisionStore $revisionStore,
31        TranslationStore $translationStore
32    ) {
33        $this->loadBalancer = $loadBalancer;
34        $this->revisionStore = $revisionStore;
35        $this->translationStore = $translationStore;
36    }
37
38    /**
39     * This hook adds "ext.cx.entrypoints.recenttranslation" module, to support
40     * entrypoint inside articles, that encourages users to review recently
41     * translated articles, if the appropriate conditions are met.
42     * These conditions are:
43     * 1. SectionTranslation is enabled for current wiki
44     * 2. User is accessing the mobile web version of the article
45     * 3. User is logged-in
46     * 4. The article was published as a new page by Content or Section Translation
47     * 5. The article was published in the last 10 days
48     * 6. The article has less than 5 edits since it was published
49     *
50     * @param OutputPage $out
51     * @param Skin $skin
52     * @throws \Exception
53     */
54    public function onBeforePageDisplay( $out, $skin ): void {
55        // This entrypoint should only be enabled for mobile web version
56        $isMobileView = false;
57
58        if ( ExtensionRegistry::getInstance()->isLoaded( 'MobileFrontend' ) ) {
59            /** @var MobileContext $mobileContext */
60            $mobileContext = MediaWikiServices::getInstance()->getService( 'MobileFrontend.Context' );
61            $isMobileView = $mobileContext->shouldDisplayMobileView();
62        }
63
64        if ( !$isMobileView ) {
65            return;
66        }
67
68        // This entrypoint should only be enabled for logged-in users
69        $user = $out->getUser();
70        if ( !$user->isNamed() ) {
71            return;
72        }
73
74        $title = $out->getTitle();
75        // This entrypoint should only be enabled for article pages
76        $isContentPage = $title->isContentPage();
77        if ( !$isContentPage ) {
78            return;
79        }
80
81        $currentLanguageCode = SiteMapper::getCurrentLanguageCode();
82        $enabledLanguages = $out->getConfig()->get( 'SectionTranslationTargetLanguages' );
83        $isSXEnabled = is_array( $enabledLanguages ) && in_array( $currentLanguageCode, $enabledLanguages );
84
85        if ( !$isSXEnabled ) {
86            return;
87        }
88
89        // This entrypoint should only be enabled:
90        // a. for pages that are created using Content or Section Translation
91        // b. for pages that were published in the last 10 days
92        // "cx_translations" table is expected to be smaller than "revision"
93        // table, so we query this table first.
94        $translation = $this->translationStore->findByPublishedTitle( $title->getPrefixedText(), $currentLanguageCode );
95
96        // If translation not found inside the table, meaning this article has
97        // not been created using Content or Section Translation, return
98        if ( $translation === null ) {
99            return;
100        }
101        $translationData = $translation->getData();
102        $creationDate = new \DateTime( $translationData['lastUpdateTimestamp'] );
103        // Check if translation was published within the last 10 days
104        $createdWithin10Days = (bool)$creationDate->diff( new \DateTime( '-10 days' ) )->invert;
105        if ( !$createdWithin10Days ) {
106            return;
107        }
108
109        // This entrypoint should only be enabled for pages that have less than 5 edits.
110        $pageId = $out->getWikiPage()->getId();
111        // Find all revisions for this page
112        $dbr = $this->loadBalancer->getConnection( DB_REPLICA );
113        $revisionsCount = $this->revisionStore->countRevisionsByPageId( $dbr, $pageId );
114
115        // If article has at least 5 edits, return
116        if ( $revisionsCount >= 5 ) {
117            return;
118        }
119
120        // If all the above conditions are met, add 'ext.cx.entrypoints.recenttranslation' entrypoint
121        $out->addModules( 'ext.cx.entrypoints.recenttranslation' );
122        // Add Javascript variables for translation source title and source language,
123        // so that they can be used inside UI
124        $out->addJsConfigVars( 'wgSectionTranslationSourceTitle',
125            $translationData['sourceTitle'] );
126        $out->addJsConfigVars( 'wgSectionTranslationSourceLanguage',
127            $translationData['sourceLanguage'] );
128    }
129}