Updated Zapette API and script

This commit is contained in:
keplyx 2020-02-25 16:20:56 +01:00
parent ebe52728c5
commit 2154c439df
5 changed files with 301 additions and 60 deletions

View file

@ -1,35 +0,0 @@
<?php
$rest_json = file_get_contents("php://input");
$_POST = json_decode($rest_json, true);
// Must have a code and password field
$fp = fopen('.htpassajax', 'r');
$password = trim(fread($fp, filesize('.htpassajax')));
fclose($fp);
if ($_POST["password"] != $password)
die("Wrong Password");
// open the file and get the stock
$file = '../data/stock-v2.json';
$fp = fopen($file, 'r');
$result = json_decode(fread($fp, filesize($file)));
fclose($fp);
$returnVal = 'N/A';
// Get the price from the given code and remove 1 in quantity. Do not get the price if quantity is at 0
foreach ($result->articles as $articleObject) {
if ($articleObject->code === $_POST["code"] && intval($articleObject->quantity) > 0) {
$returnVal = $articleObject->name . "\n". $articleObject->price . "";
$articleObject->quantity = strval(intval($articleObject->quantity) - 1);
}
}
// open the file and write the updated stock
$fp = fopen('../data/stock.json', 'w');
fwrite($fp, json_encode($result));
fclose($fp);
echo $returnVal;

10
ajax/zapette.php Normal file
View file

@ -0,0 +1,10 @@
<?php
$relativePath = "../";
require_once $relativePath.'classes/zapetteHandler.php';
$rest_json = file_get_contents("php://input");
$_POST = json_decode($rest_json, true);
$handler = new ZapetteHandler($_POST);
echo json_encode($handler->do_action());

View file

