1<?php 2 3namespace dokuwiki\plugin\swarmwebhook\webhooks; 4 5use DateTime; 6use dokuwiki\plugin\struct\meta\Schema; 7use dokuwiki\plugin\swarmwebhook\meta\Response; 8 9class IFTTT extends AbstractWebhook 10{ 11 const IFTTT_TIME_FORMAT = 'F d, Y \a\t h:iA'; 12 13 public function run($json) 14 { 15 global $conf, $INPUT; 16 17 if ($conf['allowdebug']) { 18 dbglog($_SERVER); 19 } 20 21 /** @var null|\helper_plugin_swarmwebhook $helper */ 22 $helper = plugin_load('helper', 'swarmwebhook'); 23 if (!$helper) { 24 http_status(422, 'swarmwebhook plugin not active at this server'); 25 return; 26 } 27 if ($helper->getConf('service') !== 'IFTTT') { 28 http_status(422, 'This service is deactivated in the plugin configuration.'); 29 return; 30 } 31 32 // check that we have helper 33 $webhookData = json_decode($json, true); 34 35 $verificationResult = $this->verifyRequest($webhookData); 36 if ($verificationResult !== true) { 37 http_status($verificationResult->code, $verificationResult->content); 38 return; 39 } 40 41 $ok = $this->handleWebhookPayload($webhookData, $json); 42 43 if ($ok !== true) { 44 http_status($verificationResult->code, $verificationResult->content); 45 return; 46 } 47 48 http_status(202); 49 } 50 51 /** 52 * @param array $webhookData 53 * 54 * @return true|Response 55 * 56 */ 57 protected function verifyRequest(array $webhookData) 58 { 59 /** @var null|\helper_plugin_swarmwebhook $helper */ 60 $helper = plugin_load('helper', 'swarmwebhook'); 61 $storedSecret = $helper->getConf('hook secret'); 62 if (empty($storedSecret)) { 63 return true; 64 } 65 66 if (empty($webhookData['secret'])) { 67 return new Response(401, 'Header X_HOOK_SECRET missing!'); 68 } 69 70 if ($webhookData['secret'] !== $storedSecret) { 71 return new Response(403, 'Header X_HOOK_SECRET not identical with configured secret!'); 72 } 73 74 return true; 75 } 76 77 /** 78 * @param array $webhookData 79 * @param string $json 80 * 81 * @return true|Response 82 */ 83 protected function handleWebhookPayload(array $webhookData, $json) 84 { 85 $lookupData = $this->extractDataFromPayload($webhookData); 86 $lookupData['json'] = $json; 87 $lookupData['service'] = 'IFTTT'; 88 89 90 /** @var \helper_plugin_swarmwebhook $helper */ 91 $helper = plugin_load('helper', 'swarmwebhook'); 92 try { 93 $schemas = Schema::getAll('lookup'); 94 if (!in_array('swarm', $schemas)) { 95 $helper->createNewSwarmSchema(); 96 } 97 98 $helper->deleteCheckinFromLookup($lookupData['checkinid']); 99 $helper->saveDataToLookup($lookupData); 100 } catch (\Exception $e) { // FIXME: catch more specific exceptions! 101 $errorMessage = $e->getMessage(); 102 dbglog($errorMessage); 103 return new Response(500, $errorMessage); 104 } 105 106 return true; 107 } 108 109 /** 110 * Extract the data to be saved from the payload 111 * 112 * @param array $data 113 * 114 * @return array 115 */ 116 protected function extractDataFromPayload(array $data) 117 { 118 $checkinID = $data['ts']; 119 $locationName = $data['VenueName']; 120 121 // gues time zone 122 $nowTS = time(); 123 124 $dateTime = $this->parseTimeIntoDateTime($data['ts'], $nowTS); 125 126 $lookupData = [ 127 'date' => $dateTime->format('Y-m-d'), 128 'time' => $dateTime->format(\DateTime::ATOM), 129 'checkinid' => $checkinID, 130 'locname' => $locationName, 131 ]; 132 if (!empty($data['shout'])) { 133 $lookupData['shout'] = $data['shout']; 134 } 135 return $lookupData; 136 } 137 138 /** 139 * @param $timestring 140 * @param $nowTS 141 * 142 * @return \DateTime 143 */ 144 protected function parseTimeIntoDateTime($timestring, $nowTS) 145 { 146 //May 25, 2018 at 04:32PM 147 148 $guessedTZOffset = $this->guessTZOffset($timestring, $nowTS); 149 $timeZone = new \DateTimeZone($guessedTZOffset); 150 $dateTime = DateTime::createFromFormat(self::IFTTT_TIME_FORMAT, $timestring, $timeZone); 151 152 if (!$dateTime) { 153 return new DateTime('now', $timeZone); 154 } 155 156 return $dateTime; 157 } 158 159 protected function guessTZOffset($timestring, $nowTS) 160 { 161 $dateTime = DateTime::createFromFormat(self::IFTTT_TIME_FORMAT, $timestring, new \DateTimeZone('+0000')); 162 if ($dateTime === false) { 163 dbglog(DateTime::getLastErrors()); 164 $dateTime = new DateTime('now'); 165 } 166 $guessedOffset = round(($dateTime->getTimestamp() - $nowTS)/3600)*100; 167 $sign = $guessedOffset > 0 ? '+' : ''; 168 169 return $sign . (string)$guessedOffset; 170 } 171} 172