feat: Enhance FaceAI functionality with storage management and update deployment instructions
All checks were successful
Publish FaceAI Container / publish (push) Successful in 5m45s

This commit is contained in:
MaddoScientisto 2026-04-20 19:29:22 +02:00
commit 23f811e465
14 changed files with 500 additions and 22 deletions

View file

@ -43,7 +43,7 @@
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/popper/popper.min.js"></script>
<script src="admin/_V4/_js/_acxent.js"></script>
<script src="_js/rus-ecom-240621.js"></script>
<script src="_js/rus-ecom-240621.js?v=20260420-faceai-2"></script>
<script src="addons/datepicker/js/bootstrap-datepicker.min.js"></script>
<script src="addons/datepicker/locales/bootstrap-datepicker.it.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.min.js"></script>

View file

@ -21,7 +21,7 @@
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/popper/popper.min.js"></script>
<script src="admin/_V4/_js/_acxent.js"></script>
<script src="_js/rus-ecom-240621.js"></script>
<script src="_js/rus-ecom-240621.js?v=20260420-faceai-2"></script>
<script src="addons/datepicker/js/bootstrap-datepicker.min.js"></script>
<script src="addons/datepicker/locales/bootstrap-datepicker.it.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.min.js"></script>

View file

@ -21,7 +21,7 @@
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/popper/popper.min.js"></script>
<script src="admin/_V4/_js/_acxent.js"></script>
<script src="_js/rus-ecom-240621.js"></script>
<script src="_js/rus-ecom-240621.js?v=20260420-faceai-2"></script>
<script src="addons/datepicker/js/bootstrap-datepicker.min.js"></script>
<script src="addons/datepicker/locales/bootstrap-datepicker.it.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.min.js"></script>

View file

@ -27,7 +27,7 @@
<script src="vendor/popper/popper.min.js"></script>
<script src="admin/_V4/_js/_acxent.js"></script>
<script src="_js/rus-ecom-240621.js"></script>
<script src="_js/rus-ecom-240621.js?v=20260420-faceai-2"></script>
<script src="addons/datepicker/js/bootstrap-datepicker.min.js"></script>
<script src="addons/datepicker/locales/bootstrap-datepicker.it.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.min.js"></script>

View file

@ -29,7 +29,7 @@
<script src="vendor/popper/popper.min.js"></script>
<script src="admin/_V4/_js/_acxent.js"></script>
<script src="_js/rus-ecom-240621.js"></script>
<script src="_js/rus-ecom-240621.js?v=20260420-faceai-2"></script>
<script src="addons/datepicker/js/bootstrap-datepicker.min.js"></script>
<script src="addons/datepicker/locales/bootstrap-datepicker.it.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.min.js"></script>

View file

