Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 45 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
JsonSchemaHooks | |
0.00% |
0 / 45 |
|
0.00% |
0 / 6 |
420 | |
0.00% |
0 / 1 |
isSchemaNamespaceEnabled | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
onApiMain__moduleManager | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
onCodeEditorGetPageLanguage | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
onEditFilterMergedContent | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
42 | |||
onBeforePageDisplay | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
20 | |||
onMovePageIsValidMove | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | /** |
3 | * Hooks for managing JSON Schema namespace and content model. |
4 | * |
5 | * @file |
6 | * @ingroup Extensions |
7 | * @ingroup EventLogging |
8 | * |
9 | * @author Ori Livneh <ori@wikimedia.org> |
10 | */ |
11 | |
12 | // phpcs:disable MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName |
13 | |
14 | namespace MediaWiki\Extension\EventLogging; |
15 | |
16 | use MediaWiki\Api\ApiModuleManager; |
17 | use MediaWiki\Api\Hook\ApiMain__moduleManagerHook; |
18 | use MediaWiki\Content\Content; |
19 | use MediaWiki\Context\IContextSource; |
20 | use MediaWiki\EditPage\EditPage; |
21 | use MediaWiki\Extension\EventLogging\Libs\JsonSchemaValidation\JsonSchemaException; |
22 | use MediaWiki\Hook\EditFilterMergedContentHook; |
23 | use MediaWiki\Hook\MovePageIsValidMoveHook; |
24 | use MediaWiki\Output\Hook\BeforePageDisplayHook; |
25 | use MediaWiki\Output\OutputPage; |
26 | use MediaWiki\Status\Status; |
27 | use MediaWiki\Title\Title; |
28 | use MediaWiki\User\User; |
29 | use Skin; |
30 | |
31 | class JsonSchemaHooks implements |
32 | BeforePageDisplayHook, |
33 | EditFilterMergedContentHook, |
34 | MovePageIsValidMoveHook, |
35 | ApiMain__moduleManagerHook |
36 | { |
37 | |
38 | /** |
39 | * Convenience function to determine whether the |
40 | * Schema namespace is enabled |
41 | * |
42 | * @return bool |
43 | */ |
44 | public static function isSchemaNamespaceEnabled() { |
45 | global $wgEventLoggingDBname, $wgDBname; |
46 | |
47 | return $wgEventLoggingDBname === $wgDBname; |
48 | } |
49 | |
50 | /** |
51 | * ApiMain::moduleManager hook to register jsonschema |
52 | * API module only if the Schema namespace is enabled |
53 | * |
54 | * @param ApiModuleManager $moduleManager |
55 | */ |
56 | public function onApiMain__moduleManager( $moduleManager ): void { |
57 | if ( self::isSchemaNamespaceEnabled() ) { |
58 | $moduleManager->addModule( |
59 | 'jsonschema', |
60 | 'action', |
61 | ApiJsonSchema::class |
62 | ); |
63 | } |
64 | } |
65 | |
66 | /** |
67 | * Declares JSON as the code editor language for Schema: pages. |
68 | * This hook only runs if the CodeEditor extension is enabled. |
69 | * |
70 | * @param Title $title |
71 | * @param string &$lang Page language. |
72 | */ |
73 | public static function onCodeEditorGetPageLanguage( $title, &$lang ): void { |
74 | if ( self::isSchemaNamespaceEnabled() |
75 | && $title->inNamespace( NS_SCHEMA ) |
76 | ) { |
77 | $lang = 'json'; |
78 | } |
79 | } |
80 | |
81 | /** |
82 | * Validates that the revised contents are valid JSON. |
83 | * If not valid, rejects edit with error message. |
84 | * |
85 | * @param IContextSource $context |
86 | * @param Content $content |
87 | * @param Status $status |
88 | * @param string $summary |
89 | * @param User $user |
90 | * @param bool $minoredit |
91 | * @return bool |
92 | */ |
93 | public function onEditFilterMergedContent( |
94 | IContextSource $context, |
95 | Content $content, |
96 | Status $status, |
97 | $summary, |
98 | User $user, |
99 | $minoredit |
100 | ): bool { |
101 | $title = $context->getTitle(); |
102 | |
103 | if ( !self::isSchemaNamespaceEnabled() |
104 | || !$title->inNamespace( NS_SCHEMA ) |
105 | ) { |
106 | return true; |
107 | } |
108 | |
109 | if ( !preg_match( '/^[a-zA-Z0-9_-]{1,63}$/', $title->getText() ) ) { |
110 | $status->fatal( 'badtitle' ); |
111 | // @todo Remove this line after this extension do not support mediawiki version 1.36 and before |
112 | $status->value = EditPage::AS_HOOK_ERROR_EXPECTED; |
113 | return false; |
114 | } |
115 | |
116 | if ( !$content instanceof JsonSchemaContent ) { |
117 | return true; |
118 | } |
119 | |
120 | try { |
121 | $content->validate(); |
122 | return true; |
123 | } catch ( JsonSchemaException $e ) { |
124 | $status->fatal( $context->msg( $e->getCode(), $e->args ) ); |
125 | // @todo Remove this line after this extension do not support mediawiki version 1.36 and before |
126 | $status->value = EditPage::AS_HOOK_ERROR_EXPECTED; |
127 | return false; |
128 | } |
129 | } |
130 | |
131 | /** |
132 | * Add the revision id as the subtitle on NS_SCHEMA pages. |
133 | * |
134 | * @param OutputPage $out |
135 | * @param Skin $skin |
136 | */ |
137 | public function onBeforePageDisplay( $out, $skin ): void { |
138 | $title = $out->getTitle(); |
139 | $revId = $out->getRevisionId(); |
140 | |
141 | if ( self::isSchemaNamespaceEnabled() |
142 | && $title->inNamespace( NS_SCHEMA ) |
143 | && $revId !== null |
144 | ) { |
145 | $out->addSubtitle( $out->msg( 'eventlogging-revision-id' ) |
146 | // We use 'rawParams' rather than 'numParams' to make it |
147 | // easy to copy/paste the value into code. |
148 | ->rawParams( $revId ) |
149 | ->escaped() ); |
150 | } |
151 | } |
152 | |
153 | /** |
154 | * Prohibit moving (renaming) Schema pages, as doing so violates |
155 | * immutability guarantees. |
156 | * |
157 | * @param Title $currentTitle |
158 | * @param Title $newTitle |
159 | * @param Status $status |
160 | * @return bool |
161 | */ |
162 | public function onMovePageIsValidMove( |
163 | $currentTitle, $newTitle, $status |
164 | ) { |
165 | if ( !self::isSchemaNamespaceEnabled() ) { |
166 | // Namespace isn't even enabled |
167 | return true; |
168 | } elseif ( $currentTitle->inNamespace( NS_SCHEMA ) ) { |
169 | $status->fatal( 'eventlogging-error-move-source' ); |
170 | return false; |
171 | } elseif ( $newTitle->inNamespace( NS_SCHEMA ) ) { |
172 | $status->fatal( 'eventlogging-error-move-destination' ); |
173 | return false; |
174 | } |
175 | return true; |
176 | } |
177 | } |