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

IFTTT   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 157
Duplicated Lines 0 %

Test Coverage

Coverage 70.83%

Importance

Changes 0
Metric Value
wmc 19
dl 0
loc 157
ccs 51
cts 72
cp 0.7083
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A parseTimeIntoTimestamp() 0 9 1
B handleWebhookPayload() 0 24 3
B run() 0 36 6
A guessTZOffset() 0 11 3
A extractDataFromPayload() 0 20 2
A verifyRequest() 0 18 4
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