feat: Enhance FaceAI functionality with storage management and update deployment instructions
All checks were successful
Publish FaceAI Container / publish (push) Successful in 5m45s
All checks were successful
Publish FaceAI Container / publish (push) Successful in 5m45s
This commit is contained in:
parent
c0d072c6ea
commit
23f811e465
14 changed files with 500 additions and 22 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue