1 | <?php |
||
2 | |||
3 | namespace Godbout\Alfred\Time\Services; |
||
4 | |||
5 | use Carbon\Carbon; |
||
6 | use Carbon\CarbonInterval; |
||
7 | use Exception; |
||
8 | use MorningTrain\TogglApi\TogglApi; |
||
9 | |||
10 | class Toggl extends TimerService |
||
11 | { |
||
12 | private $client; |
||
13 | |||
14 | private $data = null; |
||
15 | |||
16 | |||
17 | 106 | public function __construct($apiToken) |
|
18 | { |
||
19 | 106 | $this->client = new TogglApi($apiToken); |
|
20 | 106 | } |
|
21 | |||
22 | 26 | public function projects() |
|
23 | { |
||
24 | 26 | return $this->extractFromData('projects'); |
|
25 | } |
||
26 | |||
27 | 20 | public function tags() |
|
28 | { |
||
29 | 20 | return $this->extractFromData('tags'); |
|
30 | } |
||
31 | |||
32 | 2 | public function pastTimers() |
|
33 | { |
||
34 | try { |
||
35 | 2 | $togglTimers = $this->client->getTimeEntriesInRange(Carbon::today(), Carbon::today()->subDays(30)); |
|
36 | |||
37 | 2 | return $this->convertToPastTimers($togglTimers); |
|
38 | } catch (Exception $e) { |
||
39 | return []; |
||
40 | } |
||
41 | } |
||
42 | |||
43 | 14 | public function startTimer() |
|
44 | { |
||
45 | try { |
||
46 | 14 | $timer = $this->client->startTimeEntry([ |
|
47 | 14 | 'description' => getenv('timer_description'), |
|
48 | 14 | 'pid' => getenv('timer_project_id'), |
|
49 | 14 | 'tags' => getenv('timer_tag') ? [getenv('timer_tag')] : '', |
|
50 | 14 | 'created_with' => 'Alfred Time' |
|
51 | ]); |
||
52 | |||
53 | 14 | if (! isset($timer->id)) { |
|
54 | 14 | return false; |
|
55 | } |
||
56 | } catch (Exception $e) { |
||
57 | return false; |
||
58 | } |
||
59 | |||
60 | 14 | return $timer->id; |
|
61 | } |
||
62 | |||
63 | 10 | public function stopCurrentTimer() |
|
64 | { |
||
65 | 10 | if ($timerId = $this->runningTimer()) { |
|
66 | 10 | $response = $this->client->stopTimeEntry($timerId); |
|
67 | |||
68 | 10 | if (! isset($response->id)) { |
|
69 | throw new Exception("Can't stop current running timer.", 1); |
||
70 | } |
||
71 | |||
72 | 10 | return true; |
|
73 | } |
||
74 | |||
75 | return false; |
||
76 | } |
||
77 | |||
78 | 70 | public function runningTimer() |
|
79 | { |
||
80 | 70 | $timer = $this->client->getRunningTimeEntry(); |
|
81 | |||
82 | 70 | return $timer->id ?? false; |
|
83 | } |
||
84 | |||
85 | 2 | public function continueTimer($timerId) |
|
86 | { |
||
87 | /** |
||
88 | * Timer attributes are stored in env variables |
||
89 | * gathered in startTimer. |
||
90 | */ |
||
91 | 2 | return $this->startTimer(); |
|
92 | } |
||
93 | |||
94 | 14 | public function deleteTimer($timerId) |
|
95 | { |
||
96 | try { |
||
97 | 14 | $this->client->deleteTimeEntry($timerId); |
|
98 | } catch (Exception $e) { |
||
99 | return false; |
||
100 | } |
||
101 | |||
102 | 14 | return true; |
|
103 | } |
||
104 | |||
105 | 46 | private function extractFromData($needle) |
|
106 | { |
||
107 | 46 | $data = $this->getData(); |
|
108 | |||
109 | 46 | if (! isset($data->$needle)) { |
|
110 | 36 | return []; |
|
111 | } |
||
112 | |||
113 | 10 | $choosableData = $this->filterOutServerwiseDeletedAndArchivedItemsFromData($data->$needle); |
|
114 | |||
115 | 10 | return array_column($choosableData, 'name', 'id'); |
|
116 | } |
||
117 | |||
118 | 46 | private function getData() |
|
119 | { |
||
120 | 46 | if (is_null($this->data)) { |
|
121 | 46 | return $this->client->getMe(true); |
|
122 | } |
||
123 | |||
124 | return $this->data; |
||
125 | } |
||
126 | |||
127 | 10 | private function filterOutServerwiseDeletedAndArchivedItemsFromData($items = []) |
|
128 | { |
||
129 | 10 | return array_filter($items, function ($item) { |
|
130 | return |
||
131 | 10 | ! $this->itemIsDeletedServerwise($item) |
|
132 | 10 | && ! $this->itemIsArchivedServerwise($item); |
|
133 | 10 | }); |
|
134 | } |
||
135 | |||
136 | 10 | private function itemIsDeletedServerwise($item) |
|
137 | { |
||
138 | 10 | return isset($item->server_deleted_at); |
|
139 | } |
||
140 | |||
141 | 10 | private function itemIsArchivedServerwise($item) |
|
142 | { |
||
143 | return |
||
144 | 10 | isset($item->active) |
|
145 | 10 | && $item->active === false; |
|
146 | } |
||
147 | |||
148 | 2 | protected function convertToPastTimers($togglTimers) |
|
149 | { |
||
150 | 2 | $projects = $this->projects(); |
|
151 | |||
152 | 2 | return array_reverse( |
|
153 | 2 | array_map(function ($togglTimer) use ($projects) { |
|
154 | 2 | return $this->buildPastTimerObject($togglTimer, $projects); |
|
155 | 2 | }, $togglTimers) |
|
156 | ); |
||
157 | } |
||
158 | |||
159 | 2 | protected function buildPastTimerObject($togglTimer, $projects) |
|
160 | { |
||
161 | 2 | $pastTimer['id'] = $togglTimer->id; |
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Loading history...
|
|||
162 | 2 | $pastTimer['description'] = $togglTimer->description ?? ''; |
|
163 | 2 | $pastTimer['duration'] = CarbonInterval::seconds($togglTimer->duration)->cascade()->format('%H:%I:%S'); |
|
164 | |||
165 | 2 | if (isset($togglTimer->pid)) { |
|
166 | 2 | $pastTimer['project_id'] = $togglTimer->pid; |
|
167 | 2 | $pastTimer['project_name'] = $projects[$togglTimer->pid] ?? $togglTimer->pid; |
|
168 | } |
||
169 | |||
170 | 2 | if (isset($togglTimer->tags)) { |
|
171 | 2 | $pastTimer['tags'] = implode(', ', (array) $togglTimer->tags); |
|
172 | } |
||
173 | |||
174 | 2 | return (object) $pastTimer; |
|
175 | } |
||
176 | } |
||
177 |