@ -228,6 +228,197 @@ function clearFaceAiErrorState() {
window.history.replaceState({}, document.title, cleanUrl.pathname + cleanUrl.search + cleanUrl.hash);
}
function getFaceAiMatchStorageEntryKey(storageKey) {
return "faceai-match-state:" + String(storageKey || "").trim();
}
function getFaceAiPendingMatchEntryKey() {
return "faceai-pending-match-state";
}
function getFaceAiPathForComparison(value) {
if (!value) {
return "";
}
try {
return decodeURIComponent(String(value));
} catch (error) {
return String(value);
}
}
function getFaceAiCurrentRaceId() {
return String($("#id_gara").val() || "").trim();
}
function isFaceAiStoredPayloadFresh(storedAt, maxAgeMs) {
var timestamp = Date.parse(String(storedAt || ""));
if (!timestamp) {
return false;
}
return (Date.now() - timestamp) <= maxAgeMs;
}
function canUseFaceAiWebStorage(storage) {
var testKey = "__faceai_storage_test__";
if (!storage) {
return false;
}
try {
storage.setItem(testKey, "1");
storage.removeItem(testKey);
return true;
} catch (error) {
return false;
}
}
function readFaceAiStoredMatchPayload(storageKey) {
var entryKey = getFaceAiMatchStorageEntryKey(storageKey);
var rawPayload = "";
var windowNamePayload;
if (!storageKey) {
return null;
}
if (canUseFaceAiWebStorage(window.sessionStorage)) {
rawPayload = window.sessionStorage.getItem(entryKey) || "";
}
if (!rawPayload && canUseFaceAiWebStorage(window.localStorage)) {
rawPayload = window.localStorage.getItem(entryKey) || "";
}
if (!rawPayload && window.name) {
try {
windowNamePayload = JSON.parse(window.name);
if (windowNamePayload && windowNamePayload.faceAiStorageKey === storageKey && windowNamePayload.faceAiMatchState) {
rawPayload = JSON.stringify(windowNamePayload.faceAiMatchState);
}
} catch (error) {
rawPayload = "";
}
}
if (!rawPayload) {
return null;
}
try {
return JSON.parse(rawPayload);
} catch (error) {
return null;
}
}
function readFaceAiPendingMatchPayload() {
var entryKey = getFaceAiPendingMatchEntryKey();
var rawPayload = "";
var parsedPayload = null;
var windowNamePayload;
var currentPath = getFaceAiPathForComparison(window.location.pathname || "");
var currentRaceId = getFaceAiCurrentRaceId();
if (canUseFaceAiWebStorage(window.sessionStorage)) {
rawPayload = window.sessionStorage.getItem(entryKey) || "";
}
if (!rawPayload && canUseFaceAiWebStorage(window.localStorage)) {
rawPayload = window.localStorage.getItem(entryKey) || "";
}
if (!rawPayload && window.name) {
try {
windowNamePayload = JSON.parse(window.name);
if (windowNamePayload && windowNamePayload.faceAiPendingMatchState) {
rawPayload = JSON.stringify(windowNamePayload.faceAiPendingMatchState);
}
} catch (error) {
rawPayload = "";
}
}
if (!rawPayload) {
return null;
}
try {
parsedPayload = JSON.parse(rawPayload);
} catch (error) {
return null;
}
if (!parsedPayload || !parsedPayload.payload || !parsedPayload.payload.photoIds || !parsedPayload.payload.photoIds.length) {
return null;
}
if (!isFaceAiStoredPayloadFresh(parsedPayload.payload.storedAt, 15 * 60 * 1000)) {
return null;
}
if (String(parsedPayload.raceId || "").trim() && currentRaceId && String(parsedPayload.raceId || "").trim() !== currentRaceId) {
return null;
}
if (!String(parsedPayload.raceId || "").trim() && getFaceAiPathForComparison(parsedPayload.targetPath || "") !== currentPath) {
return null;
}
return parsedPayload;
}
function clearFaceAiStoredMatchPayload(storageKey) {
var entryKey = getFaceAiMatchStorageEntryKey(storageKey);
var pendingEntryKey = getFaceAiPendingMatchEntryKey();
var windowNamePayload;
var pendingPayload = readFaceAiPendingMatchPayload();
if (!storageKey) {
return;
}
if (canUseFaceAiWebStorage(window.sessionStorage)) {
window.sessionStorage.removeItem(entryKey);
}
if (canUseFaceAiWebStorage(window.localStorage)) {
window.localStorage.removeItem(entryKey);
if (pendingPayload && pendingPayload.storageKey === storageKey) {
window.localStorage.removeItem(pendingEntryKey);
}
}
if (canUseFaceAiWebStorage(window.sessionStorage) && pendingPayload && pendingPayload.storageKey === storageKey) {
window.sessionStorage.removeItem(pendingEntryKey);
}
if (!window.name) {
return;
}
try {
windowNamePayload = JSON.parse(window.name);
if (windowNamePayload && windowNamePayload.faceAiStorageKey === storageKey) {
delete windowNamePayload.faceAiStorageKey;
delete windowNamePayload.faceAiMatchState;
}
if (windowNamePayload && windowNamePayload.faceAiPendingMatchState && windowNamePayload.faceAiPendingMatchState.storageKey === storageKey) {
delete windowNamePayload.faceAiPendingMatchState;
}
if (!windowNamePayload || !Object.keys(windowNamePayload).length) {
window.name = "";
} else {
window.name = JSON.stringify(windowNamePayload);
}
} catch (error) {}
}
function showFaceAiErrorModal(title, message) {
var modal = $("#faceAiErrorModal");
@ -266,6 +457,7 @@ function stripFaceAiStateFromUrl(url) {
cleanUrl.searchParams.delete("faceaiMatchSource");
cleanUrl.searchParams.delete("faceaiMatchCount");
cleanUrl.searchParams.delete("faceaiPhotoIds");
cleanUrl.searchParams.delete("faceaiMatchStorageKey");
return cleanUrl.toString();
} catch (error) {
return url || fallbackUrl;
@ -279,6 +471,26 @@ function getFaceAiMatchState() {
var params = new URLSearchParams(window.location.search || "");
var rawIds = params.get("faceaiPhotoIds") || "";
var storageKey = String(params.get("faceaiMatchStorageKey") || "").trim();
var storedPayload = null;
var pendingPayload = null;
if (!rawIds && storageKey) {
storedPayload = readFaceAiStoredMatchPayload(storageKey);
if (storedPayload && storedPayload.photoIds && storedPayload.photoIds.length) {
rawIds = storedPayload.photoIds.join(",");
}
}
if (!rawIds) {
pendingPayload = readFaceAiPendingMatchPayload();
if (pendingPayload && pendingPayload.payload && pendingPayload.payload.photoIds && pendingPayload.payload.photoIds.length) {
rawIds = pendingPayload.payload.photoIds.join(",");
storageKey = storageKey || String(pendingPayload.storageKey || "").trim();
storedPayload = storedPayload || pendingPayload.payload;
}
}
if (!rawIds) {
return null;
}
@ -303,7 +515,8 @@ function getFaceAiMatchState() {
return {
photoIds: photoIds,
photoIdSet: photoIdSet,
matchCount: isNaN(parsedCount) ? photoIds.length : parsedCount,
matchCount: isNaN(parsedCount) ? ((storedPayload && storedPayload.matchCount) ? storedPayload.matchCount : photoIds.length) : parsedCount,
storageKey: storageKey,
clearUrl: stripFaceAiStateFromUrl(window.location.href)
};
}
@ -499,12 +712,17 @@ function renderFaceAiLegacyBanner(state) {
}
banner = $("#faceAiFilterBanner");
$(document).off("click.faceAiClearFilter", "#faceAiClearFilterButton");
$(document).on("click.faceAiClearFilter", "#faceAiClearFilterButton", function() {
window.location.href = state.clearUrl;
});
}
$(document).off("click.faceAiClearFilter", "#faceAiClearFilterButton");
$(document).on("click.faceAiClearFilter", "#faceAiClearFilterButton", function() {
var activeState = window.faceAiMatchState || state;
if (activeState && activeState.storageKey) {
clearFaceAiStoredMatchPayload(activeState.storageKey);
}
window.location.href = activeState && activeState.clearUrl ? activeState.clearUrl : state.clearUrl;
});
$("#faceAiFilterBannerTitle").text(copy.bannerTitle);
$("#faceAiFilterBannerText").html(message);
$("#faceAiClearFilterButton").text(copy.clearText);

View file

@ -233,6 +233,63 @@ function faceai_render_message_page($title, $message, array $details = array(),
exit;
}
function faceai_render_storage_redirect_page($targetUrl, $storageKey, array $photoIds, $matchCount, $raceId = '')
{
http_response_code(200);
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Content-Type: text/html; charset=UTF-8');
$payload = array(
'photoIds' => array_values($photoIds),
'matchCount' => (int) $matchCount,
'storedAt' => gmdate('c')
);
$pendingPayload = array(
'storageKey' => (string) $storageKey,
'raceId' => trim((string) $raceId),
'targetPath' => (string) (parse_url((string) $targetUrl, PHP_URL_PATH) ?: ''),
'payload' => $payload
);
echo '<!doctype html><html lang="it"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">';
echo '<title>FaceAI redirect</title>';
echo '<style>body{font-family:Georgia,serif;background:#f7f1e8;color:#2a231b;margin:0;padding:32px}main{max-width:900px;margin:0 auto;background:#fff;border:1px solid #ddcbb5;padding:24px}p{margin:0 0 12px}</style>';
echo '</head><body><main><h1>Reindirizzamento FaceAI in corso</h1><p>Sto preparando i risultati e torno alla galleria della gara.</p><noscript><p>JavaScript e richiesto per completare il reindirizzamento FaceAI.</p></noscript>';
echo '<script>';
echo '(function () {';
echo 'var targetUrl = ' . json_encode((string) $targetUrl) . ';';
echo 'var storageKey = ' . json_encode((string) $storageKey) . ';';
echo 'var payload = ' . json_encode($payload) . ';';
echo 'var pendingPayload = ' . json_encode($pendingPayload) . ';';
echo 'var entryKey = "faceai-match-state:" + storageKey;';
echo 'var pendingEntryKey = "faceai-pending-match-state";';
echo 'var stored = false;';
echo 'function persist(storageName, key, value) {';
echo ' try {';
echo ' var storage = window[storageName];';
echo ' if (!storage) { return false; }';
echo ' storage.setItem(key, JSON.stringify(value));';
echo ' return storage.getItem(key) !== null;';
echo ' } catch (error) {';
echo ' return false;';
echo ' }';
echo '}';
echo 'stored = persist("sessionStorage", entryKey, payload) || persist("localStorage", entryKey, payload);';
echo 'stored = persist("sessionStorage", pendingEntryKey, pendingPayload) || persist("localStorage", pendingEntryKey, pendingPayload) || stored;';
echo 'try {';
echo ' window.name = JSON.stringify({ faceAiStorageKey: storageKey, faceAiMatchState: payload, faceAiPendingMatchState: pendingPayload });';
echo '} catch (error) {}';
echo 'if (!stored && !window.name) {';
echo ' document.body.innerHTML = "<main><h1>FaceAI non disponibile</h1><p>Il browser non permette di trasferire i risultati FaceAI verso la galleria.</p></main>";';
echo ' return;';
echo '}';
echo 'window.location.replace(targetUrl);';
echo '}());';
echo '</script></main></body></html>';
exit;
}
function faceai_fetch_json($url)
{
$context = stream_context_create(array(

View file

@ -54,12 +54,23 @@ try {
$photoIds[$photoId] = true;
}
header('Location: ' . faceai_build_url($returnUrl, array(
$matchCount = count($photoIds);
if ($matchCount === 0) {
header('Location: ' . faceai_build_url($returnUrl, array(
'faceaiMatchSource' => 'faceai',
'faceaiMatchCount' => 0
)), true, 302);
exit;
}
$storageKey = 'faceai-result-' . preg_replace('/[^a-zA-Z0-9_-]/', '', $resultId);
$redirectUrl = faceai_build_url($returnUrl, array(
'faceaiMatchSource' => 'faceai',
'faceaiMatchCount' => count($photoIds),
'faceaiPhotoIds' => implode(',', array_keys($photoIds))
)), true, 302);
exit;
'faceaiMatchCount' => $matchCount,
'faceaiMatchStorageKey' => $storageKey
));
faceai_render_storage_redirect_page($redirectUrl, $storageKey, array_keys($photoIds), $matchCount, (string) ($result['raceId'] ?? ($payload['raceId'] ?? '')));
} catch (Throwable $error) {
faceai_render_message_page('Errore return FaceAI', $error->getMessage(), array(), 500);
}

View file

@ -235,7 +235,7 @@ window.faceAiSimulator = {
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/popper/popper.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.min.js"></script>
<script src="_js/rus-ecom-240621.js"></script>
<script src="_js/rus-ecom-240621.js?v=20260420-faceai-2"></script>
</body>
</html>
<?php