Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 81 |
|
0.00% |
0 / 8 |
CRAP | |
0.00% |
0 / 1 |
FundraiserLandingPage | |
0.00% |
0 / 81 |
|
0.00% |
0 / 8 |
506 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 50 |
|
0.00% |
0 / 1 |
72 | |||
getRobotPolicy | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
fundraiserLandingPageMakeSafe | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
20 | |||
fundraiserLandingPageSwitchLanguage | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
fundraiserLandingPageSwitchCountry | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
isFundraiseUp | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getFundraiseUpJavascript | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\FundraiserLandingPage\Specials; |
4 | |
5 | /* |
6 | * SpecialPage definition for FundraiserLandingPage. Extending UnlistedSpecialPage |
7 | * since this page does not need to listed in Special:SpecialPages. |
8 | * |
9 | * @author Peter Gehres <pgehres@wikimedia.org> |
10 | */ |
11 | |
12 | use MediaWiki\Parser\Parser; |
13 | use MediaWiki\SpecialPage\UnlistedSpecialPage; |
14 | use MediaWiki\Title\Title; |
15 | |
16 | class FundraiserLandingPage extends UnlistedSpecialPage { |
17 | public function __construct() { |
18 | parent::__construct( 'FundraiserLandingPage' ); |
19 | } |
20 | |
21 | /** |
22 | * @param string $par |
23 | */ |
24 | public function execute( $par ) { |
25 | $config = $this->getConfig(); |
26 | |
27 | $out = $this->getOutput(); |
28 | $request = $this->getRequest(); |
29 | |
30 | // Set squid age |
31 | $out->setCdnMaxage( $config->get( 'FundraiserLandingPageMaxAge' ) ); |
32 | |
33 | if ( $this->isFundraiseUp() ) { |
34 | $out->addScript( $this->getFundraiseUpJavascript() ); |
35 | } |
36 | $this->setHeaders(); |
37 | |
38 | // set the page title to something useful |
39 | $titleMsg = $this->msg( 'donate_interface-make-your-donation' ); |
40 | if ( !is_callable( [ $out, 'setPageTitleMsg' ] ) ) { |
41 | // Backward compatibility with MW < 1.41 |
42 | $out->setPageTitle( $titleMsg ); |
43 | } else { |
44 | // MW >= 1.41 |
45 | $out->setPageTitleMsg( $titleMsg ); |
46 | } |
47 | |
48 | // and add a <meta name="description"> tag to give search engines a useful blurb |
49 | $out->addMeta( 'description', $this->msg( 'fundraiserlandingpage-meta-description' ) ); |
50 | |
51 | // Instruct browsers to pre-fetch the DNS for payments-wiki to speed up loading the next form |
52 | $out->addHeadItem( |
53 | 'payments-dns-prefetch', |
54 | '<link rel="dns-prefetch" href="' . $this->getConfig()->get( 'FundraiserLandingPagePaymentsHost' ) . '" />' |
55 | ); |
56 | |
57 | // clear output variable to be safe |
58 | $output = ''; |
59 | |
60 | $fundraiserLPDefaults = $config->get( 'FundraiserLPDefaults' ); |
61 | // begin generating the template call |
62 | $template = self::fundraiserLandingPageMakeSafe( |
63 | $request->getText( 'template', $fundraiserLPDefaults[ 'template' ] ) |
64 | ); |
65 | $output .= "{{ $template\n"; |
66 | |
67 | // get the required variables (except template and country) to use for the landing page |
68 | $requiredParams = [ |
69 | 'appeal', |
70 | 'appeal-template', |
71 | 'form-template', |
72 | 'form-countryspecific' |
73 | ]; |
74 | foreach ( $requiredParams as $requiredParam ) { |
75 | $param = self::fundraiserLandingPageMakeSafe( |
76 | $request->getText( $requiredParam, $fundraiserLPDefaults[$requiredParam] ) |
77 | ); |
78 | // Add them to the template call |
79 | $output .= "| $requiredParam = $param\n"; |
80 | } |
81 | |
82 | // get the country code |
83 | $country = $request->getVal( 'country' ); |
84 | // If country still isn't set, set it to the default |
85 | if ( !$country ) { |
86 | $country = $fundraiserLPDefaults[ 'country' ]; |
87 | } |
88 | $country = self::fundraiserLandingPageMakeSafe( $country ); |
89 | $output .= "| country = $country\n"; |
90 | |
91 | // @phan-suppress-next-line PhanUselessBinaryAddRight |
92 | $excludeKeys = $requiredParams + [ 'template', 'country', 'title' ]; |
93 | |
94 | // if there are any other parameters passed in the querystring, add them |
95 | if ( $request->getQueryValuesOnly() ) { |
96 | foreach ( $request->getQueryValuesOnly() as $k_unsafe => $v_unsafe ) { |
97 | // skip the required variables |
98 | if ( in_array( $k_unsafe, $excludeKeys ) ) { |
99 | continue; |
100 | } |
101 | // get the variable's name and value |
102 | $key = self::fundraiserLandingPageMakeSafe( $k_unsafe ); |
103 | $val = self::fundraiserLandingPageMakeSafe( $v_unsafe ); |
104 | // print to the template in wiki-syntax |
105 | $output .= "| $key = $val\n"; |
106 | } |
107 | } |
108 | |
109 | // close the template call |
110 | $output .= "}}"; |
111 | |
112 | // Hijack parser internals to workaround T156184. This should be safe |
113 | // since we've sanitized all params. |
114 | $parserOptions = $out->parserOptions(); |
115 | $parserOptions->setAllowUnsafeRawHtml( true ); |
116 | |
117 | // print the output to the page |
118 | $out->addWikiTextAsInterface( $output ); |
119 | } |
120 | |
121 | /** |
122 | * Mark the page as allowed for search engine indexing |
123 | * (default for SpecialPages is noindex) |
124 | * |
125 | * @return string |
126 | */ |
127 | protected function getRobotPolicy() { |
128 | return 'index,nofollow'; |
129 | } |
130 | |
131 | /** |
132 | * This function limits the possible characters passed as template keys and |
133 | * values to letters, numbers, hyphens, underscores, and the forward slash. |
134 | * The function also performs standard escaping of the passed values. |
135 | * |
136 | * @param mixed $value The unsafe value to escape and check for invalid characters |
137 | * @param string $default A default value to return if when making the $string safe no |
138 | * results are returned. |
139 | * |
140 | * @return string A string matching the regex or an empty string |
141 | * @suppress SecurityCheck-DoubleEscaped double escaping is on purpose per the inline |
142 | * comment |
143 | */ |
144 | private static function fundraiserLandingPageMakeSafe( $value, $default = '' ) { |
145 | if ( $default != '' ) { |
146 | $default = self::fundraiserLandingPageMakeSafe( $default ); |
147 | } |
148 | |
149 | if ( !is_string( $value ) ) { |
150 | // In case someone has passed in an array as a request parameter |
151 | return $default; |
152 | } |
153 | |
154 | $num = preg_match( '/^([-a-zA-Z0-9_\/]+)$/', $value, $matches ); |
155 | |
156 | if ( $num == 1 ) { |
157 | # theoretically this is overkill, but better safe than sorry |
158 | return wfEscapeWikiText( htmlspecialchars( $matches[1] ) ); |
159 | } |
160 | return $default; |
161 | } |
162 | |
163 | /** |
164 | * Attempts to load a language localized template. Precedence is Language, |
165 | * Country, Root. It is assumed that all parts of the title are separated |
166 | * with '/'. |
167 | * |
168 | * @param Parser $parser Reference to the WM parser object |
169 | * @param string $page The template page root to load |
170 | * @param string $language The language to attempt to localize onto |
171 | * @param string $country The country to attempt to localize onto |
172 | * |
173 | * @return array The wikitext template |
174 | */ |
175 | public static function fundraiserLandingPageSwitchLanguage( $parser, $page = '', |
176 | $language = 'en', $country = 'XX' |
177 | ) { |
178 | $page = self::fundraiserLandingPageMakeSafe( $page ); |
179 | $country = self::fundraiserLandingPageMakeSafe( $country, 'XX' ); |
180 | $language = self::fundraiserLandingPageMakeSafe( $language, 'en' ); |
181 | |
182 | if ( Title::newFromText( "Template:$page/$language/$country" )->exists() ) { |
183 | $tpltext = "$page/$language/$country"; |
184 | } elseif ( Title::newFromText( "Template:$page/$language" )->exists() ) { |
185 | $tpltext = "$page/$language"; |
186 | } else { |
187 | // If all the variants don't exist, then merely return the base. If |
188 | // something really screwy happened and the base doesn't exist either |
189 | // we will let the WM error handler sort it out. |
190 | |
191 | $tpltext = $page; |
192 | } |
193 | |
194 | return [ "{{Template:$tpltext}}", 'noparse' => false ]; |
195 | } |
196 | |
197 | /** |
198 | * Attempts to load a language localized template. Precedence is Country, |
199 | * Language, Root. It is assumed that all parts of the title are separated |
200 | * with '/'. |
201 | * |
202 | * @param Parser $parser Reference to the WM parser object |
203 | * @param string $page The template page root to load |
204 | * @param string $country The country to attempt to localize onto |
205 | * @param string $language The language to attempt to localize onto |
206 | * |
207 | * @return array The wikitext template |
208 | */ |
209 | public static function fundraiserLandingPageSwitchCountry( $parser, $page = '', $country = 'XX', |
210 | $language = 'en' |
211 | ) { |
212 | $page = self::fundraiserLandingPageMakeSafe( $page ); |
213 | $country = self::fundraiserLandingPageMakeSafe( $country, 'XX' ); |
214 | $language = self::fundraiserLandingPageMakeSafe( $language, 'en' ); |
215 | |
216 | if ( Title::newFromText( "Template:$page/$country/$language" )->exists() ) { |
217 | $tpltext = "$page/$country/$language"; |
218 | |
219 | } elseif ( Title::newFromText( "Template:$page/$country" )->exists() ) { |
220 | $tpltext = "$page/$country"; |
221 | |
222 | } else { |
223 | // If all the variants don't exist, then merely return the base. If |
224 | // something really screwy happened and the base doesn't exist either |
225 | // we will let the WM error handler sort it out. |
226 | |
227 | $tpltext = $page; |
228 | } |
229 | |
230 | return [ "{{Template:$tpltext}}", 'noparse' => false ]; |
231 | } |
232 | |
233 | /** |
234 | * Check if template is fundraiseup |
235 | * @return bool |
236 | */ |
237 | private function isFundraiseUp() { |
238 | return $this->getRequest()->getVal( 'fundraiseupScript' ) === "1"; |
239 | } |
240 | |
241 | /** |
242 | * Javascript to add fundraiseup to DonateWiki page |
243 | * |
244 | * @return string |
245 | */ |
246 | private function getFundraiseUpJavascript() { |
247 | return <<<EOF |
248 | <script>(function(w,d,s,n,a){if(!w[n]){var l='call,catch,on,once,set,then,track' |
249 | .split(','),i,o=function(n){return'function'==typeof n?o.l.push([arguments])&&o |
250 | :function(){return o.l.push([n,arguments])&&o}},t=d.getElementsByTagName(s)[0], |
251 | j=d.createElement(s);j.async=!0;j.src='https://cdn.fundraiseup.com/widget/'+a; |
252 | t.parentNode.insertBefore(j,t);o.s=Date.now();o.v=4;o.h=w.location.href;o.l=[]; |
253 | for(i=0;i<7;i++)o[l[i]]=o(l[i]);w[n]=o} |
254 | })(window,document,'script','FundraiseUp','AVLMPSRU'); |
255 | </script> |
256 | EOF; |
257 | } |
258 | } |