Add validateOnly

This commit is contained in:
Schneider Roland 2022-08-02 18:39:08 +02:00
parent 97e31c4caf
commit 604e5304c1
10 changed files with 183 additions and 88 deletions

View File

@ -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,7 +28,6 @@ class DoorManager extends BaseObject
/**
* @param $cardNumber 00000000: nyomogombos nyitás
* @param $device string B(gomb)|Q(qrcode)|C(nfc),E(emergency)
* @param $direction string IN|OUT
@ -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,7 +86,8 @@ class DoorManager extends BaseObject
/**
* emergency- no card needed
*/
if ($direction == DoorLog::$DIRECTION_ALL_EMERGENCY) {
if ($device == 'E' ) {
if (!$verifyOnly) {
$doorLog->save(false);
Log::log(
[
@ -81,19 +98,40 @@ class DoorManager extends BaseObject
);
\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 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) {
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());
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,6 +207,7 @@ class DoorManager extends BaseObject
// increase the ticket usage count with 1
$usageCount = $ticket->usage_count;
$ticket->usage_count += 1;
if (!$verifyOnly) {
$ticket->save(false);
Log::log(
[
@ -170,6 +217,7 @@ class DoorManager extends BaseObject
'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;
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,10 +293,13 @@ class DoorManager extends BaseObject
}
$ticket->count_move_out = $ticket->usage_count;
if (!$verifyOnly) {
$ticket->save(false);
}
\Yii::error("direction_out: ticket count_move_out set after direction_out in sec " . $stopWatch->split());
}
if (!$verifyOnly) {
Card::updateCardFlagTicket($ticket->id_ticket);
\Yii::error("updateCardFlagTicket: card flag updated in sec " . $stopWatch->split());
@ -266,6 +319,7 @@ class DoorManager extends BaseObject
\Yii::error("direction_in: Card flag updated in sec " . $stopWatch->split());
}
}
}
$stopWatch->stop();

View File

@ -0,0 +1 @@
docker-compose exec webserver nginx -s reload

View File

@ -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"
}
}

View File

@ -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"
}

View File

@ -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;
}

View File

@ -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']
];
}

View File

@ -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);