Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
55.26% covered (warning)
55.26%
21 / 38
25.00% covered (danger)
25.00%
2 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
Hooks
55.26% covered (warning)
55.26%
21 / 38
25.00% covered (danger)
25.00%
2 / 8
31.55
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
 onSetup
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 onBeforePageDisplay
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getSchemas
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getEventLoggingConfig
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 getModuleData
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onGetPreferences
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 loadEventStreamConfigs
84.62% covered (warning)
84.62%
11 / 13
0.00% covered (danger)
0.00%
0 / 1
3.03
1<?php
2/**
3 * Hooks for EventLogging extension.
4 *
5 * @file
6 *
7 * @ingroup Extensions
8 * @ingroup EventLogging
9 *
10 * @author Ori Livneh <ori@wikimedia.org>
11 */
12
13namespace MediaWiki\Extension\EventLogging;
14
15use MediaWiki\Config\Config;
16use MediaWiki\MediaWikiServices;
17use MediaWiki\Output\Hook\BeforePageDisplayHook;
18use MediaWiki\Output\OutputPage;
19use MediaWiki\Preferences\Hook\GetPreferencesHook;
20use MediaWiki\Registration\ExtensionRegistry;
21use MediaWiki\ResourceLoader as RL;
22use MediaWiki\Skin\Skin;
23use MediaWiki\User\Options\UserOptionsLookup;
24use MediaWiki\User\User;
25
26class Hooks implements
27    BeforePageDisplayHook,
28    GetPreferencesHook
29{
30
31    /**
32     * The list of stream config settings that should be sent to the client as part of the
33     * ext.eventLogging RL module.
34     *
35     * @var string[]
36     */
37    private const STREAM_CONFIG_SETTINGS_ALLOWLIST = [
38        'sample',
39        'producers',
40    ];
41
42    private UserOptionsLookup $userOptionsLookup;
43
44    public function __construct(
45        UserOptionsLookup $userOptionsLookup
46    ) {
47        $this->userOptionsLookup = $userOptionsLookup;
48    }
49
50    /**
51     * Emit a debug log message for each invalid or unset
52     * configuration variable (if any).
53     */
54    public static function onSetup(): void {
55        global $wgEventLoggingBaseUri, $wgEventLoggingStreamNames;
56
57        if ( $wgEventLoggingBaseUri === false ) {
58            EventLogging::getLogger()->debug( 'wgEventLoggingBaseUri has not been configured.' );
59        }
60
61        if ( $wgEventLoggingStreamNames !== false && !is_array( $wgEventLoggingStreamNames ) ) {
62            EventLogging::getLogger()->debug(
63                'wgEventLoggingStreamNames is configured but is not a list of stream names'
64            );
65
66            $wgEventLoggingStreamNames = [];
67        }
68    }
69
70    /**
71     * @param OutputPage $out
72     * @param Skin $skin
73     */
74    public function onBeforePageDisplay( $out, $skin ): void {
75        $out->addModules( [ 'ext.eventLogging' ] );
76
77        if ( $this->userOptionsLookup->getIntOption( $out->getUser(), 'eventlogging-display-console' ) ) {
78            $out->addModules( 'ext.eventLogging.debug' );
79        }
80    }
81
82    /**
83     * Return all schemas registered in extension.json EventLoggingSchemas and
84     * PHP $wgEventLoggingSchemas.  The returned array will map from schema name
85     * to either MediaWiki (metawiki) revision id, or to a relative schema URI
86     * for forward compatibility with Event Platform.
87     * TODO: what happens when two extensions register the same schema with a different revision?
88     *
89     * @return array
90     */
91    private static function getSchemas() {
92        global $wgEventLoggingSchemas;
93
94        $extRegistry = ExtensionRegistry::getInstance();
95        $schemas = $wgEventLoggingSchemas + $extRegistry->getAttribute( 'EventLoggingSchemas' );
96
97        return $schemas;
98    }
99
100    /**
101     * Returns an object with EventLogging specific configuration extracted from
102     * MW Config and from extension attributes.
103     *
104     * @param Config $config
105     * @return array
106     */
107    public static function getEventLoggingConfig( Config $config ) {
108        return [
109            'baseUrl' => $config->get( 'EventLoggingBaseUri' ),
110            'schemasInfo' => self::getSchemas(),
111            'serviceUri' => $config->get( 'EventLoggingServiceUri' ),
112            'queueLingerSeconds' => $config->get( 'EventLoggingQueueLingerSeconds' ),
113            // If this is false, EventLogging will not use stream config.
114            'streamConfigs' => self::loadEventStreamConfigs()
115        ];
116    }
117
118    /**
119     * Wraps getEventLoggingConfig for use with ResourceLoader.
120     *
121     * @param RL\Context $context
122     * @param Config $config
123     * @return array
124     */
125    public static function getModuleData( RL\Context $context, Config $config ) {
126        return self::getEventLoggingConfig( $config );
127    }
128
129    /**
130     * @param User $user
131     * @param array &$preferences
132     */
133    public function onGetPreferences( $user, &$preferences ): void {
134        // See 'ext.eventLogging.debug' module.
135        $preferences['eventlogging-display-console'] = [
136            'type' => 'api',
137        ];
138    }
139
140    /**
141     * Uses the EventStreamConfig extension to return a stream configs map
142     * (stream name -> config).  The target stream configs to export are
143     * selected using the $wgEventLoggingStreamNames MW config variable.
144     * This is expected to be a list of stream names that are defined
145     * in $wgEventStreams.
146     *
147     * EventLogging uses this within the ./data.json data file
148     * from which it loads and configures all of the streams and stream
149     * configs to which it is allowed to submit events.
150     *
151     * This function returns an array mapping explicit stream names
152     * to their configurations.
153     *
154     * NOTE: We need a list of target streams to get configs for.
155     * $wgEventStreams may not explicitly define all stream names;
156     * it supports matching stream names by regexes.  We need to
157     * give the EventStreamConfig StreamConfigs->get function
158     * a list of streams to search for in $wgEventStreams.
159     * $wgEventLoggingStreamNames is that list.
160     *
161     * @return array|bool Selected stream name -> stream configs
162     */
163    private static function loadEventStreamConfigs() {
164        // FIXME: Does the following need to be logged?
165        if ( !ExtensionRegistry::getInstance()->isLoaded( 'EventStreamConfig' ) ) {
166            EventLogging::getLogger()->debug( 'EventStreamConfig is not installed' );
167            return false;
168        }
169
170        $streamConfigs = MediaWikiServices::getInstance()->getService( 'EventLogging.StreamConfigs' );
171
172        if ( $streamConfigs === false ) {
173            return false;
174        }
175
176        // Only send stream config settings that should be sent to the client as part of the
177        // ext.eventLogging RL module.
178        $settingsAllowList = array_flip( self::STREAM_CONFIG_SETTINGS_ALLOWLIST );
179
180        return array_map(
181            static function ( $streamConfig ) use ( $settingsAllowList ) {
182                return array_intersect_key( $streamConfig, $settingsAllowList );
183            },
184            $streamConfigs
185        );
186    }
187}