Completed
Push — master ( 329ed0...ea7895 )
by William Johnson S.
03:12
created

HttpApi::setCompanyId()   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/%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
        /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
66% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

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