Passed
Pull Request — master (#30)
by Guillaume
37:05 queued 35:32
created

Clockify::stopCurrentTimer()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 25
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3.0067

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 3
eloc 12
c 1
b 0
f 1
nc 3
nop 0
dl 0
loc 25
ccs 10
cts 11
cp 0.9091
crap 3.0067
rs 9.8666
1
<?php
2
3
namespace Godbout\Alfred\Time\Services;
4
5
use Carbon\Carbon;
6
use Godbout\Alfred\Time\Workflow;
7
use GuzzleHttp\Client;
8
9
class Clockify extends TimerService
10
{
11
    private $client;
12
13
    private $data = null;
0 ignored issues
show
introduced by
The private property $data is not used, and could be removed.
Loading history...
14
15
16 69
    public function __construct($apiToken)
17
    {
18 69
        $this->client = new Client([
19 69
            'base_uri' => 'https://api.clockify.me/api/v1/',
20
            'headers' => [
21 69
                'content-type' => 'application/json',
22 69
                'X-Api-Key' => $apiToken
23
            ]
24
        ]);
25 69
    }
26
27 19
    public function projects()
28
    {
29
        try {
30 19
            $user = json_decode(
31 19
                $this->client->get("user")->getBody()->getContents()
32
            );
33
34 14
            Workflow::getConfig()->write('clockify.active_workspace_id', $user->activeWorkspace);
35
36 14
            $response = $this->client->get("workspaces/{$user->activeWorkspace}/projects");
37
38 14
            $projects = json_decode($response->getBody()->getContents());
39
40 14
            return array_column($projects, 'name', 'id');
41 5
        } catch (\Exception $e) {
42 5
            return [];
43
        }
44
    }
45
46 19
    public function tags()
47
    {
48
        try {
49 19
            $workspaceId = Workflow::getConfig()->read('clockify.active_workspace_id');
50
51 19
            $response = $this->client->get("workspaces/$workspaceId/tags");
52 14
            $tags = json_decode($response->getBody()->getContents());
53
54 14
            return array_column($tags, 'name', 'id');
55 5
        } catch (\Exception $e) {
56 5
            return [];
57
        }
58
    }
59
60 35
    public function startTimer()
61
    {
62
        try {
63 35
            $workspaceId = Workflow::getConfig()->read('clockify.active_workspace_id');
64
65 35
            $response = $this->client->post("workspaces/$workspaceId/time-entries", [
66 15
                'json' => [
67 35
                    'start' => (new \DateTime())->format('Y-m-d\TH:i:s\Z'),
68 35
                    'description' => getenv('timer_description'),
69 35
                    'projectId' => getenv('timer_project_id'),
70 35
                    'tagIds' => getenv('timer_tag_id') ? [getenv('timer_tag_id')] : [''],
71
                ]
72
            ]);
73
74 35
            $timer = json_decode($response->getBody()->getContents());
75
76 35
            if (! isset($timer->id)) {
77 35
                return false;
78
            }
79
        } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The type Godbout\Alfred\Time\Services\Exception was not found. Did you mean Exception? If so, make sure to prefix the type with \.
Loading history...
80
            return false;
81
        }
82
83 35
        return $timer->id;
84
    }
85
86 35
    public function stopCurrentTimer()
87
    {
88 35
        $user = json_decode(
89 35
            $this->client->get("user")->getBody()->getContents()
90
        );
91
92 35
        if ($timerId = $this->runningTimer()) {
0 ignored issues
show
Unused Code introduced by
The assignment to $timerId is dead and can be removed.
Loading history...
93 35
            $response = $this->client->patch("workspaces/{$user->activeWorkspace}/user/{$user->id}/time-entries", [
94
                'json' => [
95 35
                    'end' => (new \DateTime())->format('Y-m-d\TH:i:s\Z'),
96
                ]
97
            ]) ;
98
99 35
            $timer = json_decode($response->getBody()->getContents());
100
101 35
            if (! isset($timer->timeInterval->end)) {
102
                throw new Exception("Can't stop current running timer.", 1);
103
104
                return false;
0 ignored issues
show
Unused Code introduced by
return false is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
105
            }
106
107 35
            return true;
108
        }
109
110 7
        return false;
111
    }
112
113 69
    public function runningTimer()
114
    {
115
        try {
116 69
            $user = json_decode(
117 69
                $this->client->get("user")->getBody()->getContents()
118
            );
119
120 69
            $response = $this->client->get(
121 69
                "workspaces/{$user->activeWorkspace}/user/{$user->id}/time-entries?in-progress=true"
122
            );
123
124 69
            $timer = json_decode($response->getBody()->getContents());
125
126 69
            return $timer[0]->id ?? false;
127
        } catch (\Exception $e) {
128
            return false;
129
        }
130
131
        return true;
0 ignored issues
show
Unused Code introduced by
return true is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
132
    }
133
134 7
    public function pastTimers()
135
    {
136
        try {
137 7
            $pastTimers = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $pastTimers is dead and can be removed.
Loading history...
138
139 7
            $user = json_decode(
140 7
                $this->client->get("user")->getBody()->getContents()
141
            );
142
143 7
            $response = $this->client->get("workspaces/{$user->activeWorkspace}/user/{$user->id}/time-entries", [
144 7
                'start' => Carbon::today(),
145 7
                'end' => Carbon::today()->subDays(30),
146
            ]);
147 7
            $clockifyTimers = json_decode($response->getBody()->getContents());
148
149 7
            return $this->convertToPastTimers($clockifyTimers);
150
        } catch (Exception $e) {
151
            return [];
152
        }
153
    }
154
155 7
    public function continueTimer($timerId = null)
156
    {
157
        /**
158
         * Timer attributes are stored in env variables
159
         * gathered in startTimer.
160
         */
161 7
        return $this->startTimer();
162
    }
163
164 8
    public function deleteTimer($timerId)
165
    {
166 8
        return false;
167
    }
168
169 7
    protected function convertToPastTimers($clockifyTimers)
170
    {
171 7
        $projects = $this->projects();
172 7
        $tags = $this->tags();
173
174
        return array_map(function ($clockifyTimer) use ($projects, $tags) {
175 7
            return $this->buildPastTimerObject($clockifyTimer, $projects, $tags);
176 7
        }, $clockifyTimers);
177
    }
178
179 7
    protected function buildPastTimerObject($clockifyTimer, $projects, $tags)
180
    {
181 7
        $pastTimer['id'] = $clockifyTimer->id;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$pastTimer was never initialized. Although not strictly required by PHP, it is generally a good practice to add $pastTimer = array(); before regardless.
Loading history...
182 7
        $pastTimer['description'] = $clockifyTimer->description;
183
184 7
        if (isset($clockifyTimer->projectId)) {
185 7
            $pastTimer['project_id'] = $clockifyTimer->projectId;
186 7
            $pastTimer['project_name'] = $projects[$clockifyTimer->projectId];
187
        }
188
189 7
        if (isset($clockifyTimer->tagIds[0])) {
190 7
            $pastTimer['tag_id'] = $clockifyTimer->tagIds[0];
191 7
            $pastTimer['tags'] = $tags[$clockifyTimer->tagIds[0]];
192
        }
193
194 7
        $pastTimer['duration'] = $clockifyTimer->timeInterval->duration;
195
196 7
        return (object) $pastTimer;
197
    }
198
}
199