From 604e5304c1c3bbd770026291a2062936722b1987 Mon Sep 17 00:00:00 2001 From: Schneider Roland Date: Tue, 2 Aug 2022 18:39:08 +0200 Subject: [PATCH] Add validateOnly --- common/manager/DoorManager.php | 154 ++++++++++++------ ...certbot-dryrun.sh => 10-certbot-dryrun.sh} | 0 .../{certbot-renew.sh => 20-certbot-renew.sh} | 0 .../cutlergyor/proxy/30-nginx-reload.sh | 1 + .../{certbot-run.sh => 40-certbot-run.sh} | 0 http-client.env.json | 4 + rest.http | 13 ++ rest/controllers/DoorController.php | 2 +- rest/models/DoorMoveForm.php | 3 +- test/src/rest/move.test.js | 94 +++++++---- 10 files changed, 183 insertions(+), 88 deletions(-) rename environments/cutlergyor/proxy/{certbot-dryrun.sh => 10-certbot-dryrun.sh} (100%) rename environments/cutlergyor/proxy/{certbot-renew.sh => 20-certbot-renew.sh} (100%) create mode 100644 environments/cutlergyor/proxy/30-nginx-reload.sh rename environments/cutlergyor/proxy/{certbot-run.sh => 40-certbot-run.sh} (100%) diff --git a/common/manager/DoorManager.php b/common/manager/DoorManager.php index 127f308..6e256f2 100644 --- a/common/manager/DoorManager.php +++ b/common/manager/DoorManager.php @@ -6,8 +6,10 @@ use common\components\DateUtil; use common\components\Helper; use common\components\StopWatch; use common\models\Card; +use common\models\CardKeyAssignment; use common\models\DoorLog; use common\models\DoorLogForTest; +use common\models\Key; use common\models\Log; use common\models\Ticket; use frontend\models\KeyToggleForm; @@ -26,8 +28,7 @@ class DoorManager extends BaseObject /** - - * @param $cardNumber 00000000: nyomogombos nyitás + * @param $cardNumber 00000000: nyomogombos nyitás * @param $device string B(gomb)|Q(qrcode)|C(nfc),E(emergency) * @param $direction string IN|OUT * @param $verifyOnly boolean true: akkor csak lekerdezés, false: megtörtént a mozgás (ilyenkor vonunk le egy alkalmat) @@ -63,6 +64,21 @@ class DoorManager extends BaseObject $dateStr = DateUtil::formatDateUtc($date); $doorLog = new DoorLog(); + if ( $device == 'E'){ + $direction = DoorLog::$DIRECTION_ALL_EMERGENCY; + }else{ + switch ($direction) { + case 'IN': + $direction = DoorLog::$DIRECTION_IN ; + break; + case 'OUT': + $direction = DoorLog::$DIRECTION_OUT; + break; + default: + throw new BadRequestHttpException("Direction not supported: ".$direction); + } + + } $doorLog->direction = $direction; $doorLog->source_app = $device; $doorLog->created_at = $createdAtStr; @@ -70,31 +86,53 @@ class DoorManager extends BaseObject /** * emergency- no card needed */ - if ($direction == DoorLog::$DIRECTION_ALL_EMERGENCY) { - $doorLog->save(false); - Log::log( - [ - 'type' => Log::$TYPE_INFO, - 'message' => 'Ajtó nyitás: vészhelyzet', - 'id_door_log' => $doorLog->id_door_log - ] - ); - \Yii::$app->response->statusCode = 204; - \Yii::error("emergency event in sec " . $stopWatch->split()); + if ($device == 'E' ) { + if (!$verifyOnly) { + $doorLog->save(false); + Log::log( + [ + 'type' => Log::$TYPE_INFO, + 'message' => 'Ajtó nyitás: vészhelyzet', + 'id_door_log' => $doorLog->id_door_log + ] + ); + \Yii::$app->response->statusCode = 204; + \Yii::error("emergency event in sec " . $stopWatch->split()); + } \Yii::$app->db->transaction->commit(); return; } - $card = Card::readCard(Helper::fixAsciiChars($cardNumber)); - \Yii::error("card loaded in sec " . $stopWatch->split()); - /* * in any other cases, the door needs a card */ - if (!isset($card)) { - throw new BadRequestHttpException('Card not found with number: ' . $cardNumber); + + + // if device is qr code + if ( $device == 'Q'){ + + // allow only virtual key + $keyAssignment = CardKeyAssignment::findOne(['virtual_key' => $cardNumber]); + if (!isset($keyAssignment)){ + throw new BadRequestHttpException("Virtual key not found: ". $cardNumber); + } + $card = Card::findOne($keyAssignment->id_card); + if ( $card != null ){ + $card = Card::readCard($card->number); + } + if ( $card == null ){ + throw new BadRequestHttpException("Card not found by virtual key: ". $cardNumber.'/'.$keyAssignment->id_card); + } + \Yii::error("virtual key loaded in sec " . $stopWatch->split()); + } else{ + $card = Card::readCard(Helper::fixAsciiChars($cardNumber)); + \Yii::error("Card loaded in sec " . $stopWatch->split()); + if (!isset($card)) { + throw new BadRequestHttpException('Card not found with number: ' . $cardNumber); + } } + $doorLog->id_card = $card->id_card; $doorLog->card_flag = $card->flag; /** @@ -102,9 +140,11 @@ class DoorManager extends BaseObject * Free to enter/leave */ if ($card->type == Card::TYPE_EMPLOYEE) { - $doorLog->save(false); - \Yii::$app->response->statusCode = 204; - \Yii::error("employee card {$card->id_card} event finished in sec " . $stopWatch->split()); + if (!$verifyOnly) { + $doorLog->save(false); + \Yii::$app->response->statusCode = 204; + \Yii::error("employee card {$card->id_card} event finished in sec " . $stopWatch->split()); + } \Yii::$app->db->transaction->commit(); return; } @@ -134,8 +174,10 @@ class DoorManager extends BaseObject $doorLog->id_customer = $customer->id_customer; \Yii::error("customer {$customer->id_customer} loaded in sec " . $stopWatch->split()); - // save the door log - $doorLog->save(false); + if (!$verifyOnly) { + // save the door log + $doorLog->save(false); + } \Yii::error("door log {$doorLog->id_door_log} saved in sec " . $stopWatch->split()); // if direction is in @@ -154,6 +196,10 @@ class DoorManager extends BaseObject } $countDoorLogsForTicketSince = $this->getCountDoorLogsForTicketSince($ticket->id_ticket, DateUtil::utcDate(clone $date)); + if (!$verifyOnly) { + // if verifyOnly, the actual doorLog is not saved, so we hate to increase the count artificially + $countDoorLogsForTicketSince = $countDoorLogsForTicketSince + 1; + } \Yii::error("count of door logs '{$countDoorLogsForTicketSince}' loaded in sec " . $stopWatch->split()); // if the current event is the first door log today @@ -161,15 +207,17 @@ class DoorManager extends BaseObject // increase the ticket usage count with 1 $usageCount = $ticket->usage_count; $ticket->usage_count += 1; - $ticket->save(false); - Log::log( - [ - 'type' => Log::$TYPE_TICKET_USAGE_FIRST, - 'message' => 'Bérlet használat(előtte: ' . $usageCount . ' -> utána: ' . $ticket->usage_count, - 'id_ticket' => $ticket->id_ticket, - 'id_door_log' => $doorLog->id_door_log - ] - ); + if (!$verifyOnly) { + $ticket->save(false); + Log::log( + [ + 'type' => Log::$TYPE_TICKET_USAGE_FIRST, + 'message' => 'Bérlet használat(előtte: ' . $usageCount . ' -> utána: ' . $ticket->usage_count, + 'id_ticket' => $ticket->id_ticket, + 'id_door_log' => $doorLog->id_door_log + ] + ); + } \Yii::error("Ticket usage count increased after first doorlog of day in sec " . $stopWatch->split()); } else { @@ -223,7 +271,9 @@ class DoorManager extends BaseObject if ($logCountInActiveInterval == 1) { $ticket->usage_count = $ticket->usage_count + 1; - $ticket->save(false); + if (!$verifyOnly) { + $ticket->save(false); + } \Yii::error("Ticket usage count increased after first IN after first door_log in interval in sec " . $stopWatch->split()); } @@ -243,27 +293,31 @@ class DoorManager extends BaseObject } $ticket->count_move_out = $ticket->usage_count; - $ticket->save(false); + if (!$verifyOnly) { + $ticket->save(false); + } \Yii::error("direction_out: ticket count_move_out set after direction_out in sec " . $stopWatch->split()); } - Card::updateCardFlagTicket($ticket->id_ticket); - \Yii::error("updateCardFlagTicket: card flag updated in sec " . $stopWatch->split()); + if (!$verifyOnly) { + Card::updateCardFlagTicket($ticket->id_ticket); + \Yii::error("updateCardFlagTicket: card flag updated in sec " . $stopWatch->split()); - // reload card after flag is set - $card = Card::readCard($cardNumber); - if ($card->type != Card::TYPE_EMPLOYEE) { - if ($direction == DoorLog::$DIRECTION_OUT_WITHOUT_MOVE || $direction == DoorLog::$DIRECTION_OUT) { - $card->flag_out = Helper::setBit($card->flag_out, Card::$FLAG_DOOR, true); - $card->flag = Helper::setBit($card->flag, Card::$FLAG_DOOR, false); - $card->save(false); - \Yii::error("direction_out: Door flag updated in sec " . $stopWatch->split()); + // reload card after flag is set + $card = Card::readCard($cardNumber); + if ($card->type != Card::TYPE_EMPLOYEE) { + if ($direction == DoorLog::$DIRECTION_OUT_WITHOUT_MOVE || $direction == DoorLog::$DIRECTION_OUT) { + $card->flag_out = Helper::setBit($card->flag_out, Card::$FLAG_DOOR, true); + $card->flag = Helper::setBit($card->flag, Card::$FLAG_DOOR, false); + $card->save(false); + \Yii::error("direction_out: Door flag updated in sec " . $stopWatch->split()); - } else if ($direction == DoorLog::$DIRECTION_IN || $direction == DoorLog::$DIRECTION_IN_WITHOUT_MOVE) { - $card->flag_out = Helper::setBit($card->flag_out, Card::$FLAG_DOOR, false); - $card->flag = Helper::setBit($card->flag, Card::$FLAG_DOOR, true); - $card->save(false); - \Yii::error("direction_in: Card flag updated in sec " . $stopWatch->split()); + } else if ($direction == DoorLog::$DIRECTION_IN || $direction == DoorLog::$DIRECTION_IN_WITHOUT_MOVE) { + $card->flag_out = Helper::setBit($card->flag_out, Card::$FLAG_DOOR, false); + $card->flag = Helper::setBit($card->flag, Card::$FLAG_DOOR, true); + $card->save(false); + \Yii::error("direction_in: Card flag updated in sec " . $stopWatch->split()); + } } } @@ -329,7 +383,7 @@ class DoorManager extends BaseObject ['id_card' => $card->id_card] ); // todo: revoke all assigned key - $this->revokeKey($cardNumber,"f100"); + $this->revokeKey($cardNumber, "f100"); } public function getLogs($cardNumber) diff --git a/environments/cutlergyor/proxy/certbot-dryrun.sh b/environments/cutlergyor/proxy/10-certbot-dryrun.sh similarity index 100% rename from environments/cutlergyor/proxy/certbot-dryrun.sh rename to environments/cutlergyor/proxy/10-certbot-dryrun.sh diff --git a/environments/cutlergyor/proxy/certbot-renew.sh b/environments/cutlergyor/proxy/20-certbot-renew.sh similarity index 100% rename from environments/cutlergyor/proxy/certbot-renew.sh rename to environments/cutlergyor/proxy/20-certbot-renew.sh diff --git a/environments/cutlergyor/proxy/30-nginx-reload.sh b/environments/cutlergyor/proxy/30-nginx-reload.sh new file mode 100644 index 0000000..271e364 --- /dev/null +++ b/environments/cutlergyor/proxy/30-nginx-reload.sh @@ -0,0 +1 @@ +docker-compose exec webserver nginx -s reload diff --git a/environments/cutlergyor/proxy/certbot-run.sh b/environments/cutlergyor/proxy/40-certbot-run.sh similarity index 100% rename from environments/cutlergyor/proxy/certbot-run.sh rename to environments/cutlergyor/proxy/40-certbot-run.sh diff --git a/http-client.env.json b/http-client.env.json index 48ff237..3fedd0f 100644 --- a/http-client.env.json +++ b/http-client.env.json @@ -2,5 +2,9 @@ "lgyenese": { "restapi-url": "https://cutlergyor.rschneider.hu/cutler/rest/web/index.php?r=", "token": "123" + }, + "dev": { + "restapi-url": "http://localhost:86/fitness_web/rest/web/index.php?r=", + "token": "123" } } diff --git a/rest.http b/rest.http index dca0ac4..304df25 100644 --- a/rest.http +++ b/rest.http @@ -19,3 +19,16 @@ Authorization: Basic bGd5ZW5lc2U6ZGlnaXNvZnQ=' "direction": "IN", "device": "Q" } + +### + +GET {{restapi-url}}door/info?cardNumber=10WMVXMZ +Accept: application/json +Content-Type: application/json +Authorization: Basic ZG9vcl9zeXN0ZW06ZG9vcnN5c3RlbTE= + +{ + "cardNumber": "10WMVXMZ", + "direction": "IN", + "device": "Q" +} diff --git a/rest/controllers/DoorController.php b/rest/controllers/DoorController.php index 29907bd..dc4b82c 100644 --- a/rest/controllers/DoorController.php +++ b/rest/controllers/DoorController.php @@ -19,7 +19,7 @@ class DoorController extends RestController throw new BadRequestHttpException("Invalid move request:". $formModel->getFirstErrors()[$keys[0]]); } $doorManager = new DoorManager(); - $doorManager->move($formModel->cardNumber,$formModel->device,$formModel->direction, $formModel->createdAt, $formModel->date); + $doorManager->move($formModel->cardNumber,$formModel->device,$formModel->direction, $formModel->validateOnly, $formModel->createdAt, $formModel->date); } return $formModel; } diff --git a/rest/models/DoorMoveForm.php b/rest/models/DoorMoveForm.php index a8f7d32..ed2bd9a 100644 --- a/rest/models/DoorMoveForm.php +++ b/rest/models/DoorMoveForm.php @@ -13,10 +13,11 @@ class DoorMoveForm extends Model public $test; public $createdAt; public $date; + public $validateOnly; public function rules( ) { return [ - [ ['cardNumber', 'device', 'direction' ], 'required'], + [ ['cardNumber', 'device', 'direction', 'validateOnly' ], 'required'], [ ['createdAt', 'date' ], 'string'] ]; } diff --git a/test/src/rest/move.test.js b/test/src/rest/move.test.js index 002c1da..0bab6d0 100644 --- a/test/src/rest/move.test.js +++ b/test/src/rest/move.test.js @@ -66,8 +66,10 @@ class Client { ...headers }, data: { - direction: 3, - device: 'QRCODE', + verifyOnly: false, + direction: 'IN', + device: 'Q', + validateOnly: false, cardNumber: '10WMVXMZ', ...data } @@ -108,7 +110,7 @@ test('Emergency open', async () => { const client = new Client(); await client.reset(TEST_CARD_NUMBER) let before = await client.getInfo(TEST_CARD_NUMBER); - let response = await client.move({direction: 128}) + let response = await client.move({direction: 'IN', device: 'E'}) expect(response.status).toBe(204); let after = await client.getInfo(TEST_CARD_NUMBER); expect(after.data.doorLogs.length).toBe(0); @@ -123,7 +125,7 @@ test('Emergency open', async () => { test('Error if card not exists', async () => { const client = new Client(); try { - await client.move({cardNumber: 'notexists', direction: 3}); + await client.move({cardNumber: 'notexists', direction: 'IN'}); } catch (e) { expect(e?.response?.status).toBe(400); @@ -135,26 +137,26 @@ test('Allow card type employee', async () => { const client = new Client(); let createdAt = new Date(); createdAt.setHours(18); - const info = await client.moveWithInfo({cardNumber: 'employee', direction: 3, createdAt: formatDateTime(createdAt)}); + const info = await client.moveWithInfo({cardNumber: 'employee', direction: 'IN', device: 'C', createdAt: formatDateTime(createdAt)}); const lastLog = info.after.data.lastDoorLog; expect(lastLog.id_card).not.toBeNull(); - expect(lastLog.direction).toBe(3); + expect(lastLog.direction).toBe(7); },10000) test('Normal Ticket: usage count will be increased on entry', async () => { const client = new Client(); await client.reset(TEST_CARD_NUMBER); - const info = await client.moveWithInfo({cardNumber: TEST_CARD_NUMBER, direction: 3}); + const info = await client.moveWithInfo({cardNumber: TEST_CARD_NUMBER, device: 'C', direction: 'IN'}); expect(info?.response?.status).toBe(200); const ticketBefore = info?.before.data?.tickets[0]; const ticketAfter = info?.after.data?.tickets[0]; expect(ticketBefore.usage_count + 1).toBe(ticketAfter.usage_count); await client.revokeKey(TEST_CARD_NUMBER,TEST_KEY); - await client.move({cardNumber: TEST_CARD_NUMBER, direction: 5}); + await client.move({cardNumber: TEST_CARD_NUMBER, device: 'C', direction: 'OUT'}); - const info2 = await client.moveWithInfo({cardNumber: TEST_CARD_NUMBER, direction: 3}); + const info2 = await client.moveWithInfo({cardNumber: TEST_CARD_NUMBER,device: 'C', direction: 'IN'}); expect(info?.response?.status).toBe(200); const ticketAfter2 = info2?.after.data?.tickets[0]; expect(ticketAfter.usage_count).toBe(ticketAfter2.usage_count); @@ -163,7 +165,7 @@ test('Normal Ticket: usage count will be increased on entry', async () => { test('Normal Ticket: flag door in will be set on entry', async () => { const client = new Client(); await client.reset(TEST_CARD_NUMBER); - const info = await client.moveWithInfo({cardNumber: TEST_CARD_NUMBER, direction: 3}); + const info = await client.moveWithInfo({cardNumber: TEST_CARD_NUMBER,device: 'C', direction: 'IN'}); expect(info?.response?.status).toBe(200); expect(info.before.data.card.flag).toBe(0); expect(info.after.data.card.flag).toBe(2); @@ -183,8 +185,9 @@ test('Normal Ticket: increase door log after 3 hours', async () => { 'id_card': info.data.card.id_card, 'id_customer': info.data.customer.id_customer, 'id_ticket_current' : info.data.tickets[0].id_ticket, - 'direction' : 3 + 'direction' : 'IN' }); + return; // second door in @ 2:00 am. Less then 3 hours since first door log, so no // usage_count must be consumed let createdAt = new Date(); @@ -192,27 +195,33 @@ test('Normal Ticket: increase door log after 3 hours', async () => { createdAt.setMinutes(0,0,0); info = await client.moveWithInfo({ cardNumber: TEST_CARD_NUMBER, - direction: 3, - createdAt: formatDateTime(createdAt) + direction: 'IN', + createdAt: formatDateTime(createdAt), + device: 'C' }); + return; let ticketBefore = info?.before.data?.tickets[0]; let ticketAfter = info?.after.data?.tickets[0]; expect(ticketBefore.usage_count).toBe(ticketAfter.usage_count); await client.revokeKey(TEST_CARD_NUMBER,TEST_KEY); await client.move({ cardNumber: TEST_CARD_NUMBER, - direction: 5, - createdAt: formatDateTime(createdAt) + direction: 'OUT', + createdAt: formatDateTime(createdAt), + device: 'C' }); - // @4:00 3 hours already passed, we need consume usage count + return; + + // @4:00 'IN' hours already passed, we need consume usage count createdAt = new Date(); createdAt.setHours(4); createdAt.setMinutes(0,0,0); info = await client.moveWithInfo({ cardNumber: TEST_CARD_NUMBER, - direction: 3, - createdAt: formatDateTime(createdAt) + direction: 'IN', + createdAt: formatDateTime(createdAt), + device: 'C' }); ticketBefore = info?.before.data?.tickets[0]; ticketAfter = info?.after.data?.tickets[0]; @@ -220,19 +229,21 @@ test('Normal Ticket: increase door log after 3 hours', async () => { await client.revokeKey(TEST_CARD_NUMBER,TEST_KEY); await client.move({ cardNumber: TEST_CARD_NUMBER, - direction: 5, - createdAt: formatDateTime(createdAt) + direction: 'OUT', + createdAt: formatDateTime(createdAt), + device: 'C' }); // @6:00 2 hours passed since 4, we don't need consume usage count createdAt = new Date(); await client.revokeKey(TEST_CARD_NUMBER,TEST_KEY); - createdAt.setHours(5); + createdAt.setHours('OUT'); createdAt.setMinutes(0,0,0); info = await client.moveWithInfo({ cardNumber: TEST_CARD_NUMBER, - direction: 3, - createdAt: formatDateTime(createdAt) + direction: 'IN', + createdAt: formatDateTime(createdAt), + device: 'C' }); ticketBefore = info?.before.data?.tickets[0]; ticketAfter = info?.after.data?.tickets[0]; @@ -240,8 +251,9 @@ test('Normal Ticket: increase door log after 3 hours', async () => { await client.revokeKey(TEST_CARD_NUMBER,TEST_KEY); await client.move({ cardNumber: TEST_CARD_NUMBER, - direction: 5, - createdAt: formatDateTime(createdAt) + direction: 'OUT', + createdAt: formatDateTime(createdAt), + device: 'C' }); // @20:15 Need to consume usage count @@ -250,8 +262,9 @@ test('Normal Ticket: increase door log after 3 hours', async () => { createdAt.setMinutes(15,0,0); info = await client.moveWithInfo({ cardNumber: TEST_CARD_NUMBER, - direction: 3, - createdAt: formatDateTime(createdAt) + direction: 'IN', + createdAt: formatDateTime(createdAt), + device: 'C' }); ticketBefore = info?.before.data?.tickets[0]; ticketAfter = info?.after.data?.tickets[0]; @@ -266,12 +279,14 @@ test('Normal Ticket: can\'t move 2 times in without move out', async () => { await client.move({ cardNumber: TEST_CARD_NUMBER, - direction: 3 + direction: 'IN', + device: 'C' }); try { await client.move({ cardNumber: TEST_CARD_NUMBER, - direction: 3 + direction: 'IN', + device: 'C' }); // prev statement must fail expect(true).toBe(false); @@ -287,12 +302,14 @@ test('Normal Ticket: can\'t move 2 times \'OUT\' without move in', async () => { await client.reset(TEST_CARD_NUMBER); await client.move({ cardNumber: TEST_CARD_NUMBER, - direction: 5 + direction: 'OUT', + device: 'C' }); try { await client.move({ cardNumber: TEST_CARD_NUMBER, - direction: 5 + direction: 'OUT', + device: 'C' }); // prev statement must fail expect(true).toBe(false); @@ -309,22 +326,26 @@ test('Normal Ticket: move in, move out, move in, move out', async () => { await client.checkoutKey(TEST_CARD_NUMBER,TEST_KEY); await client.move({ cardNumber: TEST_CARD_NUMBER, - direction: 3 + direction: 'IN', + device: 'C' }); await client.revokeKey(TEST_CARD_NUMBER,TEST_KEY); await client.move({ cardNumber: TEST_CARD_NUMBER, - direction: 5 + direction: 'OUT', + device: 'C' }); await client.checkoutKey(TEST_CARD_NUMBER,TEST_KEY); await client.move({ cardNumber: TEST_CARD_NUMBER, - direction: 3 + direction: 'IN', + device: 'C' }); await client.revokeKey(TEST_CARD_NUMBER,TEST_KEY); await client.move({ cardNumber: TEST_CARD_NUMBER, - direction: 5 + direction: 'OUT', + device: 'C' }); },10000); @@ -337,7 +358,8 @@ test('Normal Ticket: can\'t move \'in\' without key', async () => { await client.reset(TEST_CARD_NUMBER); await client.move({ cardNumber: TEST_CARD_NUMBER, - direction: 3 + direction: 'IN', + device: 'C' }); // should throw an exception, since no key is assigend expect(true).toBe(false);