1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Katapoka\Ahgora; |
4
|
|
|
|
5
|
|
|
use DateTime; |
6
|
|
|
use InvalidArgumentException; |
7
|
|
|
use Katapoka\Ahgora\Contracts\IHttpClient; |
8
|
|
|
use Katapoka\Ahgora\Contracts\IHttpResponse; |
9
|
|
|
use LogicException; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* Class responsible for getting the data from the Ahgora system. |
13
|
|
|
*/ |
14
|
|
|
class HttpApi extends AbstractApi |
15
|
|
|
{ |
16
|
|
|
const AHGORA_BASE_URL = 'https://www.ahgora.com.br'; |
17
|
|
|
const AHGORA_COMPANY_URL = '%s/externo/index/%s'; |
18
|
|
|
const AHGORA_LOGIN_URL = '%s/externo/login'; |
19
|
|
|
const AHGORA_PUNCHS_URL = '%s/externo/batidas/%s-%s'; |
20
|
|
|
|
21
|
|
|
/** @var \Katapoka\Ahgora\Contracts\IHttpClient */ |
22
|
|
|
private $httpClient; |
23
|
|
|
/** @var string */ |
24
|
|
|
private $password; |
25
|
|
|
/** @var string */ |
26
|
|
|
private $companyId; |
27
|
|
|
/** @var string */ |
28
|
|
|
private $username; |
29
|
|
|
/** @var bool */ |
30
|
|
|
private $loggedIn = false; |
31
|
|
|
/** @var HtmlPageParser */ |
32
|
|
|
private $htmlPageParser; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Api constructor. |
36
|
|
|
* |
37
|
|
|
* @param IHttpClient $httpClient |
38
|
|
|
*/ |
39
|
1 |
|
public function __construct(IHttpClient $httpClient) |
40
|
|
|
{ |
41
|
1 |
|
$this->httpClient = $httpClient; |
42
|
1 |
|
$this->htmlPageParser = new HtmlPageParser(); |
43
|
1 |
|
$this->debug('Api instance created'); |
44
|
1 |
|
} |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Set the company id of the ahgora system. |
48
|
|
|
* |
49
|
|
|
* @param string $companyId |
50
|
|
|
* |
51
|
|
|
* @return $this |
52
|
|
|
*/ |
53
|
|
|
public function setCompanyId($companyId) |
54
|
|
|
{ |
55
|
|
|
$this->companyId = $companyId; |
56
|
|
|
$this->debug('Company ID set', ['company_id' => $companyId]); |
57
|
|
|
|
58
|
|
|
return $this; |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* Set the username of the employee, from the company set at the setCompanyId. |
63
|
|
|
* |
64
|
|
|
* @param string $username |
65
|
|
|
* |
66
|
|
|
* @return $this |
67
|
|
|
*/ |
68
|
|
|
public function setUsername($username) |
69
|
|
|
{ |
70
|
|
|
$this->username = $username; |
71
|
|
|
$this->debug('Username set', ['username' => $username]); |
72
|
|
|
|
73
|
|
|
return $this; |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Set the password of the employee, from the company set at the setCompanyId. |
78
|
|
|
* |
79
|
|
|
* @param string $password |
80
|
|
|
* |
81
|
|
|
* @return $this |
82
|
|
|
*/ |
83
|
|
|
public function setPassword($password) |
84
|
|
|
{ |
85
|
|
|
$this->password = $password; |
86
|
|
|
$this->debug('Password set', ['password' => $password]); |
87
|
|
|
|
88
|
|
|
return $this; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Try to execute the login on the page. |
93
|
|
|
* To execute some actions the user needs to be loggedin. |
94
|
|
|
* After a successful login, the status loggedin is saved as true. |
95
|
|
|
* |
96
|
|
|
* @return bool Returns true if the login was successful and false otherwise |
97
|
|
|
*/ |
98
|
|
|
public function doLogin() |
99
|
|
|
{ |
100
|
|
|
$hasLoggedIn = false; |
101
|
|
|
$this->debug('Started login proccess'); |
102
|
|
|
|
103
|
|
|
$accessEnabled = $this->checkAccessEnabled(); |
104
|
|
|
|
105
|
|
|
if ($accessEnabled) { |
106
|
|
|
$response = $this->executeLogin(); |
107
|
|
|
$hasLoggedIn = $this->checkLoginStatus($response); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
$this->debug($accessEnabled ? "Company has external access enabled" : "Company hasn't external access enabled"); |
111
|
|
|
|
112
|
|
|
$this->setLoggedIn($hasLoggedIn); |
113
|
|
|
|
114
|
|
|
return $hasLoggedIn; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Get the punches at the given parameters. |
119
|
|
|
* |
120
|
|
|
* @param int|null $month The month you want to get the punches - Must be between 01 and 12 (both included) |
121
|
|
|
* @param int|null $year The year you want to get the punches |
122
|
|
|
* |
123
|
|
|
* @return array |
124
|
|
|
*/ |
125
|
|
|
public function getPunches($month = null, $year = null) |
126
|
|
|
{ |
127
|
|
|
if (!$this->loggedIn) { |
128
|
|
|
throw new LogicException('To get punches you need to be loggedIn'); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
$month = IntHelper::parseNullableInt($month); |
132
|
|
|
$year = IntHelper::parseNullableInt($year); |
133
|
|
|
|
134
|
|
|
$month = $month ?: (int)date('m') + (intval(date('d')) >= 20 ? 1 : 0); |
135
|
|
|
$year = $year ?: (int)date('Y'); |
136
|
|
|
|
137
|
|
|
return $this->getPunchesFromPage($this->getPunchesPage($month, $year)); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* Get the punches from some given day. |
142
|
|
|
* |
143
|
|
|
* @param int $day |
144
|
|
|
* @param int $month |
145
|
|
|
* @param int $year |
146
|
|
|
* |
147
|
|
|
* @return mixed |
148
|
|
|
*/ |
149
|
|
View Code Duplication |
public function getPunchesFromDay($day, $month, $year) |
|
|
|
|
150
|
|
|
{ |
151
|
|
|
$date = date("Y-m-d", mktime(0, 0, 0, $month, $day, $year)); |
152
|
|
|
list($year, $month, $day) = explode('-', $date); |
153
|
|
|
|
154
|
|
|
if ($day > 19) { |
155
|
|
|
$month++; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
if ($month > 12) { |
159
|
|
|
$month = 1; |
160
|
|
|
$year++; |
161
|
|
|
} |
162
|
|
|
$punches = $this->getPunches($month, $year); |
163
|
|
|
|
164
|
|
|
return array_filter($punches['punches'], function (\DateTime $punchDateTime) use ($day) { |
165
|
|
|
return (int) $punchDateTime->format('d') === (int) $day; |
166
|
|
|
}); |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* Gets the employee name. |
171
|
|
|
* |
172
|
|
|
* @return string |
173
|
|
|
*/ |
174
|
|
|
public function getEmployeeName() |
175
|
|
|
{ |
176
|
|
|
return "NOT IMPLEMENTED YET"; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* Gets the employer name. |
181
|
|
|
* |
182
|
|
|
* @return string |
183
|
|
|
*/ |
184
|
|
|
public function getEmployeeRole() |
185
|
|
|
{ |
186
|
|
|
return "NOT IMPLEMENTED YET"; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* Get the employer department. |
191
|
|
|
* |
192
|
|
|
* @return string |
193
|
|
|
*/ |
194
|
|
|
public function getDepartment() |
195
|
|
|
{ |
196
|
|
|
return "NOT IMPLEMENTED YET"; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* Retrive all the punches for the given string. |
201
|
|
|
* |
202
|
|
|
* @param string $punchesStr |
203
|
|
|
* |
204
|
|
|
* @return array |
205
|
|
|
*/ |
206
|
|
|
private function parsePunches($punchesStr) |
207
|
|
|
{ |
208
|
|
|
$punches = []; |
209
|
|
|
if (!!preg_match_all('/(\d{2}:\d{2})/is', $punchesStr, $matches)) { |
210
|
|
|
$punches = $matches[0]; |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
return $punches; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* Execute the login on the server and returns the server response. |
218
|
|
|
* |
219
|
|
|
* @return IHttpResponse |
220
|
|
|
*/ |
221
|
|
|
private function executeLogin() |
222
|
|
|
{ |
223
|
|
|
return $this->httpClient->post($this->loginUrl(), [ |
224
|
|
|
'empresa' => $this->companyId, |
225
|
|
|
'matricula' => $this->username, |
226
|
|
|
'senha' => $this->password, |
227
|
|
|
]); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* Check if the company has external access on the Ahgora system. |
232
|
|
|
* |
233
|
|
|
* @return bool |
234
|
|
|
*/ |
235
|
|
|
private function checkAccessEnabled() |
236
|
|
|
{ |
237
|
|
|
$response = $this->httpClient->get($this->companyUrl()); |
238
|
|
|
|
239
|
|
|
return stripos($response->getBody(), 'Sua Empresa não liberou o acesso a essa ferramenta') === false; |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
/** |
243
|
|
|
* Check the return of the login action. |
244
|
|
|
* How it works: If statusCode 200 and no body, login ok, otherwise, login failed. |
245
|
|
|
* Should return a json with property "r" with "error" and "text" with the message |
246
|
|
|
* |
247
|
|
|
* @param IHttpResponse $response |
248
|
|
|
* |
249
|
|
|
* @return bool |
250
|
|
|
*/ |
251
|
|
|
private function checkLoginStatus(IHttpResponse $response) |
252
|
|
|
{ |
253
|
|
|
try { |
254
|
|
|
return $response->getHttpStatus() === IHttpClient::HTTP_STATUS_OK && $this->getResponseLoginStatus($response); |
255
|
|
|
} catch (InvalidArgumentException $iaex) { |
256
|
|
|
$this->error('checkLoginStatus', ['expcetion' => $iaex]); |
257
|
|
|
|
258
|
|
|
return false; |
259
|
|
|
} |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* Check if the response can be decoded as json, has the property r and r is 'success'. |
264
|
|
|
* |
265
|
|
|
* @param IHttpResponse $response |
266
|
|
|
* |
267
|
|
|
* @return bool |
268
|
|
|
*/ |
269
|
|
|
private function getResponseLoginStatus(IHttpResponse $response) |
270
|
|
|
{ |
271
|
|
|
try { |
272
|
|
|
$json = $response->json(); |
273
|
|
|
|
274
|
|
|
return array_key_exists('r', $json) && $json->r === 'success'; |
275
|
|
|
} catch (InvalidArgumentException $iaex) { |
276
|
|
|
$this->debug('getResponseLoginStatus', ['exception', $iaex]); |
277
|
|
|
|
278
|
|
|
return false; |
279
|
|
|
} |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
/** |
283
|
|
|
* Safely set if the user is loggedin or not. |
284
|
|
|
* Did a separate method do eventually trigger events, if necessary. |
285
|
|
|
* |
286
|
|
|
* @param bool $loggedIn |
287
|
|
|
* |
288
|
|
|
* @return $this |
289
|
|
|
*/ |
290
|
|
|
private function setLoggedIn($loggedIn = true) |
291
|
|
|
{ |
292
|
|
|
if (!is_bool($loggedIn)) { |
293
|
|
|
throw new InvalidArgumentException('LoggedIn parameter must be boolean'); |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
$this->debug('setLoggedIn', ['logged_in' => $loggedIn]); |
297
|
|
|
$this->loggedIn = $loggedIn; |
298
|
|
|
|
299
|
|
|
return $this; |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
/** |
303
|
|
|
* Build the company url string. |
304
|
|
|
* |
305
|
|
|
* @return string |
306
|
|
|
*/ |
307
|
|
|
private function companyUrl() |
308
|
|
|
{ |
309
|
|
|
$companyUrl = sprintf(self::AHGORA_COMPANY_URL, self::AHGORA_BASE_URL, $this->companyId); |
310
|
|
|
$this->debug('CompanyURL', ['company_url' => $companyUrl]); |
311
|
|
|
|
312
|
|
|
return $companyUrl; |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
/** |
316
|
|
|
* Build the login url. |
317
|
|
|
* |
318
|
|
|
* @return string |
319
|
|
|
*/ |
320
|
|
|
private function loginUrl() |
321
|
|
|
{ |
322
|
|
|
$loginUrl = sprintf(self::AHGORA_LOGIN_URL, self::AHGORA_BASE_URL); |
323
|
|
|
$this->debug('loginUrl', ['login_url' => $loginUrl]); |
324
|
|
|
|
325
|
|
|
return $loginUrl; |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
/** |
329
|
|
|
* Get the built punchesUrl with the given month and year. |
330
|
|
|
* |
331
|
|
|
* @param int $month |
332
|
|
|
* @param int $year |
333
|
|
|
* |
334
|
|
|
* @return string |
335
|
|
|
*/ |
336
|
|
|
private function punchesUrl($month, $year) |
337
|
|
|
{ |
338
|
|
|
$month = str_pad(strval($month), 2, '0', STR_PAD_LEFT); |
339
|
|
|
$punchesUrl = sprintf(self::AHGORA_PUNCHS_URL, self::AHGORA_BASE_URL, $month, $year); |
340
|
|
|
$this->debug('punchesUrl', [ |
341
|
|
|
'punches_url' => $punchesUrl, |
342
|
|
|
'month' => $month, |
343
|
|
|
'year' => $year |
344
|
|
|
]); |
345
|
|
|
|
346
|
|
|
return $punchesUrl; |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
/** |
350
|
|
|
* Make the request to the punches page of the requested time period. |
351
|
|
|
* |
352
|
|
|
* @param int $month |
353
|
|
|
* @param int $year |
354
|
|
|
* |
355
|
|
|
* @return IHttpResponse |
356
|
|
|
*/ |
357
|
|
|
private function getPunchesPage($month, $year) |
358
|
|
|
{ |
359
|
|
|
return $this->httpClient->get($this->punchesUrl($month, $year)); |
360
|
|
|
} |
361
|
|
|
|
362
|
|
|
/** |
363
|
|
|
* Get the punches from the given response of the punches page. |
364
|
|
|
* |
365
|
|
|
* @param IHttpResponse $punchesPageResponse |
366
|
|
|
* |
367
|
|
|
* @return array |
368
|
|
|
*/ |
369
|
|
|
private function getPunchesFromPage(IHttpResponse $punchesPageResponse) |
370
|
|
|
{ |
371
|
|
|
if ($punchesPageResponse->getHttpStatus() !== IHttpClient::HTTP_STATUS_OK) { |
372
|
|
|
throw new InvalidArgumentException('The request returned http status ' . $punchesPageResponse->getHttpStatus()); |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
$punches = $this->parsePunchesPage($punchesPageResponse); |
376
|
|
|
|
377
|
|
|
return [ |
378
|
|
|
'punches' => $punches, |
379
|
|
|
]; |
380
|
|
|
} |
381
|
|
|
|
382
|
|
|
private function parsePunchesPage(IHttpResponse $punchesPageResponse) |
383
|
|
|
{ |
384
|
|
|
$rows = $this->htmlPageParser->getPunchesRows($punchesPageResponse); |
385
|
|
|
$punchCollection = []; |
386
|
|
|
|
387
|
|
|
foreach ($rows as $row) { |
388
|
|
|
$punches = $this->parsePunches($row['punches']); |
389
|
|
|
$punchCollection = array_merge($punchCollection, $this->createPunchesDate($row['date'], $punches)); |
390
|
|
|
} |
391
|
|
|
|
392
|
|
|
return $punchCollection; |
393
|
|
|
} |
394
|
|
|
|
395
|
|
|
/** |
396
|
|
|
* Convert the date string and the datepunch array to an array of DateTime's. |
397
|
|
|
* |
398
|
|
|
* @param string $date |
399
|
|
|
* @param array $punches |
400
|
|
|
* |
401
|
|
|
* @return \DateTime[] |
402
|
|
|
*/ |
403
|
|
|
private function createPunchesDate($date, array $punches = []) |
404
|
|
|
{ |
405
|
|
|
$dates = []; |
406
|
|
|
foreach ($punches as $punch) { |
407
|
|
|
$dates[] = DateTime::createFromFormat($this->datetimeFormat, sprintf('%s %s', $date, $punch)); |
408
|
|
|
} |
409
|
|
|
|
410
|
|
|
return $dates; |
411
|
|
|
} |
412
|
|
|
} |
413
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.