Completed
Push — master ( a834a2...4b25ee )
by William Johnson S.
02:11
created

HttpApi::parsePunchsPage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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