IFTTT::parseTimeIntoDateTime()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2.0116

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 13
ccs 6
cts 7
cp 0.8571
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2.0116
1
<?php
2
3
namespace dokuwiki\plugin\swarmwebhook\webhooks;
4
5
use DateTime;
6
use dokuwiki\plugin\struct\meta\Schema;
7
use dokuwiki\plugin\swarmwebhook\meta\Response;
8
9
class IFTTT extends AbstractWebhook
10
{
11
    const IFTTT_TIME_FORMAT = 'F d, Y \a\t h:iA';
12
13 1
    public function run($json)
14
    {
15 1
        global $conf, $INPUT;
16
17 1
        if ($conf['allowdebug']) {
18
            dbglog($_SERVER);
19
        }
20
21
        /** @var null|\helper_plugin_swarmwebhook $helper */
22 1
        $helper = plugin_load('helper', 'swarmwebhook');
23 1
        if (!$helper) {
24
            http_status(422, 'swarmwebhook plugin not active at this server');
25
            return;
26
        }
27 1
        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 1
        $webhookData = json_decode($json, true);
34
35 1
        $verificationResult = $this->verifyRequest($webhookData);
36 1
        if ($verificationResult !== true) {
37
            http_status($verificationResult->code, $verificationResult->content);
38
            return;
39
        }
40
41 1
        $ok = $this->handleWebhookPayload($webhookData, $json);
42
43 1
        if ($ok !== true) {
44
            http_status($verificationResult->code, $verificationResult->content);
45
            return;
46
        }
47
48 1
        http_status(202);
49 1
    }
50
51
    /**
52
     * @param array $webhookData
53
     *
54
     * @return true|Response
55
     *
56
     */
57 1
    protected function verifyRequest(array $webhookData)
58
    {
59
        /** @var null|\helper_plugin_swarmwebhook $helper */
60 1
        $helper = plugin_load('helper', 'swarmwebhook');
61 1
        $storedSecret = $helper->getConf('hook secret');
62 1
        if (empty($storedSecret)) {
63 1
            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 1
    protected function handleWebhookPayload(array $webhookData, $json)
84
    {
85 1
        $lookupData = $this->extractDataFromPayload($webhookData);
86 1
        $lookupData['json'] = $json;
87 1
        $lookupData['service'] = 'IFTTT';
88
89
90
        /** @var \helper_plugin_swarmwebhook $helper */
91 1
        $helper = plugin_load('helper', 'swarmwebhook');
92
        try {
93 1
            $schemas = Schema::getAll('lookup');
94 1
            if (!in_array('swarm', $schemas)) {
95 1
                $helper->createNewSwarmSchema();
96
            }
97
98 1
            $helper->deleteCheckinFromLookup($lookupData['checkinid']);
99 1
            $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 1
        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 1
    protected function extractDataFromPayload(array $data)
117
    {
118 1
        $checkinID = $data['ts'];
119 1
        $locationName = $data['VenueName'];
120
121
        // gues time zone
122 1
        $nowTS = time();
123
124 1
        $dateTime = $this->parseTimeIntoDateTime($data['ts'], $nowTS);
125
126
        $lookupData = [
127 1
            'date' => $dateTime->format('Y-m-d'),
128 1
            'time' => $dateTime->format(\DateTime::ATOM),
129 1
            'checkinid' => $checkinID,
130 1
            'locname' => $locationName,
131
        ];
132 1
        if (!empty($data['shout'])) {
133
            $lookupData['shout'] = $data['shout'];
134
        }
135 1
        return $lookupData;
136
    }
137
138
    /**
139
     * @param $timestring
140
     * @param $nowTS
141
     *
142
     * @return \DateTime
143
     */
144 2
    protected function parseTimeIntoDateTime($timestring, $nowTS)
145
    {
146
        //May 25, 2018 at 04:32PM
147
148 2
        $guessedTZOffset = $this->guessTZOffset($timestring, $nowTS);
149 2
        $timeZone = new \DateTimeZone($guessedTZOffset);
150 2
        $dateTime = DateTime::createFromFormat(self::IFTTT_TIME_FORMAT, $timestring, $timeZone);
151
152 2
        if (!$dateTime) {
153
            return new DateTime('now', $timeZone);
154
        }
155
156 2
        return $dateTime;
157
    }
158
159 2
    protected function guessTZOffset($timestring, $nowTS)
160
    {
161 2
        $dateTime = DateTime::createFromFormat(self::IFTTT_TIME_FORMAT, $timestring, new \DateTimeZone('+0000'));
162 2
        if ($dateTime === false) {
163
            dbglog(DateTime::getLastErrors());
164
            $dateTime = new DateTime('now');
165
        }
166 2
        $guessedOffset = round(($dateTime->getTimestamp() - $nowTS)/3600)*100;
167 2
        $sign = $guessedOffset > 0 ? '+' : '';
168
169 2
        return $sign . (string)$guessedOffset;
170
    }
171
}
172