Completed
Push — master ( fa07c4...971973 )
by William Johnson S.
02:14
created

HttpApi::getDepartment()   A

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 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
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/%d-%d';
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
        if (!$this->isValidPeriod($month, $year)) {
135
            throw new InvalidArgumentException(sprintf('Invalid period of time: [%s-%s]', $month, $year));
136
        }
137
138
        return $this->getPunchesFromPage($this->getPunchesPage($month, $year));
139
    }
140
141
    /**
142
     * Gets the employer name.
143
     *
144
     * @return string
145
     */
146
    public function getEmployeeRole()
147
    {
148
        return "NOT IMPLEMENTED YET";
149
    }
150
151
    /**
152
     * Get the employer department.
153
     *
154
     * @return string
155
     */
156
    public function getDepartment()
157
    {
158
        return "NOT IMPLEMENTED YET";
159
    }
160
161
    /**
162
     * Retrive all the punches for the given string.
163
     *
164
     * @param string $punchesStr
165
     *
166
     * @return array
167
     */
168
    private function parsePunches($punchesStr)
169
    {
170
        $punches = [];
171
        if (!!preg_match_all('/(\d{2}:\d{2})/is', $punchesStr, $matches)) {
172
            $punches = $matches[0];
173
        }
174
175
        return $punches;
176
    }
177
178
    /**
179
     * Execute the login on the server and returns the server response.
180
     *
181
     * @return IHttpResponse
182
     */
183
    private function executeLogin()
184
    {
185
        return $this->httpClient->post($this->loginUrl(), [
186
            'empresa'   => $this->companyId,
187
            'matricula' => $this->username,
188
            'senha'     => $this->password,
189
        ]);
190
    }
191
192
    /**
193
     * Check if the company has external access on the Ahgora system.
194
     *
195
     * @return bool
196
     */
197
    private function checkAccessEnabled()
198
    {
199
        $response = $this->httpClient->get($this->companyUrl());
200
201
        return stripos($response->getBody(), 'Sua Empresa não liberou o acesso a essa ferramenta') === false;
202
    }
203
204
    /**
205
     * Check the return of the login action.
206
     * How it works: If statusCode 200 and no body, login ok, otherwise, login failed.
207
     * Should return a json with property "r" with "error" and "text" with the message
208
     *
209
     * @param IHttpResponse $response
210
     *
211
     * @return bool
212
     */
213
    private function checkLoginStatus(IHttpResponse $response)
214
    {
215
        try {
216
            return $response->getHttpStatus() === IHttpClient::HTTP_STATUS_OK && $this->getResponseLoginStatus($response);
217
        } catch (InvalidArgumentException $iaex) {
218
            $this->error('checkLoginStatus', ['expcetion' => $iaex]);
219
220
            return false;
221
        }
222
    }
223
224
    /**
225
     * Check if the response can be decoded as json, has the property r and r is 'success'.
226
     *
227
     * @param IHttpResponse $response
228
     *
229
     * @return bool
230
     */
231
    private function getResponseLoginStatus(IHttpResponse $response)
232
    {
233
        try {
234
            $json = $response->json();
235
236
            return array_key_exists('r', $json) && $json->r === 'success';
237
        } catch (InvalidArgumentException $iaex) {
238
            $this->debug('getResponseLoginStatus', ['exception', $iaex]);
239
240
            return false;
241
        }
242
    }
243
244
    /**
245
     * Safely set if the user is loggedin or not.
246
     * Did a separate method do eventually trigger events, if necessary.
247
     *
248
     * @param bool $loggedIn
249
     *
250
     * @return $this
251
     */
252
    private function setLoggedIn($loggedIn = true)
253
    {
254
        if (!is_bool($loggedIn)) {
255
            throw new InvalidArgumentException('LoggedIn parameter must be boolean');
256
        }
257
258
        $this->debug('setLoggedIn', ['logged_in' => $loggedIn]);
259
        $this->loggedIn = $loggedIn;
260
261
        return $this;
262
    }
263
264
    /**
265
     * Build the company url string.
266
     *
267
     * @return string
268
     */
269
    private function companyUrl()
270
    {
271
        $companyUrl = sprintf(self::AHGORA_COMPANY_URL, self::AHGORA_BASE_URL, $this->companyId);
272
        $this->debug('CompanyURL', ['company_url' => $companyUrl]);
273
274
        return $companyUrl;
275
    }
276
277
    /**
278
     * Build the login url.
279
     *
280
     * @return string
281
     */
282
    private function loginUrl()
283
    {
284
        $loginUrl = sprintf(self::AHGORA_LOGIN_URL, self::AHGORA_BASE_URL);
285
        $this->debug('loginUrl', ['login_url' => $loginUrl]);
286
287
        return $loginUrl;
288
    }
289
290
    /**
291
     * Get the built punchesUrl with the given month and year.
292
     *
293
     * @param int $month
294
     * @param int $year
295
     *
296
     * @return string
297
     */
298
    private function punchesUrl($month, $year)
299
    {
300
        $month = str_pad($month, 2, '0', STR_PAD_LEFT);
301
        $punchesUrl = sprintf(self::AHGORA_PUNCHS_URL, self::AHGORA_BASE_URL, $month, $year);
302
        $this->debug('punchesUrl', ['punches_url' => $punchesUrl]);
303
304
        return $punchesUrl;
305
    }
306
307
    /**
308
     * Make the request to the punches page of the requested time period.
309
     *
310
     * @param int $month
311
     * @param int $year
312
     *
313
     * @return IHttpResponse
314
     */
315
    private function getPunchesPage($month, $year)
316
    {
317
        return $this->httpClient->get($this->punchesUrl($month, $year));
318
    }
319
320
    /**
321
     * Get the punches from the given response of the punches page.
322
     *
323
     * @param IHttpResponse $punchesPageResponse
324
     *
325
     * @return array
326
     */
327
    private function getPunchesFromPage(IHttpResponse $punchesPageResponse)
328
    {
329
        if ($punchesPageResponse->getHttpStatus() !== IHttpClient::HTTP_STATUS_OK) {
330
            throw new InvalidArgumentException('The request returned http status ' . $punchesPageResponse->getHttpStatus());
331
        }
332
333
        $punches = $this->parsePunchesPage($punchesPageResponse);
334
335
        return [
336
            'punches' => $punches,
337
        ];
338
    }
339
340
    private function parsePunchesPage(IHttpResponse $punchesPageResponse)
341
    {
342
        $rows = $this->htmlPageParser->getPunchesRows($punchesPageResponse);
343
        $punchCollection = [];
344
345
        foreach ($rows as $row) {
346
            $punches = $this->parsePunches($row['punches']);
347
            $punchCollection = array_merge($punchCollection, $this->createPunchesDate($row['date'], $punches));
348
        }
349
350
        return $punchCollection;
351
    }
352
353
    /**
354
     * Convert the date string and the datepunch array to an array of DateTime's.
355
     *
356
     * @param string $date
357
     * @param array  $punches
358
     *
359
     * @return \DateTime[]
360
     */
361
    private function createPunchesDate($date, array $punches = [])
362
    {
363
        $dates = [];
364
        foreach ($punches as $punch) {
365
            $dates[] = DateTime::createFromFormat($this->datetimeFormat, sprintf('%s %s', $date, $punch));
366
        }
367
368
        return $dates;
369
    }
370
}
371