HttpApi::getEmployeeName()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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