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