@ -35,6 +35,14 @@ class Dao
return $cursor->fetchAll(PDO::FETCH_ASSOC); return $cursor->fetchAll(PDO::FETCH_ASSOC);
} }
public function get_article_of_code($code)
{
$sql = 'SELECT * FROM articles WHERE code=?';
$cursor = $this->conn->prepare($sql);
$cursor->execute([$code]);
return $cursor->fetchAll(PDO::FETCH_ASSOC)[0];
}
public function get_categories_of_article($articleid) public function get_categories_of_article($articleid)
{ {
$sql = 'SELECT category_id FROM article_categories WHERE article_id=?'; $sql = 'SELECT category_id FROM article_categories WHERE article_id=?';

121
classes/zapetteHandler.php Normal file
View file

@ -0,0 +1,121 @@
<?php
require_once 'dao.php';
class ZapetteHandler
{
private $valid_actions = ["scan", "validate",];
private $action;
private $data;
private $given_password;
private $dao;
private $password;
private $responseArray = array(
"status" => 0,
"message" => "Success",
"data" => "",
);
public function __construct($post)
{
$this->read_password();
$this->given_password = $this->get_password($post);
$this->action = $this->get_action($post);
$this->data = $this->get_data($post);
$this->dao = new Dao();
}
public function do_action()
{
$result = "";
if ($this->is_password_valid()) {
if ($this->action == "scan") {
$result = $this->get_scanned_article();
if (sizeof($result) == 0)
$this->setUnknownCodeErrorResponse();
} else if ($this->action == "validate") {
$result = $this->update_stock();
if (!$result)
$this->setUpdateStockErrorResponse();
}
} else {
$this->setWrongPasswordErrorResponse();
}
$this->responseArray["data"] = $result;
return $this->responseArray;
}
private function read_password() {
$real_path = __DIR__ . "/.htpasszapette";
$fp = fopen($real_path, 'r');
$this->password = trim(fread($fp, filesize($real_path)));
fclose($fp);
}
private function is_password_valid() {
return $this->given_password == $this->password;
}
private function get_scanned_article() {
$article = [];
if ($this->data != "") {
$article = $this->dao->get_article_of_code($this->data);
}
return $article;
}
private function update_stock() {
$result = false;
if ($this->data != "") {
foreach ($this->data as $row) {
$result = $this->dao->update_article_stock($row["id"], $row["quantity"]);
}
}
return $result;
}
function setWrongPasswordErrorResponse()
{
$this->responseArray["status"] = 1;
$this->responseArray["message"] = "Error: Wrong password";
}
function setUnknownCodeErrorResponse()
{
$this->responseArray["status"] = 2;
$this->responseArray["message"] = "Error: Unknown code scanned";
}
function setUpdateStockErrorResponse()
{
$this->responseArray["status"] = 3;
$this->responseArray["message"] = "Error: Impossible to update stock";
}
private function get_action($inputData)
{
if (!in_array($inputData["action"], $this->valid_actions))
return "";
else
return $inputData["action"];
}
private function get_data($inputData)
{
if ($inputData["data"] == null)
return "";
else
return $inputData["data"];
}
private function get_password($inputData)
{
if ($inputData["password"] == null)
return "";
else
return $inputData["password"];
}
}

View file

@ -1,37 +1,174 @@
# run pip3 install requests # run pip3 install requests
import requests import requests
import json import json
import os
from signal import signal, SIGINT
from sys import exit
API_ENDPOINT = "https://srv-falcon.etud.insa-toulouse.fr/~proximo/ajax/scan_article.php" # API_ENDPOINT = "https://etud.insa-toulouse.fr/~proximo/ajax/zapette.php"
API_ENDPOINT = "http://localhost/proximo/ajax/zapette.php"
def get_password(): class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
class scan_types:
SELL = 'v',
BUY = 'a',
class error_types:
NONE = 0,
NETWORK = 1,
URL = 2,
INPUT = 3,
NO_EXIST = 4,
class Scanner:
def __init__(self):
self.ask_type()
self.password = self.get_password()
self.scannedArticles = []
def ask_type(self):
typeInput = input("\nVoulez vous " + bcolors.OKGREEN + "acheter" + bcolors.ENDC + " ou " + bcolors.FAIL + "vendre" + bcolors.ENDC + " ? [" + bcolors.OKGREEN + "a" + bcolors.ENDC + "/" + bcolors.FAIL + "v" + bcolors.ENDC + "] ")
if (typeInput.lower() == 'a'):
self.type = scan_types.BUY
else:
self.type = scan_types.SELL
def get_password(self):
with open('pass') as f: with open('pass') as f:
password = f.readline() password = f.readline()
return password.strip() return password.strip()
def display_type(self):
if (self.type == scan_types.SELL):
print(" ==> Mode " + bcolors.FAIL + bcolors.BOLD + "VENTE")
else:
print(" ==> Mode " + bcolors.OKGREEN + bcolors.BOLD + "ACHAT")
print(bcolors.ENDC)
def search_product(code): def scan_product(self, code):
# data to be sent to api
data = { data = {
'password': get_password(), 'password': self.password,
'code': str(code) 'action': 'scan',
'data': str(code)
} }
# sending post request and saving response as response object
r = requests.post(url=API_ENDPOINT, data=json.dumps(data)) r = requests.post(url=API_ENDPOINT, data=json.dumps(data))
return r.text if (r.json()['status'] == 0):
article = r.json()["data"]
self.scannedArticles.append(article)
return r.json()['status'] == 0
def display_cart(self):
total = 0.0
for article in self.scannedArticles:
print(article["name"] + ' : ' + bcolors.BOLD + article["price"] + '' + bcolors.ENDC)
total += float(article["price"])
# Print only to only 2 decimals
total_display = "{:.2f}".format(total)
print(bcolors.OKGREEN + "Total: " + bcolors.BOLD + total_display + '' + bcolors.ENDC)
def send_cart(self):
scanned_list = []
modifier = -1 if self.type == scan_types.SELL else 1
for article in self.scannedArticles:
scanned_list.append({"id": article["id"], "quantity": modifier})
data = {
'password': self.password,
'action': 'validate',
'data': scanned_list
}
r = requests.post(url=API_ENDPOINT, data=json.dumps(data))
return r.json()['status'] == 0
def ask_confirmation(message):
confirm_input = input(message)
return confirm_input.lower() == 'o'
def clear_screen():
os.system('clear')
print("Appuyez sur " + bcolors.BOLD + "[CTRL + C]" + bcolors.ENDC + " à tout moment pour quitter.\n")
def printStartScreen():
clear_screen()
print(bcolors.BOLD)
print(bcolors.WARNING + "#########################################")
print("#/ \#")
print("# " + bcolors.FAIL + "-=|" + bcolors.OKGREEN + " ZAPETTE " + bcolors.FAIL + "|=-" + bcolors.WARNING + " #")
print("#\ /#")
print("#########################################")
print(bcolors.ENDC)
print("Bienvenue dans le programme de la Zapette !")
def display_scan_header(scanner, last_error):
clear_screen()
scanner.display_type()
print("Scannez le codes puis appuyez sur [ENTRÉE] pour valider.")
print("Appuyez sur [ENTRÉE] sans code pour valider la commande.\n")
scanner.display_cart()
if (last_error == error_types.URL):
print(bcolors.FAIL + "Format URL invalide !" + bcolors.ENDC)
elif (last_error == error_types.NETWORK):
print(bcolors.FAIL + "URL invalide !" + bcolors.ENDC)
elif (last_error == error_types.INPUT):
print(bcolors.FAIL + "Code invalide !" + bcolors.ENDC)
elif (last_error == error_types.NO_EXIST):
print(bcolors.FAIL + "L'article n'existe pas." + bcolors.ENDC)
print()
def confirm_end_scan(scanner):
display_scan_header(scanner, error_types.NONE)
return ask_confirmation("Voulez vous vraiment terminer et envoyer les modifications ? [o/n] ")
def handler(signal_received, frame):
os.system('clear')
print('Programme de la zapette terminé.')
exit(0)
def validate_cart(scanner):
clear_screen()
print("Envoi des modifications au serveur...")
if (scanner.send_cart()):
print(bcolors.OKGREEN + bcolors.BOLD + "Succès !" + bcolors.ENDC)
else:
print(bcolors.FAIL + bcolors.BOLD + "Échec !" + bcolors.ENDC)
input("\nAppuyez sur [ENTRÉE] pour continuer...")
def main(): def main():
code_input = input('Scannez le code\n') signal(SIGINT, handler)
printStartScreen()
while True:
scanner = Scanner()
last_error = error_types.NONE
while True:
display_scan_header(scanner, last_error)
code_input = input('=> ')
if (code_input == ""):
if (confirm_end_scan(scanner)):
validate_cart(scanner)
break
else:
continue
try: try:
code = int(code_input) code = int(code_input)
result = search_product(code) if (scanner.scan_product(code)):
print(result) last_error = error_types.NONE
else:
last_error = error_types.NO_EXIST
except requests.exceptions.MissingSchema: except requests.exceptions.MissingSchema:
print("Format URL invalide !") last_error = error_types.URL
except requests.exceptions.ConnectionError: except requests.exceptions.ConnectionError:
print("URL invalide !") last_error = error_types.NETWORK
except ValueError: except ValueError:
print("Code invalide !") last_error = error_types.INPUT
clear_screen()
main() main()