Compare commits
2 Commits
f5581d2490
...
e0f394a051
Author | SHA1 | Date |
---|---|---|
Eirik Th S | e0f394a051 | |
Eirik Th S | ae840610d8 |
|
@ -22,6 +22,28 @@ function returns($content = 'Success', $code = 0){
|
|||
die();
|
||||
}
|
||||
|
||||
function returnsErr($alternate = ''){
|
||||
global $db;
|
||||
if($error = $db->error){
|
||||
returns("Database error: ".$error, 1);
|
||||
}
|
||||
if($alternate != ''){
|
||||
returns($alternate, 2);
|
||||
}
|
||||
|
||||
returns("Error", 2);
|
||||
}
|
||||
|
||||
function checkArgs($args){
|
||||
foreach($args as $key => $arg){
|
||||
if($arg == ""){
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function sanitize(): array{
|
||||
global $_GET, $_POST;
|
||||
$data = array();
|
||||
|
@ -29,6 +51,7 @@ function sanitize(): array{
|
|||
foreach([$_GET, $_POST] as $request){
|
||||
if(!empty($request)){
|
||||
foreach($request as $key => $value){
|
||||
if(in_array($value, ['string', 'integer', 'number', 'boolean'])){ $value = ''; } // API DEFAULTS CLEAN
|
||||
if(($data[$key] = filter($value)) === false){
|
||||
print_r($value);
|
||||
echo "Failed to sanitize: `".$key."`: ".$value." \t-\t type: ".gettype($value)."\n";
|
||||
|
|
|
@ -7,6 +7,9 @@ error_reporting(E_ALL);
|
|||
$docs['general'][] = array("method"=>'GET', "href"=>"/", "name"=>"Nothing", "body"=>"{}");
|
||||
$docs['recipe'][] = array("method"=>'GET', "href"=>"/recipe", "name"=>"Get all available recipes", "body"=>"{}");
|
||||
$docs['recipe'][] = array("method"=>'POST', "href"=>"/recipe", "name"=>"Create recipe", "body"=>"{\n \"name\": \"string\",\n \"portions\": \"integer\",\n \"public\": \"boolean\" \n}");
|
||||
$docs['recipe'][] = array("method"=>'POST', "href"=>"/recipe", "name"=>"Add item to recipe", "body"=>"{\n \"recipe_id\": \"integer\",\n \"name\": \"string\",\n \"price\": \"number\",\n \"amount\": \"integer\" \n}");
|
||||
$docs['recipe'][] = array("method"=>'POST', "href"=>"/recipe", "name"=>"Edit recipe item", "body"=>"{\n \"recipe_id\": \"integer\",\n \"recipe_item_id\": \"integer\",\n \"newName\": \"string\",\n \"newPrice\": \"number\",\n \"newAmount\": \"integer\",\n \"newItem_id\": \"integer\" \n}");
|
||||
$docs['recipe'][] = array("method"=>'POST', "href"=>"/recipe", "name"=>"Delete recipe item", "body"=>"{\n \"recipe_id\": \"integer\",\n \"del_item_id\": \"integer\",\n \"delName\": \"string\" \n}");
|
||||
|
||||
|
||||
|
||||
|
@ -61,7 +64,7 @@ function capitalizeFirst($input){
|
|||
?>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="heading<?=$i;?>">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapse<?=$i;?>" aria-expanded="true" aria-controls="collapse<?=$i;?>">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse<?=$i;?>" aria-expanded="true" aria-controls="collapse<?=$i;?>">
|
||||
<div class="badge <?=$methodClass;?>" style="margin-right: 5px;"><?=$row['method'];?></div>
|
||||
<div style="font-family: var(--bs-font-monospace); margin-right: 5px;"><?=$row['href'];?></div>
|
||||
<div><strong><?=$row['name'];?></strong></div>
|
||||
|
@ -95,6 +98,8 @@ function capitalizeFirst($input){
|
|||
let formElem = $(ev.currentTarget);
|
||||
let params = formElem.serializeArray();
|
||||
|
||||
formElem.find(".apiExecResponse").html("...")
|
||||
|
||||
let url = "."+params[0].value;
|
||||
let body = JSON.parse( params[1].value );
|
||||
|
||||
|
|
|
@ -17,14 +17,47 @@ switch ($group){
|
|||
case "recipe":
|
||||
include 'recipes.php';
|
||||
if(!empty($_POST)){
|
||||
// CREATE RECIPE
|
||||
if(isset($data['name']) && $data['name'] != "string"){
|
||||
if(isset($data['recipe_id'])){
|
||||
if($rec = new Recipes($data['recipe_id'])){
|
||||
|
||||
if(isset($data['name'])){
|
||||
$amount = 1;
|
||||
$price = 0;
|
||||
if(is_numeric($data['amount'])){
|
||||
$amount = $data['amount'];
|
||||
}
|
||||
|
||||
if(is_numeric($data['price'])){
|
||||
$price = $data['price'];
|
||||
}
|
||||
|
||||
if($rec->addItemToRecipe($data['name'], $amount, $price)){
|
||||
returns();
|
||||
}
|
||||
}
|
||||
elseif(isset($data['recipe_item_id'])){
|
||||
if($rec->editRecipeItem($data['recipe_item_id'], $data['newName'], $data['newPrice'], $data['newAmount'], $data['newItem_id'])){
|
||||
returns();
|
||||
}
|
||||
}
|
||||
elseif(isset($data['del_item_id'], $data['delName'])){
|
||||
if($rec->deleteRecipeItem($data['del_item_id'], $data['delName'])){
|
||||
returns();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
returnsErr("Recipe might not be owned by user");
|
||||
}
|
||||
}
|
||||
|
||||
// CREATE RECIPE
|
||||
if(isset($data['name'])){
|
||||
if($newID = Recipes::createRecipe($data['name'], $data['portions'], $data['public'])){
|
||||
returns("OK: ".$newID);
|
||||
}
|
||||
else {
|
||||
returns($db->error, 1);
|
||||
returnsErr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,13 +68,10 @@ switch ($group){
|
|||
break;
|
||||
|
||||
case "plan":
|
||||
returns("Coming soon...");
|
||||
returns("Coming soon... See /plan/do.php in the meantime.");
|
||||
break;
|
||||
|
||||
default:
|
||||
returns('Nothing to do');
|
||||
}
|
||||
returns('Failed.',2);
|
||||
|
||||
|
||||
$docs['recipe'][] = array("method"=>'POST', "href"=>"/recipe", "name"=>"Create recipe", "body"=>"{\n \"name\": \"string\",\n \"public\": \"boolean\" \n}");
|
||||
returnsErr('Failed.');
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<?php
|
||||
|
||||
class Recipes {
|
||||
// function __construct($recipeID = 0){
|
||||
|
||||
static function getAll(): array{
|
||||
global $user_id, $db;
|
||||
$return = array();
|
||||
|
@ -11,9 +9,15 @@ class Recipes {
|
|||
$res = $db->query($sql);
|
||||
while($row = $res->fetch_assoc()){
|
||||
$return[$row['recipe_id']] = $row;
|
||||
unset($return[$row['recipe_id']]['author']);
|
||||
if($row['author'] == $user_id){
|
||||
$return[$row['recipe_id']]['owner'] = true;
|
||||
}
|
||||
|
||||
|
||||
// $return[$row['recipe_id']]['items'] = ;
|
||||
$itemsRes = $db->query("SELECT * FROM recipe_item WHERE `recipe_id` = '$row[recipe_id]'");
|
||||
while ($item = $itemsRes->fetch_assoc()){
|
||||
$return[$row['recipe_id']]['items'][] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($return)){
|
||||
|
@ -23,20 +27,107 @@ class Recipes {
|
|||
return $return;
|
||||
}
|
||||
|
||||
static function createRecipe($name, $portions = 1, $public = 0) {
|
||||
static function createRecipe($name, $portions = 1, $public = 0): bool {
|
||||
global $user_id, $db;
|
||||
|
||||
if($portions == null){
|
||||
$portions = 1;
|
||||
}
|
||||
|
||||
if(strlen($name) <= 200 && is_numeric($public)){
|
||||
if(strlenBetween($name,2,200) && is_numeric($public)){
|
||||
$createRecipeSQL = "INSERT INTO `recipe` (name, author, portions, public) VALUES ('$name', $user_id, $portions, $public);";
|
||||
if($db->query($createRecipeSQL)){
|
||||
return $db->insert_id;
|
||||
}
|
||||
else {
|
||||
// file_put_contents('test.txt', $createRecipeSQL);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private $recipeId;
|
||||
|
||||
function __construct($recipeID = 0){
|
||||
global $db, $user_id;
|
||||
|
||||
if(!is_numeric($recipeID)){ return false; }
|
||||
|
||||
$checkRecipeOwnerRes = $db->query("SELECT `recipe_id` FROM recipe WHERE `recipe_id` = '$recipeID' AND `author` = '$user_id' LIMIT 1");
|
||||
if($checkRecipeOwnerRes->fetch_row()[0] == $recipeID){
|
||||
$this->recipeId = $recipeID;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addItemToRecipe($name, $amount, $price = 0): bool{
|
||||
global $db;
|
||||
|
||||
if((is_numeric($name) || (strlen($name) > 0 && strlen($name) < 255)) && $amount > 0 && $amount < 99){
|
||||
$nextItemIdQue = $db->query('SELECT count(0)+1 FROM recipe_item WHERE `recipe_id` = '.$this->recipeId);
|
||||
$nextItemId = $nextItemIdQue->fetch_row()[0];
|
||||
if(is_numeric($name)){
|
||||
$addItemSql = "INSERT INTO `recipe_item` (recipe_id, item_num, name, price, amount, item_id) VALUES (".verifyRecipeOwnerSQL($this->recipeId).", $nextItemId, '$name', $price, $amount, $name)";
|
||||
}
|
||||
else {
|
||||
$addItemSql = "INSERT INTO `recipe_item` (recipe_id, item_num, name, price, amount) VALUES (".verifyRecipeOwnerSQL($this->recipeId).", $nextItemId, '$name', $price, $amount)";
|
||||
}
|
||||
|
||||
if($db->query($addItemSql)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function editRecipeItem($recipe_item_id, $newName, $newPrice, $newAmount, $newItemId = null): bool{
|
||||
global $db;
|
||||
|
||||
if($newName && strlenBetween($newName,0,255)){ $set[] = "`name` = '$newName'"; }
|
||||
if(is_numeric($newPrice)){ $set[] = "`price` = '$newPrice'"; }
|
||||
if($newAmount && $newAmount > 0 && $newAmount < 99){ $set[] = "`amount` = '$newAmount'"; }
|
||||
if(is_numeric($newItemId)){ $set[] = "`item_id` = '$newItemId'"; }
|
||||
|
||||
if(!empty($set)){
|
||||
$editItemSql = "UPDATE `recipe_item` SET ".implode(', ', $set)." WHERE `recipe_id` = $this->recipeId AND `recipe_item_id` = '$recipe_item_id';";
|
||||
|
||||
// file_put_contents('test.txt', $editItemSql);
|
||||
if($db->query($editItemSql)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function deleteRecipeItem($recipe_item_id, $name): bool{
|
||||
global $db;
|
||||
|
||||
$deleteItemSql = "DELETE FROM `recipe_item` WHERE recipe_id = $this->recipeId AND `recipe_item_id` = '$recipe_item_id' AND name LIKE '$name' LIMIT 1";
|
||||
|
||||
if($db->query($deleteItemSql) && $db->affected_rows > 0){
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
returnsErr("No rows deleted");
|
||||
}
|
||||
|
||||
// file_put_contents('test.txt', $deleteItemSql);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function verifyRecipeOwnerSQL($recipeId): string{
|
||||
global $user_id;
|
||||
return "(SELECT `recipe_id` FROM recipe WHERE `recipe_id` = '$recipeId' AND `author` = '$user_id' LIMIT 1)";
|
||||
}
|
||||
|
||||
function strlenBetween($str, $min, $max): bool{
|
||||
return strlen($str) > $min && strlen($str) <= $max;
|
||||
}
|
||||
|
||||
// file_put_contents('test.txt', $addItemSql);
|
||||
|
|
|
@ -98,6 +98,9 @@ body.dollars span.price::before {
|
|||
body.dollars span.price::after {
|
||||
content: '';
|
||||
}
|
||||
span.recipeItemAmount::after {
|
||||
content: 'x';
|
||||
}
|
||||
|
||||
.subtotal {
|
||||
font-weight: bold;
|
||||
|
|
|
@ -90,7 +90,11 @@ if(!empty($data) && isset($user_id)){
|
|||
returns("Missing a value: $temp", 1);
|
||||
}
|
||||
|
||||
if( ($itemID = addItem($data['storeID'], $data['name'], $data['price'])) !== false ){
|
||||
if(!isset($data['amount'])){
|
||||
$data['amount'] = 1;
|
||||
}
|
||||
|
||||
if( ($itemID = addItem($data['storeID'], $data['name'], $data['price'], $data['amount'])) !== false ){
|
||||
returns($itemID);
|
||||
}
|
||||
else {
|
||||
|
@ -370,13 +374,13 @@ function deleteStore($storeID, $storeName, $itemsLength){
|
|||
return false;
|
||||
}
|
||||
|
||||
function addItem($storeID, $name, $price){
|
||||
function addItem($storeID, $name, $price, $amount){
|
||||
global $db, $spaceID;
|
||||
|
||||
$verifyUserOwnershipSQL = "SELECT plan_store_id FROM plan_store WHERE `space_id` = '$spaceID' AND plan_store_id = '$storeID'";
|
||||
|
||||
$insertItemSQL = "INSERT INTO plan_store_item (`plan_store_id`, `pos`, `name`, `price`)
|
||||
SELECT ($verifyUserOwnershipSQL), count(0)+1, '$name', $price FROM plan_store_item WHERE plan_store_id = '$storeID';";
|
||||
$insertItemSQL = "INSERT INTO plan_store_item (`plan_store_id`, `pos`, `name`, `price`, `amount`)
|
||||
SELECT ($verifyUserOwnershipSQL), count(0)+1, '$name', $price, $amount FROM plan_store_item WHERE plan_store_id = '$storeID';";
|
||||
|
||||
if($db->query($insertItemSQL)){
|
||||
return $db->insert_id;
|
||||
|
@ -418,7 +422,7 @@ function moveItem($storeID, $itemID, $afterID){
|
|||
if($sameStoreCheck = $db->query($sameStoreCheckSQL)){
|
||||
$stores = $sameStoreCheck->fetch_array();
|
||||
|
||||
if($stores[0] != $stores[1]){
|
||||
if(isset($stores[1]) && $stores[0] != $stores[1]){
|
||||
// DIFFERENT STORES
|
||||
$storeID = $stores[1];
|
||||
$differentStoreAddSQL = ", plan_store_id = $storeID";
|
||||
|
|
|
@ -28,15 +28,55 @@
|
|||
|
||||
<div id='totalPriceWrapper'>Space subtotal: <span id="totalPrice" class="priceWrapper price">00.00</span></div>
|
||||
<br>
|
||||
<button id="addStore">Add store</button><br><br>
|
||||
<button id="refreshAll">Refresh all</button>
|
||||
<button class="btn btn-primary mb-2" id="addStore">Add store</button><br>
|
||||
<button class="btn btn-secondary" id="refreshAll">Refresh all</button>
|
||||
|
||||
</div>
|
||||
|
||||
<script src='plan.js'></script>
|
||||
<script src='recipe.js'></script>
|
||||
<script src='draggingClass.js'></script>
|
||||
</div>
|
||||
<?php include $rPath.'webdata/footer.html'; ?>
|
||||
</div>
|
||||
|
||||
<div class="modal" tabindex="-1" id="addStoreModal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Add store</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body align-content-center">
|
||||
<button class="btn btn-primary" id="addEmptyStore">Empty store</button>
|
||||
<hr>
|
||||
<div class="accordion mb-2" id="addStoreRecipe"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
let addStoreModal = new bootstrap.Modal( document.getElementById('addStoreModal') );
|
||||
|
||||
$("#addStore").on('click', ev=>{
|
||||
ev.stopPropagation();
|
||||
addStoreModal.show();
|
||||
});
|
||||
|
||||
$("#addStoreModal").on('show.bs.modal', ev=> {
|
||||
$("#addStoreRecipe").html('');
|
||||
|
||||
$.getJSON('/api/v1/recipe', {}, resp => {
|
||||
let recipes = new Recipe(resp);
|
||||
recipes.getAccordionHtml('#addStoreRecipe');
|
||||
});
|
||||
});
|
||||
|
||||
$("#addEmptyStore").click(ev => {
|
||||
stores.push(new Store());
|
||||
addStoreModal.hide();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -27,7 +27,7 @@ class Store {
|
|||
html += " <div class='card-body'>";
|
||||
html += " <ul class='list-group list-group-flush storeItems dragHolder'>";
|
||||
html += " <li class='list-group-item emptyList'>No items added</li>";
|
||||
html += " <li class='list-group-item draggable' style='height: 10px; width: 100%;'></li>";
|
||||
html += " <li class='list-group-item draggable' data-itemid='0' data-storeid='"+this.storeID+"' style='height: 10px; width: 100%;'></li>";
|
||||
html += " </ul>";
|
||||
|
||||
html += " <span class='addItemFormWrapper'>";
|
||||
|
@ -203,19 +203,20 @@ class Store {
|
|||
}
|
||||
}
|
||||
|
||||
addItem(text, price){
|
||||
addItem(text, price, amount){
|
||||
amount = amount || 1;
|
||||
if(text.length > 0){
|
||||
|
||||
if(this.storeID === null){
|
||||
this.getStoreID().done(json => { this.addItem(text, price); });
|
||||
this.getStoreID().done(json => { this.addItem(text, price, amount); });
|
||||
|
||||
return $.ajax();
|
||||
}
|
||||
|
||||
let that = this;
|
||||
return ajaxReq({ plan: 'addItem', storeID: this.storeID, name: text, price: price })
|
||||
return ajaxReq({ plan: 'addItem', storeID: this.storeID, name: text, price: price, amount: amount })
|
||||
.done(json => {
|
||||
return that.addItemHtml(text, price, json['data']);
|
||||
return that.addItemHtml(text, price, json['data'], amount);
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -233,6 +234,7 @@ class Store {
|
|||
|
||||
let html = "\n";
|
||||
html += "<li class='list-group-item draggable"+(checked?' checkedItem':'')+"' id='item_"+itemID+"' data-itemid='"+itemID+"' style='height: 100%; min-width: 200px;'>"; // draggable='true'
|
||||
// html += " <span style='float: left; margin-right: 0px; width: 32px; margin-left: -22px;'><svg xmlns='http://www.w3.org/2000/svg' fill='gray' class='bi bi-grip-vertical' viewBox='0 0 16 16' height='32' width='32'> <path d='M7 2a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zM7 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zM7 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0z'></path></svg></span>";
|
||||
html += " <span style='float: left; display: none; margin-right: 5px;' class='checkItems'><input type='checkbox'"+(checked?" checked":"")+"></span>";
|
||||
html += " <span style='float: left;'>"+text+"</span>";
|
||||
|
||||
|
@ -524,13 +526,10 @@ class Store {
|
|||
var stores = [];
|
||||
$("#stores").html("");
|
||||
|
||||
$("#addStore").click(ev => {
|
||||
stores.push(new Store());
|
||||
});
|
||||
|
||||
$("#refreshAll").on('click', ev => {
|
||||
$("#stores").css('height', $("#stores").height());
|
||||
$(".tooltip").remove();
|
||||
$(".elemHolder").remove();
|
||||
getStores(spaceID).done(json => { $("#stores").css('height', ''); });
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
/*jshint sub:true, esversion: 6, -W083 */
|
||||
|
||||
class Recipe {
|
||||
constructor(jsonObj){
|
||||
this.portionAmount = 1;
|
||||
if(typeof jsonObj === "undefined"){
|
||||
alert('create new store?');
|
||||
}
|
||||
else {
|
||||
this.recipes = jsonObj.data;
|
||||
}
|
||||
}
|
||||
|
||||
getAccordionHtml(appendId){
|
||||
let appendElem = $(appendId);
|
||||
if(!appendElem.hasClass('accordion')){ appendElem.addClass('accordion'); }
|
||||
|
||||
for(const key in this.recipes){
|
||||
const recipe = this.recipes[key];
|
||||
|
||||
let html = "<div class='accordion-item'>"+
|
||||
" <h2 class='accordion-header' id='heading"+key+"'>"+
|
||||
" <button class='accordion-button' type='button' data-bs-toggle='collapse' data-bs-target='#collapse"+key+"' aria-expanded='true' aria-controls='collapse"+key+"'>"+recipe.name+"</button>"+
|
||||
" </h2>"+
|
||||
" <div id='collapse"+key+"' class='accordion-collapse collapse' aria-labelledby='heading"+key+"' data-bs-parent='#addStoreRecipe'>"+
|
||||
" <div class='accordion-body'>"+
|
||||
" <ul class='list-group list-group-flush' id='recipeItems"+key+"' data-recipe-name='"+recipe.name+"' data-recipe-id='"+recipe['recipe_id']+"'>";
|
||||
|
||||
for(const itemKey in recipe.items){
|
||||
const recipeItem = recipe.items[itemKey];
|
||||
html += "<li class='list-group-item'>"+
|
||||
"<div class='row'>"+
|
||||
"<span class='col-1 number recipeItemAmount' data-amount='"+recipeItem.amount+"'>"+recipeItem.amount+"</span> "+
|
||||
"<span class='col itemName'>"+recipeItem.name+"</span> "+
|
||||
"<span class='col-3 price'>"+recipeItem.price+"</span> ";
|
||||
if(recipe.owner) {
|
||||
html += "<span class='col-2 editing gx-3' style='display: none;' data-itemid='"+recipeItem['recipe_item_id']+"'><img src='../icon/pencil-square.svg' class='ariaButton editRow' alt='Edit'><img src='../icon/x-circle.svg' class='ariaButton delRow' alt='Remove' style='filter: invert(28%) sepia(93%) saturate(1776%) hue-rotate(334deg) brightness(89%) contrast(94%);'></span> ";
|
||||
}
|
||||
html += "</div>"+
|
||||
"</li>";
|
||||
}
|
||||
|
||||
html += " </ul>"+
|
||||
" <div class='row row-cols-2'><label >Portions:</label><div class='input-group portionAmountBtns'>"+
|
||||
" <button class='btn btn-outline-danger' data-type='descend' type='button'>-</button>"+
|
||||
" <input class='form-control' data-type='edit' type='number' value='"+this.portionAmount+"' min='1' max='99' aria-label='Amount of portions'>"+
|
||||
" <button class='btn btn-outline-success' data-type='ascend' type='button'>+</button>"+
|
||||
" </div></div>"+
|
||||
" <button class='btn btn-primary m-1 addStoreContents'>Add as a store</button>";
|
||||
if(recipe.owner){
|
||||
html += " <button class='btn btn-secondary m-1 editList' data-recipeid='"+key+"'>Edit list...</button>";
|
||||
}
|
||||
html += " </div>"+
|
||||
"</div>";
|
||||
|
||||
let htmlElem = $(html);
|
||||
|
||||
// MODIFY PORTIONS
|
||||
htmlElem.find('.portionAmountBtns button, .portionAmountBtns input').on('click', portionEv=>{
|
||||
let clickedElem = $(portionEv.currentTarget);
|
||||
let inputElem = clickedElem.parent().find('input');
|
||||
let amountNum = Number(inputElem.val());
|
||||
switch (clickedElem.attr('data-type')){
|
||||
case 'descend':
|
||||
if(amountNum > 1){
|
||||
amountNum--;
|
||||
}
|
||||
break;
|
||||
case 'ascend':
|
||||
if(amountNum < 99){
|
||||
amountNum++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
this.portionAmount = amountNum;
|
||||
|
||||
inputElem.val(amountNum);
|
||||
inputElem.trigger('change');
|
||||
});
|
||||
htmlElem.find('.portionAmountBtns input').on('change', portionChangeEv => {
|
||||
let amountModifier = Number($(portionChangeEv.currentTarget).val());
|
||||
$("#recipeItems"+key+" li .number").each((k, portionVal)=>{
|
||||
let elem = $(portionVal);
|
||||
elem.html( Number(elem.attr('data-amount'))*amountModifier );
|
||||
});
|
||||
});
|
||||
|
||||
// SAVE AS A STORE
|
||||
htmlElem.find('.addStoreContents').one('click', addStoreEv => {
|
||||
let recipeList = $(addStoreEv.currentTarget).parent().find('ul');
|
||||
let recipeItems = [];
|
||||
recipeList.find("li").each((k, recipeItem)=> {
|
||||
let elem = $(recipeItem);
|
||||
recipeItems.push([elem.find('.itemName').html(), elem.find('.price').html(), elem.find('.recipeItemAmount').html()]);
|
||||
});
|
||||
|
||||
this.saveToStore(recipeList.attr('data-recipe-name'), recipeItems);
|
||||
addStoreModal.hide();
|
||||
});
|
||||
|
||||
// TODO: EDIT RECIPE
|
||||
htmlElem.find('.editList').css('cursor','pointer').one('click', editListEv => {
|
||||
let accBody = $(editListEv.currentTarget).parent();
|
||||
|
||||
accBody.find('li .editing').show();
|
||||
});
|
||||
|
||||
htmlElem.find(".ariaButton").off('keydown').on('keydown', function(e){
|
||||
if(e.code === "Space" || e.code === "Enter"){
|
||||
e.preventDefault();
|
||||
$(this).trigger('click');
|
||||
}
|
||||
});
|
||||
|
||||
htmlElem.find('.editRow').on('click', ev=>{this.editRow(ev);});
|
||||
htmlElem.find('.delRow').on('click', ev=>{this.editRow(ev, true);});
|
||||
|
||||
htmlElem.appendTo(appendElem);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
editRow(event, doDelete){
|
||||
doDelete = doDelete || false;
|
||||
let eventElem = $(event.currentTarget);
|
||||
let recipe_id = eventElem.parent().parent().parent().parent().attr('data-recipe-id');
|
||||
let r_item_id = eventElem.parent().attr('data-itemid');
|
||||
let item_name = eventElem.parent().parent().find('.itemName').html();
|
||||
|
||||
if(doDelete){
|
||||
ajaxPost('/api/v1/recipe', { recipe_id: recipe_id, del_item_num: r_item_id, delName: item_name }).done(resp => {
|
||||
// eventElem.remove();
|
||||
eventElem.parent().parent().parent().hide();
|
||||
});
|
||||
}
|
||||
else {
|
||||
alert("Edit coming soon..."+"\nrecipeid: "+recipe_id+"\nitem_num: "+item_num);
|
||||
}
|
||||
}
|
||||
|
||||
saveToStore(storeName, recipeItems){
|
||||
if(typeof Store !== "undefined" && typeof stores !== "undefined"){
|
||||
if(!storeName){
|
||||
storeName = 'Recipe';
|
||||
}
|
||||
else {
|
||||
storeName = 'Recipe: '+storeName;
|
||||
}
|
||||
|
||||
stores.push( new Store(storeName));
|
||||
let storeKey = stores.length - 1;
|
||||
return stores[storeKey].getStoreID().done(json => {
|
||||
for (const recKey in recipeItems) {
|
||||
const recItem = recipeItems[recKey];
|
||||
stores[storeKey].addItem(recItem[0], recItem[1], recItem[2]);
|
||||
}
|
||||
});
|
||||
}
|
||||
console.error("Store class not initialized, or no stores-list found.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function ajaxPost(url, params){
|
||||
return $.post(url, params)
|
||||
.done(resp => {
|
||||
if(resp.status !== 0){
|
||||
alert(resp.message);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
|
@ -12,6 +12,15 @@ if(!isset($config) || empty($config)){
|
|||
|
||||
$projectRoot = $config["general"]["projectRoot"];
|
||||
|
||||
function getConfig($val, $group = "general"){
|
||||
global $config;
|
||||
|
||||
if(isset($config[$group][ $val ])){
|
||||
return $config[$group][$val];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function database(){
|
||||
global $config;
|
||||
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
<?php
|
||||
|
||||
$err = array();
|
||||
$msg = array();
|
||||
|
||||
$missingConfig = false;
|
||||
|
||||
if($_SERVER['HTTP_HOST'] != "localhost"){
|
||||
$err[] = "You need to use this page from localhost";
|
||||
$fatalErr = true;
|
||||
}
|
||||
|
||||
// CREATE USER IN DATABASE
|
||||
|
||||
|
||||
|
@ -16,18 +26,15 @@ $sql = "CREATE OR REPLACE TABLE `user` (
|
|||
`ctime` VARCHAR(220)
|
||||
) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
|
||||
|
||||
INSERT INTO `user` (full_name, user_email, user_level, pwd)
|
||||
VALUES ('Admin', 'admin@svagard.no', 5, '-');
|
||||
|
||||
|
||||
CREATE OR REPLACE TABLE plan_space (
|
||||
CREATE OR REPLACE TABLE `plan_space` (
|
||||
`space_id` INT auto_increment PRIMARY KEY,
|
||||
`space_name` tinytext,
|
||||
`owner_id` BIGINT(20),
|
||||
CONSTRAINT plan_space_owner_FK FOREIGN KEY (`owner_id`) REFERENCES `user`(`user_id`)
|
||||
);
|
||||
|
||||
CREATE OR REPLACE TABLE plan_space_member (
|
||||
CREATE OR REPLACE TABLE `plan_space_member` (
|
||||
`space_id` INT auto_increment NOT NULL,
|
||||
`member_id` BIGINT(20) NOT NULL,
|
||||
`timestamp` DATETIME default current_timestamp() NOT NULL,
|
||||
|
@ -36,7 +43,7 @@ CREATE OR REPLACE TABLE plan_space_member (
|
|||
CONSTRAINT space_member_space_FK FOREIGN KEY (`space_id`) REFERENCES `plan_space`(`space_id`)
|
||||
);
|
||||
|
||||
CREATE OR REPLACE TABLE plan_store (
|
||||
CREATE OR REPLACE TABLE `plan_store` (
|
||||
`plan_store_id` INT auto_increment,
|
||||
`space_id` INT NOT NULL,
|
||||
`name` varchar(100) NOT NULL,
|
||||
|
@ -46,7 +53,7 @@ CREATE OR REPLACE TABLE plan_store (
|
|||
CONSTRAINT plan_store_user_FK FOREIGN KEY (`space_id`) REFERENCES `plan_space`(`space_id`)
|
||||
) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
|
||||
|
||||
CREATE OR REPLACE TABLE plan_store_item (
|
||||
CREATE OR REPLACE TABLE `plan_store_item` (
|
||||
`plan_item_id` INT auto_increment NOT NULL,
|
||||
`plan_store_id` INT NOT NULL,
|
||||
`pos` tinyint(3) unsigned,
|
||||
|
@ -58,6 +65,126 @@ CREATE OR REPLACE TABLE plan_store_item (
|
|||
CONSTRAINT plan_store_item_FK FOREIGN KEY (plan_store_id) REFERENCES `plan_store`(`plan_store_id`)
|
||||
) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
|
||||
|
||||
|
||||
";
|
||||
|
||||
$recipeSQL = "
|
||||
DROP TABLE `recipe_item`;
|
||||
|
||||
CREATE OR REPLACE TABLE `recipe` (
|
||||
`recipe_id` INT AUTO_INCREMENT PRIMARY KEY NOT NULL ,
|
||||
`name` TEXT NOT NULL,
|
||||
`author` BIGINT(20) NOT NULL,
|
||||
`portions` SMALLINT DEFAULT 1,
|
||||
`public` BOOLEAN DEFAULT 0,
|
||||
CONSTRAINT author_FK FOREIGN KEY (`author`) REFERENCES user(`user_id`)
|
||||
);
|
||||
|
||||
CREATE OR REPLACE TABLE `recipe_item` (
|
||||
`recipe_id` INT NOT NULL,
|
||||
`recipe_item_id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`item_num` SMALLINT NOT NULL,
|
||||
`name` TEXT NOT NULL,
|
||||
`price` DECIMAL(8,2) DEFAULT 0.00,
|
||||
`amount` INT DEFAULT 1,
|
||||
`item_id` BIGINT(20),
|
||||
|
||||
CONSTRAINT recipe_FK FOREIGN KEY (`recipe_id`) REFERENCES recipe(`recipe_id`)
|
||||
);";
|
||||
|
||||
if(!empty($_POST) && !isset($fatalErr)){
|
||||
include "init.php";
|
||||
$db = database();
|
||||
|
||||
if(isset($_POST['setupDB'])){
|
||||
|
||||
$db->multi_query($sql);
|
||||
if($error = $db->error){
|
||||
$err[] = $error;
|
||||
}
|
||||
else {
|
||||
$msg[] = "Database tables are setup/reset.";
|
||||
}
|
||||
}
|
||||
elseif (isset($_POST['recipeTables'])){
|
||||
$db->multi_query($recipeSQL);
|
||||
if($error = $db->error){
|
||||
$err[] = $error;
|
||||
}
|
||||
else {
|
||||
$msg[] = "Recipe tables are setup/reset.";
|
||||
}
|
||||
}
|
||||
elseif (isset($_POST['goProject'])){
|
||||
header("Location: ".getConfig('projectRoot')."/");
|
||||
}
|
||||
|
||||
$db->close();
|
||||
}
|
||||
|
||||
?><!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Setup</title>
|
||||
<style>
|
||||
.alert-danger {
|
||||
color: #842029;
|
||||
background-color: #f8d7da;
|
||||
border-color: #f5c2c7;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
color: #0f5132;
|
||||
background-color: #d1e7dd;
|
||||
border-color: #badbcc;
|
||||
}
|
||||
|
||||
.alert {
|
||||
position: relative;
|
||||
padding: 1rem 1rem;
|
||||
margin-bottom: 1rem;
|
||||
border: 1px solid transparent;
|
||||
border-radius: .25rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div style='max-width: 500px; margin: auto; text-align: center;'>
|
||||
<h1>Setup</h1>
|
||||
<?php
|
||||
if(!empty($err)){
|
||||
foreach ($err as $e) {
|
||||
echo "<div class='alert alert-danger'>$e</div>";
|
||||
}
|
||||
}
|
||||
if(!empty($msg)){
|
||||
foreach ($msg as $m) {
|
||||
echo "<div class='alert alert-success'>$m</div>";
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($fatalErr)){
|
||||
die();
|
||||
}
|
||||
?>
|
||||
<form action='setup.php' method='POST'>
|
||||
<?php if($missingConfig){ ?>
|
||||
<p>Configuration-file is missing or lacks content. Fill out the data here:</p>
|
||||
<h4>Users Database</h4>
|
||||
<p><label>Host: <input type='text' name='DatabaseUser-host' value='<?=$co['DatabaseUser']['host']??''?>' placeholder='localhost:3306' required></label></p>
|
||||
<p><label>User: <input type='text' name='DatabaseUser-user' value='<?=$co['DatabaseUser']['user']??''?>' placeholder='LuxFictus' required></label></p>
|
||||
<p><label>Password: <input type='password' name='DatabaseUser-password' value='<?=$co['DatabaseUser']['password']??''?>' placeholder='******' required></label></p>
|
||||
<p><label>Database: <input type='text' name='DatabaseUser-database' value='<?=$co['DatabaseUser']['database']??''?>' placeholder='journal' required></label></p>
|
||||
|
||||
<input type='submit' value="Save" name='setup'>
|
||||
<?php } ?>
|
||||
<p><button name="setupDB">Setup tables</button></p>
|
||||
<p><button name="recipeTables">Setup recipe tables</button></p>
|
||||
<br>
|
||||
<p><button name="goProject">Go to project</button></p>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue