Skip to content

Commit f7ed422

Browse files
authored
Merge pull request #199 from globaldyne/v12.2
V12.2
2 parents de9d274 + c1d133e commit f7ed422

28 files changed

+1387
-691
lines changed

CHANGELOG.md

+15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,19 @@
11
# CHANGELOG
2+
### Version 12.2
3+
- Docker file update
4+
- Fixed document upload for ingredients returning incorrect results
5+
- Update login method
6+
- Fix API formula failing to return formulas
7+
- Added formulas upload via the API
8+
- Prevent user profile update if managed externally
9+
- API now allows upload for formulas, ingredients
10+
- User password is now using a stronger encryption algorithm
11+
- Forgot password modal update for BS5
12+
- Forgot password wording update
13+
- Check if user password is already encrypted when env user variables provided, encrypt if not
14+
- Added a stress test script to crate dummy formulas
15+
- Added available API calls endpoint table
16+
217
### Version 12.1
318
- Added summary of total amount required for pending materials
419
- Added list of materials per supplier

Dockerfile

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ RUN microdnf --setopt=tsflags=nodocs -y install \
2525
openssl \
2626
mysql \
2727
ncurses \
28-
nginx
28+
nginx \
29+
procps-ng
2930

3031

3132

VERSION.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
12.1
1+
12.2

api-functions/categories_get.php

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
if (!defined('pvault_panel')){ die('Not Found');}
4+
5+
header('Content-Type: application/json');
6+
global $conn;
7+
8+
$sql = mysqli_query($conn, "SELECT id, name, notes, image, colorKey FROM ingCategory");
9+
10+
if (!$sql) {
11+
error_log(mysqli_error($conn));
12+
die(json_encode(['error' => 'Query failed: ' . mysqli_error($conn)]));
13+
}
14+
15+
$rows = array();
16+
17+
// Default image and color key values
18+
$defaultImagePath = __ROOT__."/img/molecule.png";
19+
$defaultColorKey = "255, 255, 255";
20+
21+
// Loop through the result set
22+
while ($r = mysqli_fetch_assoc($sql)) {
23+
// Ensure notes are set to "N/A" if empty
24+
$r['notes'] = empty($r['notes']) ? "N/A" : $r['notes'];
25+
26+
// Handle the image field
27+
if (empty($r['image'])) {
28+
// Image is empty, use default image
29+
$r['image'] = base64_encode(file_get_contents($defaultImagePath));
30+
} else {
31+
// Split the base64 string and use it
32+
$img = explode('data:image/png;base64,', $r['image']);
33+
$r['image'] = isset($img[1]) ? $img[1] : base64_encode(file_get_contents($defaultImagePath));
34+
}
35+
36+
// Ensure colorKey is set to default value if empty
37+
$r['colorKey'] = empty($r['colorKey']) ? $defaultColorKey : $r['colorKey'];
38+
39+
// Cast id to integer
40+
$r['id'] = (int)$r['id'];
41+
42+
// Filter out empty values (if needed)
43+
$rows['categories'][] = array_filter($r);
44+
}
45+
46+
// Close the database connection
47+
mysqli_close($conn);
48+
49+
// Set headers and output the JSON response
50+
header('Content-Type: application/json; charset=utf-8');
51+
echo json_encode($rows, JSON_PRETTY_PRINT);
52+
return;
53+
?>

api-functions/documents_get.php

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
if (!defined('pvault_panel')){ die('Not Found');}
4+
5+
header('Content-Type: application/json');
6+
global $conn;
7+
// Pagination setup
8+
$itemsPerPage = isset($_GET['limit']) ? (int)$_GET['limit'] : 10; // Default to 10 items per page
9+
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1; // Default to page 1
10+
$page = $page > 0 ? $page : 1; // Ensure page number is positive
11+
$offset = ($page - 1) * $itemsPerPage;
12+
13+
// Query to fetch paginated data
14+
$sql = mysqli_query($conn, "SELECT id, ownerID, type, name, notes, docData, created_at, updated_at
15+
FROM documents
16+
LIMIT $itemsPerPage OFFSET $offset");
17+
18+
// Check if the query was successful
19+
if (!$sql) {
20+
die(json_encode(['error' => 'Query failed: ' . mysqli_error($conn)]));
21+
}
22+
23+
$rows = array();
24+
25+
// Process the results
26+
while ($rx = mysqli_fetch_assoc($sql)) {
27+
$r['id'] = (int)$rx['id'];
28+
$r['ownerID'] = (int)$rx['ownerID'] ?: 0;
29+
$r['type'] = (int)$rx['type'] ?: 0;
30+
$r['name'] = (string)$rx['name'] ?: "-";
31+
$r['notes'] = (string)$rx['notes'] ?: "-";
32+
$r['docData'] = (string)$rx['docData'];
33+
$r['created_at'] = (string)$rx['created_at'] ?: "-";
34+
$r['updated_at'] = (string)$rx['updated_at'] ?: "-";
35+
36+
$rows['documents'][] = $r;
37+
}
38+
39+
// Total records count for pagination metadata
40+
$totalCountQuery = mysqli_query($conn, "SELECT COUNT(*) AS total FROM documents");
41+
$totalCount = mysqli_fetch_assoc($totalCountQuery)['total'];
42+
43+
// Pagination metadata
44+
$rows['pagination'] = [
45+
'currentPage' => $page,
46+
'itemsPerPage' => $itemsPerPage,
47+
'totalItems' => (int)$totalCount,
48+
'totalPages' => ceil($totalCount / $itemsPerPage)
49+
];
50+
51+
mysqli_close($conn);
52+
53+
// Output the JSON response
54+
header('Content-Type: application/json; charset=utf-8');
55+
echo json_encode($rows, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT);
56+
return;
57+
58+
?>

api-functions/formulas_get.php

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
if (!defined('pvault_panel')){ die('Not Found');}
3+
global $conn;
4+
5+
if ($fid = mysqli_real_escape_string($conn, $_REQUEST['fid'])) {
6+
$sql = mysqli_query($conn, "SELECT id, fid, name, product_name, notes, finalType AS concentration, status, created_at, isProtected, rating, profile, src, customer_id, revision, madeOn FROM formulasMetaData WHERE fid = '$fid'");
7+
} else {
8+
$sql = mysqli_query($conn, "SELECT id, fid, name, product_name, notes, finalType AS concentration, status, created_at, isProtected, rating, profile, src, customer_id, revision, madeOn FROM formulasMetaData");
9+
}
10+
11+
$rows = ["formulas" => []];
12+
13+
if ($sql && mysqli_num_rows($sql) > 0) {
14+
while ($r = mysqli_fetch_assoc($sql)) {
15+
$C = date_format(date_create($r['created_at']), "Y-m-d H:i:s");
16+
$I = mysqli_fetch_array(mysqli_query($conn, "SELECT docData FROM documents WHERE ownerID = '" . $r['id'] . "' AND type = '2'"));
17+
$sql_ing = mysqli_query($conn, "SELECT ingredient AS name, fid, ingredient, concentration, dilutant, quantity, notes FROM formulas WHERE fid = '" . $r['fid'] . "'");
18+
19+
$formula = [
20+
'fid' => (string)$r['fid'],
21+
'name' => (string)$r['name'],
22+
'product_name' => (string)$r['product_name'] ?: "Not Set",
23+
'notes' => (string)$r['notes'] ?: "-",
24+
'concentration' => (int)$r['concentration'] ?: 100,
25+
'status' => (int)$r['status'] ?: 0,
26+
'created_at' => (string)$C ?: "-",
27+
'isProtected' => (int)$r['isProtected'] ?: 0,
28+
'rating' => (int)$r['rating'] ?: 0,
29+
'profile' => (string)$r['profile'] ?: "Default",
30+
'src' => (int)$r['src'] ?: 0,
31+
'customer_id' => (int)$r['customer_id'] ?: 0,
32+
'revision' => (int)$r['revision'] ?: 0,
33+
'madeOn' => (string)$r['madeOn'] ?: "-",
34+
'image' => (string)$I['docData'] ?: $defImage,
35+
'ingredients' => []
36+
];
37+
38+
if ($sql_ing && mysqli_num_rows($sql_ing) > 0) {
39+
while ($i = mysqli_fetch_assoc($sql_ing)) {
40+
$ingredient = [
41+
'fid' => (string)$i['fid'],
42+
'ingredient' => (string)$i['ingredient'],
43+
'concentration' => (float)$i['concentration'] ?: 100,
44+
'quantity' => (float)$i['quantity'] ?: 0,
45+
'notes' => (string)$i['notes'] ?: '-'
46+
];
47+
48+
$formula['ingredients'][] = $ingredient;
49+
}
50+
}
51+
52+
$rows['formulas'][] = $formula;
53+
}
54+
}
55+
56+
header('Content-Type: application/json; charset=utf-8');
57+
echo json_encode($rows, JSON_PRETTY_PRINT);
58+
59+
?>

api-functions/formulas_upload.php

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
if (!defined('pvault_panel')){ die('Not Found');}
3+
global $conn;
4+
5+
$json = file_get_contents('php://input');
6+
$data = json_decode($json, true);
7+
8+
if (!$data || !is_array($data)) {
9+
http_response_code(400);
10+
echo json_encode(['error' => 'Invalid JSON data']);
11+
return;
12+
}
13+
14+
if (empty($data['formulas']) || !is_array($data['formulas'])) {
15+
http_response_code(400);
16+
echo json_encode(['error' => 'Missing or invalid formulas array']);
17+
return;
18+
}
19+
20+
foreach ($data['formulas'] as $row) {
21+
// Parse formula metadata
22+
$fid = mysqli_real_escape_string($conn, $row['fid']);
23+
$name = mysqli_real_escape_string($conn, $row['name']);
24+
$product_name = mysqli_real_escape_string($conn, $row['product_name'] ?? '-');
25+
$notes = mysqli_real_escape_string($conn, $row['notes'] ?? '-');
26+
$concentration = (int)($row['concentration'] ?? 100);
27+
$status = (int)($row['status'] ?? 0);
28+
$isProtected = (int)($row['isProtected'] ?? 0);
29+
$rating = (int)($row['rating'] ?? 0);
30+
$profile = mysqli_real_escape_string($conn, $row['profile'] ?? 'Default');
31+
$src = (int)($row['src'] ?? 0);
32+
$customer_id = (int)($row['customer_id'] ?? 0);
33+
$revision = (int)($row['revision'] ?? 0);
34+
$madeOn = mysqli_real_escape_string($conn, $row['madeOn'] ?? date('Y-m-d H:i:s'));
35+
36+
$query = "INSERT INTO formulasMetaData (fid, name, product_name, notes, finalType, status, isProtected, rating, profile, src, customer_id, revision, madeOn)
37+
VALUES ('$fid', '$name', '$product_name', '$notes', '$concentration', '$status', '$isProtected', '$rating', '$profile', '$src', '$customer_id', '$revision', '$madeOn')";
38+
39+
if (!mysqli_query($conn, $query)) {
40+
error_log(mysqli_error($conn));
41+
echo json_encode(['error' => 'Failed to insert formula', 'details' => mysqli_error($conn)]);
42+
return;
43+
}
44+
45+
// Parse associated ingredients
46+
if (!empty($row['ingredients']) && is_array($row['ingredients'])) {
47+
foreach ($row['ingredients'] as $ingredient) {
48+
$ingredient_fid = mysqli_real_escape_string($conn, $ingredient['fid']);
49+
$ingredient_name = mysqli_real_escape_string($conn, $ingredient['ingredient']);
50+
$ingredient_concentration = (float)($ingredient['concentration'] ?? 100);
51+
$ingredient_quantity = (float)($ingredient['quantity'] ?? 0);
52+
$ingredient_dilutant = mysqli_real_escape_string($conn, $ingredient['dilutant']);
53+
54+
$ingredient_query = "INSERT INTO formulas (fid, name, ingredient, concentration, dilutant, quantity, notes)
55+
VALUES ('$ingredient_fid', '$name', '$ingredient_name', '$ingredient_concentration', '$ingredient_dilutant', '$ingredient_quantity', '-')";
56+
57+
if (!mysqli_query($conn, $ingredient_query)) {
58+
error_log(mysqli_error($conn));
59+
echo json_encode(['error' => 'Failed to insert ingredient', 'details' => mysqli_error($conn)]);
60+
}
61+
}
62+
}
63+
}
64+
65+
echo json_encode(['success' => 'Data inserted successfully']);
66+
67+
?>
68+
69+

0 commit comments

Comments
 (0)