1<?php
2
3require_once dirname(__FILE__) . '/blockonomics/blockonomics.php';
4
5use Blockonomics\Blockonomics;
6
7function blockonomics_config()
8{
9
10 // When loading plugin setup page, run custom JS
11 add_hook(
12 'AdminAreaFooterOutput',
13 1,
14 function () {
15 // Check if the blockonomics module is activated
16 try {
17 // Detect module name from filename.
18 $gatewayModuleName = basename(__FILE__, '.php');
19 // Fetch gateway configuration parameters.
20 $gatewayParams = getGatewayVariables($gatewayModuleName);
21 }
22 catch (exception $e) {
23 return;
24 }
25 $blockonomics = new Blockonomics();
26 include $blockonomics->getLangFilePath();
27 $system_url = \App::getSystemURL();
28 $secret = $blockonomics->getCallbackSecret();
29 $active_currencies = json_encode($blockonomics->getActiveCurrencies());
30 $callback_url = $blockonomics->getCallbackUrl($secret);
31 $trans_text_system_url_error = $_BLOCKLANG['testSetup']['systemUrl']['error'];
32 $trans_text_system_url_fix = $_BLOCKLANG['testSetup']['systemUrl']['fix'];
33 $trans_text_success = $_BLOCKLANG['testSetup']['success'];
34 $trans_text_protocol_error = $_BLOCKLANG['testSetup']['protocol']['error'];
35 $trans_text_protocol_fix = $_BLOCKLANG['testSetup']['protocol']['fix'];
36 $trans_text_testing = $_BLOCKLANG['testSetup']['testing'];
37
38 return <<<HTML
39 <script type="text/javascript">
40 var secret = document.getElementsByName('field[CallbackSecret]');
41 secret.forEach(function(element) {
42 element.value = '$secret';
43 element.readOnly = true;
44 element.parentNode.parentNode.style.display = 'none';
45 });
46 /**
47 * Disable callback url editing
48 */
49 var inputFields = document.getElementsByName('field[CallbackURL]');
50 inputFields.forEach(function(element) {
51 element.value = '$callback_url';
52 element.readOnly = true;
53 });
54
55 /**
56 * Padding for config labels
57 */
58 var inputLabels = document.getElementsByClassName('fieldlabel');
59
60 for(var i = 0; i < inputLabels.length; i++) {
61 inputLabels[i].style.paddingRight = '20px';
62 }
63
64 /**
65 * Set available values for margin setting
66 */
67 var inputMargin = document.getElementsByName('field[Margin]');
68 inputMargin.forEach(function(element) {
69 element.type = 'number';
70 element.min = 0;
71 element.max = 4;
72 element.step = 0.01;
73 });
74 var inputSlack = document.getElementsByName('field[Slack]');
75 inputSlack.forEach(function(element) {
76 element.type = 'number';
77 element.min = 0;
78 element.max = 10;
79 element.step = 0.01;
80 });
81
82 /**
83 * Generate Settings and Currency Headers
84 */
85 const blockonomicsTable = document.getElementById("Payment-Gateway-Config-blockonomics");
86 const headerStyles = 'text-decoration: underline; margin-bottom: 2px';
87 //Add Settings Row
88 const settingsRow = blockonomicsTable.insertRow( 3 );
89 settingsRow.insertCell(0);
90 const settingsFieldArea = settingsRow.insertCell(1);
91
92 const settingsHeader = document.createElement('h4');
93 settingsHeader.style.cssText = headerStyles
94 settingsHeader.textContent = 'Settings';
95 settingsFieldArea.appendChild(settingsHeader);
96
97 //Currency header
98 const currencyRow = blockonomicsTable.insertRow( 11 );
99 currencyRow.insertCell(0);
100 const currencyFieldArea = currencyRow.insertCell(1);
101
102 const currencyHeader = document.createElement('h4');
103 currencyHeader.style.cssText = headerStyles
104 currencyHeader.textContent = 'Currencies';
105 currencyFieldArea.appendChild(currencyHeader);
106
107 /**
108 * Generate Advanced Settings Button
109 */
110 //get advanced settings HTML elements
111 const timePeriod = blockonomicsTable.rows[7];
112 const extraMargin = blockonomicsTable.rows[8];
113 const underSlack = blockonomicsTable.rows[9];
114 const confirmations = blockonomicsTable.rows[10];
115
116 timePeriod.style.display = "none";
117 extraMargin.style.display = "none";
118 underSlack.style.display = "none";
119 confirmations.style.display = "none";
120
121 var advancedSettingsRow = blockonomicsTable.insertRow(7);
122 var advancedSettingsLabelCell = advancedSettingsRow.insertCell(0);
123 var advancedSettingsFieldArea = advancedSettingsRow.insertCell(1);
124
125 var advancedLink = document.createElement('a');
126 advancedLink.classList.add('cursor');
127 advancedLink.textContent = 'Advanced Settings ▼';
128 advancedSettingsFieldArea.appendChild(advancedLink);
129
130 let showingAdvancedSettings = false;
131 advancedLink.onclick = function() {
132 advancedLink.textContent = (showingAdvancedSettings) ? 'Advanced Settings ▼' : 'Advanced Settings ▲';
133 if (showingAdvancedSettings) {
134 timePeriod.style.display = "none";
135 extraMargin.style.display = "none";
136 underSlack.style.display = "none";
137 confirmations.style.display = "none";
138 } else {
139 timePeriod.style.display = "table-row";
140 extraMargin.style.display = "table-row";
141 underSlack.style.display = "table-row";
142 confirmations.style.display = "table-row";
143 }
144 showingAdvancedSettings = !showingAdvancedSettings;
145 }
146
147 // Inject Custom Styles
148
149 let style = document.createElement('style');
150 style.setAttribute('type', 'text/css');
151 style.innerHTML = 'a.cursor {cursor: pointer; text-decoration: none;} a.cursor:hover {text-decoration: none;}';
152 document.head.appendChild(style);
153
154 /**
155 * Generate Test Setup button
156 */
157 const saveButtonCell = blockonomicsTable.rows[ blockonomicsTable.rows.length - 1 ].children[1];
158 saveButtonCell.style.backgroundColor = "white";
159
160 const newBtn = document.createElement('BUTTON');
161 newBtn.setAttribute('type', 'button');
162 newBtn.className = "btn btn-primary";
163 newBtn.textContent = "Test Setup";
164
165 saveButtonCell.appendChild(newBtn);
166
167 function reqListener (response, cells) {
168 var responseObj = {};
169
170 try {
171 responseObj = JSON.parse(response);
172 } catch (err) {
173 var testSetupUrl = "$system_url" + "modules/gateways/blockonomics/testsetup.php";
174 responseObj = {};
175 Object.keys(cells).forEach(crypto => {
176 responseObj[crypto] = '$trans_text_system_url_error ' + testSetupUrl + '. $trans_text_system_url_fix';
177 });
178 }
179
180 if (Object.keys(responseObj).length) {
181 Object.keys(cells).forEach(crypto => {
182 let e = responseObj[crypto]
183 if (e) {
184 cells[crypto].innerHTML = "<label style='color:red;'>Error:</label> " + e +
185 "<br>For more information, please consult <a href='https://blockonomics.freshdesk.com/support/solutions/articles/33000215104-troubleshooting-unable-to-generate-new-address' target='_blank'>this troubleshooting article</a>";
186 } else {
187 cells[crypto].innerHTML = "<label style='color:green;'>$trans_text_success</label>";
188 }
189 })
190 } else {
191 Object.keys(cells).forEach(crypto => {
192 cells[crypto].innerHTML = "<label style='color:green;'>$trans_text_success</label>";
193 })
194 }
195 newBtn.disabled = false;
196 }
197
198 function handle_ajax_save(res, xhr, settings){
199 if (settings.url == "configgateways.php?action=save" && settings.data.includes("module=blockonomics")) {
200 // We detected the Blockonomics Request
201
202 // Remove the listener
203 jQuery(document).off('ajaxComplete', handle_ajax_save)
204
205 // Do the Test
206 if (xhr.status == 200 && sessionStorage.getItem("runTest"))
207 doTest();
208
209 // Remove Test Session Key if exists
210 sessionStorage.removeItem("runTest");
211 }
212 }
213
214 newBtn.onclick = function(e) {
215 e.preventDefault();
216 if(typeof jQuery != 'undefined') {
217 jQuery(document).on('ajaxComplete', handle_ajax_save)
218 }
219 sessionStorage.setItem("runTest", true);
220 if(saveButtonCell.querySelector('button[type=submit]')){
221 saveButtonCell.querySelector('button[type=submit]').click();
222 } else {
223 saveButtonCell.querySelector('input[type=submit]').click();
224 }
225 }
226
227 const addTestResultRow = (rowsFromBottom) => {
228 const testSetupResultRow = blockonomicsTable.insertRow(blockonomicsTable.rows.length - rowsFromBottom);
229 testSetupResultRow.classList.add('blockonomics-test-row');
230
231 const testSetupResultLabel = testSetupResultRow.insertCell(0);
232 const testSetupResultCell = testSetupResultRow.insertCell(1);
233 testSetupResultRow.style.display = "none";
234 testSetupResultRow.style.display = "table-row";
235 testSetupResultCell.className = "fieldarea";
236 return testSetupResultCell;
237 }
238
239 function doTest() {
240 const form = new FormData(saveButtonCell.closest('form'))
241 let activeCryptos = [];
242
243 if(form.getAll('field[btcEnabled]').includes('on'))
244 activeCryptos.push('btc');
245
246 if(form.getAll('field[bchEnabled]').includes('on'))
247 activeCryptos.push('bch');
248
249 let CELLS = {};
250
251 // Fix for AJAX based Submission, removes previous elements before adding new
252 document.querySelectorAll('.blockonomics-test-row').forEach(el => el.remove());
253
254 activeCryptos.forEach(crypto => {
255 rowFromBottom = (crypto === 'btc') ? 3 : 2
256 CELLS[crypto] = addTestResultRow (rowFromBottom);
257 })
258
259 var testSetupUrl = "$system_url" + "modules/gateways/blockonomics/testsetup.php";
260
261 try {
262 var systemUrlProtocol = new URL("$system_url").protocol;
263 } catch (err) {
264 var systemUrlProtocol = '';
265 }
266
267 if (systemUrlProtocol != location.protocol) {
268 Object.keys(CELLS).forEach(crypto => {
269 let cell = CELLS[crypto]
270 cell.innerHTML = "<label style='color:red;'>$trans_text_protocol_error</label> \
271 $trans_text_protocol_fix";
272 })
273 } else {
274
275 let oReq = new XMLHttpRequest();
276 oReq.addEventListener("load", function() {
277 if(this.status != 200) {
278 let status_code = this.status
279 let status_msg = this.statusText
280
281 let response = {}
282 Object.keys(CELLS).forEach(crypto => {
283 response[crypto] = "An Error Occurred. Status Code: " + status_code + " (" + status_msg + ")"
284 })
285 reqListener(JSON.stringify(response), CELLS)
286 } else {
287 reqListener(this.responseText, CELLS)
288 }
289 });
290 oReq.addEventListener("error", function(error) {
291 let response = {}
292 Object.keys(CELLS).forEach(crypto => {
293 response[crypto] = "Network Error Occurred."
294 })
295 reqListener(JSON.stringify(response), CELLS)
296 });
297 oReq.open("GET", testSetupUrl);
298 newBtn.disabled = true;
299 Object.keys(CELLS).forEach(crypto => {
300 let cell = CELLS[crypto]
301 cell.innerHTML = "$trans_text_testing";
302 })
303 oReq.send();
304
305 }
306
307 }
308
309 // For Non AJAX Based Submission
310 if(sessionStorage.getItem("runTest") && !document.querySelector('#manage .errorbox')) {
311 sessionStorage.removeItem("runTest");
312 doTest()
313 }
314
315 </script>
316HTML;
317 }
318 );
319
320 $blockonomics = new Blockonomics();
321 include $blockonomics->getLangFilePath();
322 $blockonomics->createOrderTableIfNotExist();
323
324 $settings_array = [
325 'FriendlyName' => [
326 'Type' => 'System',
327 'Value' => 'Blockonomics',
328 ],
329 [
330 'FriendlyName' => '<span style="color:grey;">' . $_BLOCKLANG['version']['title'] . '</span>',
331 'Description' => '<span style="color:grey;">' . $blockonomics->getVersion() . '</span>',
332 ],
333 ];
334 $settings_array['ApiKey'] = [
335 'FriendlyName' => $_BLOCKLANG['apiKey']['title'],
336 'Description' => $_BLOCKLANG['apiKey']['description'],
337 'Type' => 'text',
338 ];
339
340 $settings_array['CallbackSecret'] = [
341 'FriendlyName' => $_BLOCKLANG['callbackSecret']['title'],
342 'Type' => 'text',
343 ];
344 $settings_array['CallbackURL'] = [
345 'FriendlyName' => $_BLOCKLANG['callbackUrl']['title'],
346 'Type' => 'text',
347 ];
348 $settings_array['TimePeriod'] = [
349 'FriendlyName' => $_BLOCKLANG['timePeriod']['title'],
350 'Type' => 'dropdown',
351 'Options' => [
352 '10' => '10',
353 '15' => '15',
354 '20' => '20',
355 '25' => '25',
356 '30' => '30',
357 ],
358 'Description' => $_BLOCKLANG['timePeriod']['description'],
359 ];
360 $settings_array['Margin'] = [
361 'FriendlyName' => $_BLOCKLANG['margin']['title'],
362 'Type' => 'text',
363 'Size' => '5',
364 'Default' => 0,
365 'Description' => $_BLOCKLANG['margin']['description'],
366 ];
367 $settings_array['Slack'] = [
368 'FriendlyName' => $_BLOCKLANG['slack']['title'],
369 'Type' => 'text',
370 'Size' => '5',
371 'Default' => 0,
372 'Description' => $_BLOCKLANG['slack']['description'],
373 ];
374 $settings_array['Confirmations'] = [
375 'FriendlyName' => $_BLOCKLANG['confirmations']['title'],
376 'Type' => 'dropdown',
377 'Default' => 2,
378 'Options' => [
379 '2' => '2 (' . $_BLOCKLANG['confirmations']['recommended'] . ')',
380 '1' => '1',
381 '0' => '0',
382 ],
383 'Description' => $_BLOCKLANG['confirmations']['description'],
384 ];
385 $blockonomics_currencies = $blockonomics->getSupportedCurrencies();
386 foreach ($blockonomics_currencies as $code => $currency) {
387 $settings_array[$code . 'Enabled'] = [
388 'FriendlyName' => $currency['name'] .' (' . strtoupper($code) . ')',
389 'Type' => 'yesno',
390 'Description' => $_BLOCKLANG['enabled'][$code.'_description'],
391 ];
392 if ($code == 'btc') {
393 $settings_array[$code . 'Enabled']['Default'] = true;
394 }
395 }
396 return $settings_array;
397}
398
399function blockonomics_link($params)
400{
401 if (false === isset($params) || true === empty($params)) {
402 exit('[ERROR] In modules/gateways/blockonomics.php::Blockonomics_link() function: Missing or invalid $params data.');
403 }
404
405 $blockonomics = new Blockonomics();
406 $order_params = $blockonomics->get_order_checkout_params($params);
407
408 $form_url = \App::getSystemURL() . 'modules/gateways/blockonomics/payment.php';
409
410 //pass only the uuid to the payment page
411 $form = '<form action="' . $form_url . '" method="GET">';
412 foreach ($order_params as $name => $param) {
413 $form .= '<input type="hidden" name="' . $name . '" value="' . $param . '"/>';
414 }
415 $form .= '<input type="submit" value="' . $params['langpaynow'] . '"/>';
416 $form .= '</form>';
417
418 return $form;
419}