Completed
Push — develop ( 64d4ff...3a38fe )
by Michael
01:35
created

IFTTT::parseTimeIntoTimestamp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 2
crap 1
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->parseTimeIntoTimestamp($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 parseTimeIntoTimestamp($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
        return $dateTime;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $dateTime could also return false which is incompatible with the documented return type DateTime. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
153
    }
154
155 2
    protected function guessTZOffset($timestring, $nowTS)
156
    {
157 2
        $dateTime = DateTime::createFromFormat(self::IFTTT_TIME_FORMAT, $timestring, new \DateTimeZone('+0000'));
158 2
        if ($dateTime === false) {
159
            dbglog(DateTime::getLastErrors());
160
            $dateTime = new DateTime('now');
161
        }
162 2
        $guessedOffset = round(($dateTime->getTimestamp() - $nowTS)/3600)*100;
163 2
        $sign = $guessedOffset > 0 ? '+' : '';
164
165 2
        return $sign . (string)$guessedOffset;
166
    }
167
}
168