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