Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
75.86% covered (warning)
75.86%
22 / 29
66.67% covered (warning)
66.67%
6 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
TwoColConflictContext
75.86% covered (warning)
75.86%
22 / 29
66.67% covered (warning)
66.67%
6 / 9
32.10
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 shouldCoreHintBeShown
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
4
 shouldTwoColConflictBeShown
77.78% covered (warning)
77.78%
7 / 9
0.00% covered (danger)
0.00%
0 / 1
7.54
 shouldTalkPageSuggestionBeConsidered
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 isSelfConflict
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 hasUserEnabledFeature
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 isUsedAsBetaFeature
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 isEligibleTalkPage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 isTalkPageSuggesterEnabled
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace TwoColConflict;
4
5use ExtensionRegistry;
6use MediaWiki\Config\Config;
7use MediaWiki\Extension\BetaFeatures\BetaFeatures;
8use MediaWiki\Title\Title;
9use MediaWiki\User\Options\UserOptionsLookup;
10use MediaWiki\User\UserIdentity;
11use MobileContext;
12use WikiPage;
13
14/**
15 * @license GPL-2.0-or-later
16 */
17class TwoColConflictContext {
18
19    public const BETA_PREFERENCE_NAME = 'twocolconflict';
20    public const ENABLED_PREFERENCE = 'twocolconflict-enabled';
21    public const HIDE_CORE_HINT_PREFERENCE = 'userjs-twocolconflict-hide-core-hint';
22
23    private Config $config;
24    private UserOptionsLookup $userOptionsLookup;
25    private ExtensionRegistry $extensionRegistry;
26    private ?MobileContext $mobileContext;
27
28    public function __construct(
29        Config $config,
30        UserOptionsLookup $userOptionsLookup,
31        ExtensionRegistry $extensionRegistry,
32        MobileContext $mobileContext = null
33    ) {
34        $this->config = $config;
35        $this->userOptionsLookup = $userOptionsLookup;
36        $this->extensionRegistry = $extensionRegistry;
37        $this->mobileContext = $mobileContext;
38    }
39
40    /**
41     * @param UserIdentity $user
42     *
43     * @return bool True if the feature is not used as a beta feature, the
44     * user has disabled the feature but has not dismissed the core hint
45     * already.
46     */
47    public function shouldCoreHintBeShown( UserIdentity $user ): bool {
48        return $user->isRegistered() &&
49            !$this->isUsedAsBetaFeature() &&
50            !$this->userOptionsLookup->getBoolOption( $user, self::ENABLED_PREFERENCE ) &&
51            !$this->userOptionsLookup->getBoolOption( $user, self::HIDE_CORE_HINT_PREFERENCE );
52    }
53
54    /**
55     * @param UserIdentity $user
56     * @param Title $title
57     *
58     * @return bool True if the new conflict interface should be used for this
59     *   user and title.  The user may have opted out, or the titles namespace
60     *   may be excluded for this interface.
61     */
62    public function shouldTwoColConflictBeShown( UserIdentity $user, Title $title ): bool {
63        if ( !$title->hasContentModel( CONTENT_MODEL_WIKITEXT ) &&
64            !$title->hasContentModel( CONTENT_MODEL_TEXT )
65        ) {
66            return false;
67        }
68
69        // T249817: Temporarily disabled on mobile
70        if ( $this->mobileContext && $this->mobileContext->shouldDisplayMobileView() ) {
71            return false;
72        }
73
74        if ( $this->isEligibleTalkPage( $title ) &&
75            !$this->isTalkPageSuggesterEnabled()
76        ) {
77            // Temporary feature logic to completely disable on talk pages.
78            return false;
79        }
80
81        return $this->hasUserEnabledFeature( $user );
82    }
83
84    /**
85     * @param WikiPage $page
86     * @param UserIdentity $user
87     * @return bool True if this article is appropriate for the talk page
88     *   workflow, and the interface has been enabled by configuration.
89     */
90    public function shouldTalkPageSuggestionBeConsidered( WikiPage $page, UserIdentity $user ): bool {
91        return $this->isTalkPageSuggesterEnabled() &&
92            $this->isEligibleTalkPage( $page->getTitle() ) &&
93            !$this->isSelfConflict( $page, $user );
94    }
95
96    private function isSelfConflict( WikiPage $page, UserIdentity $user ): bool {
97        $lastRevision = $page->getRevisionRecord();
98        return $lastRevision && $user->equals( $lastRevision->getUser() );
99    }
100
101    private function hasUserEnabledFeature( UserIdentity $user ): bool {
102        if ( $this->isUsedAsBetaFeature() ) {
103            return BetaFeatures::isFeatureEnabled( $user, self::BETA_PREFERENCE_NAME );
104        }
105
106        return $this->userOptionsLookup->getBoolOption( $user, self::ENABLED_PREFERENCE );
107    }
108
109    /**
110     * @return bool True if TwoColConflict should be provided as a beta feature.
111     *   False if it will be the default conflict workflow.
112     */
113    public function isUsedAsBetaFeature(): bool {
114        return $this->config->get( 'TwoColConflictBetaFeature' ) &&
115            $this->extensionRegistry->isLoaded( 'BetaFeatures' );
116    }
117
118    private function isEligibleTalkPage( Title $title ): bool {
119        return $title->isTalkPage() || $title->inNamespace( NS_PROJECT );
120    }
121
122    private function isTalkPageSuggesterEnabled(): bool {
123        return $this->config->get( 'TwoColConflictSuggestResolution' );
124    }
125
126}