Completed
Push — master ( 4b25ee...fa07c4 )
by William Johnson S.
01:58
created

HttpApi::setUsername()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

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