feat: Enhance FaceAI functionality and improve login process
All checks were successful
Publish FaceAI Container / publish (push) Successful in 4m43s
All checks were successful
Publish FaceAI Container / publish (push) Successful in 4m43s
- Added a retry mechanism for page navigation in `live-site-test-utils.js` to handle transient errors during login. - Introduced a new function `performLiveLoginRequest` to handle login requests via API, improving the login flow. - Updated the login process to utilize the new API request method, ensuring a more robust authentication. - Implemented new utility functions in `rus-ecom-240621.js` for managing FaceAI state and filtering. - Created `faceai_photo_lookup.jsp` to handle photo lookups, returning JSON responses for better integration with the frontend. - Updated `faceai_return.php` to redirect users with appropriate parameters after FaceAI processing. - Modified `fotoCR.jsp` and `fotoCR-en.jsp` to include FaceAI photo IDs in the image elements for better tracking. - Enhanced the UI to display the number of matched photos dynamically based on FaceAI results.
This commit is contained in:
parent
6f191de115
commit
bba8026b7c
17 changed files with 1077 additions and 95 deletions
|
|
@ -251,6 +251,439 @@ function initFaceAiErrorModal() {
|
|||
clearFaceAiErrorState();
|
||||
}
|
||||
|
||||
function stripFaceAiStateFromUrl(url) {
|
||||
var fallbackUrl = window.location.href;
|
||||
|
||||
if (typeof URL === "undefined") {
|
||||
return url || fallbackUrl;
|
||||
}
|
||||
|
||||
try {
|
||||
var cleanUrl = new URL(url || fallbackUrl, window.location.href);
|
||||
cleanUrl.searchParams.delete("faceaiError");
|
||||
cleanUrl.searchParams.delete("faceaiErrorTitle");
|
||||
cleanUrl.searchParams.delete("faceaiErrorMessage");
|
||||
cleanUrl.searchParams.delete("faceaiMatchSource");
|
||||
cleanUrl.searchParams.delete("faceaiMatchCount");
|
||||
cleanUrl.searchParams.delete("faceaiPhotoIds");
|
||||
return cleanUrl.toString();
|
||||
} catch (error) {
|
||||
return url || fallbackUrl;
|
||||
}
|
||||
}
|
||||
|
||||
function getFaceAiMatchState() {
|
||||
if (typeof URLSearchParams === "undefined") {
|
||||
return null;
|
||||
}
|
||||
|
||||
var params = new URLSearchParams(window.location.search || "");
|
||||
var rawIds = params.get("faceaiPhotoIds") || "";
|
||||
if (!rawIds) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var photoIds = rawIds.split(",").map(function(value) {
|
||||
return String(value || "").trim();
|
||||
}).filter(function(value) {
|
||||
return value.length > 0;
|
||||
});
|
||||
|
||||
if (!photoIds.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var photoIdSet = {};
|
||||
for (var index = 0; index < photoIds.length; index += 1) {
|
||||
photoIdSet[photoIds[index]] = true;
|
||||
}
|
||||
|
||||
var parsedCount = parseInt(params.get("faceaiMatchCount"), 10);
|
||||
|
||||
return {
|
||||
photoIds: photoIds,
|
||||
photoIdSet: photoIdSet,
|
||||
matchCount: isNaN(parsedCount) ? photoIds.length : parsedCount,
|
||||
clearUrl: stripFaceAiStateFromUrl(window.location.href)
|
||||
};
|
||||
}
|
||||
|
||||
function getFaceAiFilterCopy() {
|
||||
var lang = String(getCurrentLangValue() || "it").toLowerCase();
|
||||
if (lang.indexOf("en") === 0) {
|
||||
return {
|
||||
bannerTitle: "Face ID filter active",
|
||||
bannerText: "Showing <strong>{count}</strong> matched photos on the normal race page.",
|
||||
clearText: "Show all race photos",
|
||||
emptyText: "No matched FaceAI photos are available in this current race view."
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
bannerTitle: "Filtro Face ID attivo",
|
||||
bannerText: "Mostro <strong>{count}</strong> foto corrispondenti nella normale pagina gara.",
|
||||
clearText: "Mostra tutte le foto della gara",
|
||||
emptyText: "Nessuna foto FaceAI corrispondente e disponibile in questa vista della gara."
|
||||
};
|
||||
}
|
||||
|
||||
function updateFaceAiLegacyCount(visibleCount) {
|
||||
var countValue = $("#faceAiPhotoCountValue");
|
||||
if (!countValue.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
countValue.text(String(visibleCount));
|
||||
}
|
||||
|
||||
function escapeFaceAiAttribute(value) {
|
||||
return String(value || "").replace(/&/g, "&").replace(/"/g, """);
|
||||
}
|
||||
|
||||
function isFaceAiNumericPhotoId(value) {
|
||||
return /^\d+$/.test(String(value || "").trim());
|
||||
}
|
||||
|
||||
function getFaceAiLookupEndpoint() {
|
||||
return "faceai_photo_lookup.jsp";
|
||||
}
|
||||
|
||||
function getFaceAiGalleryLayoutOptions() {
|
||||
var config = window.faceAiConfig || {};
|
||||
if (config.galleryMode === "compact") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
rowHeight: 150,
|
||||
margins: 8
|
||||
};
|
||||
}
|
||||
|
||||
function refreshFaceAiLegacyGalleryLayout(gallery) {
|
||||
var options;
|
||||
|
||||
if (!gallery || !gallery.length || typeof $.fn.justifiedGallery !== "function") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gallery.data("jg.controller")) {
|
||||
gallery.justifiedGallery("destroy");
|
||||
}
|
||||
|
||||
options = getFaceAiGalleryLayoutOptions();
|
||||
if (options) {
|
||||
gallery.justifiedGallery(options);
|
||||
return;
|
||||
}
|
||||
|
||||
gallery.justifiedGallery();
|
||||
gallery.justifiedGallery("norewind");
|
||||
return;
|
||||
}
|
||||
|
||||
function normalizeFaceAiLookupToken(value) {
|
||||
return String(value || "")
|
||||
.toUpperCase()
|
||||
.replace(/\\+/g, "/")
|
||||
.replace(/\s+/g, "_")
|
||||
.replace(/[^A-Z0-9._/-]+/g, "")
|
||||
.replace(/^_+|_+$/g, "");
|
||||
}
|
||||
|
||||
function collectFaceAiCheckpointTokens(value) {
|
||||
var normalized = normalizeFaceAiLookupToken(value);
|
||||
var tokens = {};
|
||||
var current = normalized;
|
||||
|
||||
while (current) {
|
||||
tokens[current] = true;
|
||||
current = current.replace(/^\d+\./, "");
|
||||
if (tokens[current]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current = normalized.replace(/^\d+\./, "");
|
||||
while (current) {
|
||||
tokens[current] = true;
|
||||
if (current.indexOf("_") === -1) {
|
||||
break;
|
||||
}
|
||||
current = current.replace(/_[^_]+$/, "");
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
function findFaceAiPointIdsForCheckpoint(checkpointLabel) {
|
||||
var field = $("#id_puntoFoto");
|
||||
var lookupTokens = collectFaceAiCheckpointTokens(checkpointLabel);
|
||||
var ids = [];
|
||||
|
||||
if (!field.length || !Object.keys(lookupTokens).length) {
|
||||
return ids;
|
||||
}
|
||||
|
||||
field.find("option").each(function() {
|
||||
var option = $(this);
|
||||
var value = String(option.val() || "").trim();
|
||||
var optionTokens;
|
||||
var token;
|
||||
|
||||
if (!/^\d+$/.test(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
optionTokens = collectFaceAiCheckpointTokens(option.text());
|
||||
for (token in optionTokens) {
|
||||
if (optionTokens.hasOwnProperty(token) && lookupTokens[token]) {
|
||||
ids.push(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
function getFaceAiPhotoLookupData(photoKey) {
|
||||
var value = String(photoKey || "").trim();
|
||||
var normalizedPath = value.replace(/\\+/g, "/");
|
||||
var segments = normalizedPath.split("/");
|
||||
var fileName = segments.length ? String(segments[segments.length - 1] || "").trim() : "";
|
||||
var checkpointLabel = segments.length > 1 ? String(segments[0] || "").trim() : "";
|
||||
var raceId = String($("#id_gara").val() || "").trim();
|
||||
var puntoFotoIds = checkpointLabel ? findFaceAiPointIdsForCheckpoint(checkpointLabel) : [];
|
||||
|
||||
return {
|
||||
photoKey: value,
|
||||
request: {
|
||||
photoId: value,
|
||||
normalizedPhotoId: normalizedPath,
|
||||
fileName: fileName,
|
||||
raceId: raceId,
|
||||
checkpointLabel: checkpointLabel,
|
||||
puntoFotoIds: puntoFotoIds.join(",")
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function hideFaceAiLegacyPagination() {
|
||||
$("nav[aria-label='paginatore']").hide();
|
||||
$("#pageRow").closest(".col-md-3").hide();
|
||||
}
|
||||
|
||||
function renderFaceAiLegacyBanner(state) {
|
||||
var copy = getFaceAiFilterCopy();
|
||||
var banner = $("#faceAiFilterBanner");
|
||||
var message = copy.bannerText.replace("{count}", String(state.visibleCount));
|
||||
|
||||
if (!banner.length) {
|
||||
var bannerHtml = ''
|
||||
+ '<div class="col-12" id="faceAiFilterBannerWrap">'
|
||||
+ '<div id="faceAiFilterBanner" class="alert alert-warning d-flex flex-column flex-md-row justify-content-between align-items-md-center mb-3" role="status">'
|
||||
+ '<div class="mb-2 mb-md-0">'
|
||||
+ '<strong id="faceAiFilterBannerTitle"></strong> '
|
||||
+ '<span id="faceAiFilterBannerText"></span>'
|
||||
+ '</div>'
|
||||
+ '<button type="button" id="faceAiClearFilterButton" class="btn btn-sm btn-outline-dark"></button>'
|
||||
+ '</div>'
|
||||
+ '</div>';
|
||||
|
||||
var insertTarget = $("#faceAiResultsSummary").closest(".col-md-4").parent();
|
||||
if (insertTarget.length) {
|
||||
insertTarget.before(bannerHtml);
|
||||
} else {
|
||||
$(".container.my-3 .row.mb-5").first().prepend(bannerHtml);
|
||||
}
|
||||
|
||||
banner = $("#faceAiFilterBanner");
|
||||
$(document).off("click.faceAiClearFilter", "#faceAiClearFilterButton");
|
||||
$(document).on("click.faceAiClearFilter", "#faceAiClearFilterButton", function() {
|
||||
window.location.href = state.clearUrl;
|
||||
});
|
||||
}
|
||||
|
||||
$("#faceAiFilterBannerTitle").text(copy.bannerTitle);
|
||||
$("#faceAiFilterBannerText").html(message);
|
||||
$("#faceAiClearFilterButton").text(copy.clearText);
|
||||
$("#faceAiEmptyResultsMessage").remove();
|
||||
|
||||
if (state.visibleCount > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var emptyMessage = '<div class="col-12" id="faceAiEmptyResultsMessage"><div class="alert alert-light border mb-3">' + faceAiEscapeHtml(copy.emptyText) + '</div></div>';
|
||||
var gallery = $("#demo");
|
||||
if (gallery.length) {
|
||||
gallery.closest(".col-md-10").before(emptyMessage);
|
||||
}
|
||||
}
|
||||
|
||||
function buildFaceAiLegacyPhotoCard(photoKey, legacyId, imageSrc) {
|
||||
var safePhotoKey = escapeFaceAiAttribute(photoKey);
|
||||
var safeLegacyId = escapeFaceAiAttribute(legacyId);
|
||||
var safeImageSrc = escapeFaceAiAttribute(imageSrc);
|
||||
var captionLabel = String(getCurrentLangValue() || "it").toLowerCase().indexOf("en") === 0 ? "Photo ID" : "ID foto";
|
||||
|
||||
return $(
|
||||
'<a href="javascript:mostraFoto(' + safeLegacyId + ')" data-faceai-photo-id="' + safePhotoKey + '" data-faceai-legacy-id="' + safeLegacyId + '">' +
|
||||
'<img src="' + safeImageSrc + '" alt="" class="thumb" />' +
|
||||
'<div class="caption">' + captionLabel + ': ' + faceAiEscapeHtml(photoKey) + '</div>' +
|
||||
'</a>'
|
||||
);
|
||||
}
|
||||
|
||||
function extractFaceAiImageSrc(htmlPayload) {
|
||||
var parsedNodes = $.parseHTML(htmlPayload || "", document, true) || [];
|
||||
var wrapper = $("<div></div>").append(parsedNodes);
|
||||
var image = wrapper.find("img").first();
|
||||
if (!image.length) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return image.attr("src") || "";
|
||||
}
|
||||
|
||||
function fetchFaceAiLegacyPhotoCard(photoKey) {
|
||||
var lookupData = getFaceAiPhotoLookupData(photoKey);
|
||||
|
||||
return $.getJSON(getFaceAiLookupEndpoint(), lookupData.request).then(function(payload) {
|
||||
if (!payload || !payload.found || !payload.legacyId || !payload.thumbSrc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return buildFaceAiLegacyPhotoCard(payload.photoId || lookupData.photoKey, payload.legacyId, payload.thumbSrc);
|
||||
}, function() {
|
||||
if (!isFaceAiNumericPhotoId(photoKey)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $.get("Foto2.abl?cmd=mostraFoto&id_foto=" + encodeURIComponent(photoKey)).then(function(htmlPayload) {
|
||||
var imageSrc = extractFaceAiImageSrc(htmlPayload);
|
||||
if (!imageSrc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return buildFaceAiLegacyPhotoCard(photoKey, photoKey, imageSrc);
|
||||
}, function() {
|
||||
return null;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function cloneFaceAiExistingPhotoCard(item) {
|
||||
if (!item || !item.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var clone = item.clone(true, true);
|
||||
clone.attr("data-faceai-photo-id", item.attr("data-faceai-photo-id") || "");
|
||||
clone.attr("data-faceai-legacy-id", item.attr("data-faceai-legacy-id") || "");
|
||||
return clone;
|
||||
}
|
||||
|
||||
function collectFaceAiExistingPhotoCards(gallery, matchState) {
|
||||
var cardsById = {};
|
||||
|
||||
gallery.find("[data-faceai-photo-id]").each(function() {
|
||||
var item = $(this);
|
||||
var photoId = String(item.attr("data-faceai-photo-id") || "").trim();
|
||||
if (!photoId || !matchState.photoIdSet[photoId] || cardsById[photoId]) {
|
||||
return;
|
||||
}
|
||||
|
||||
cardsById[photoId] = cloneFaceAiExistingPhotoCard(item);
|
||||
});
|
||||
|
||||
return cardsById;
|
||||
}
|
||||
|
||||
function finalizeFaceAiLegacyGallery(gallery, matchState, cards) {
|
||||
var visibleCards = [];
|
||||
var index;
|
||||
var activeRequestId = window.faceAiLegacyGalleryRequestId || 0;
|
||||
|
||||
if (matchState.requestId !== activeRequestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
gallery.empty();
|
||||
for (index = 0; index < cards.length; index += 1) {
|
||||
if (!cards[index] || !cards[index].length) {
|
||||
continue;
|
||||
}
|
||||
visibleCards.push(cards[index]);
|
||||
gallery.append(cards[index]);
|
||||
}
|
||||
|
||||
matchState.visibleCount = visibleCards.length;
|
||||
window.faceAiMatchState = matchState;
|
||||
updateFaceAiLegacyCount(matchState.visibleCount);
|
||||
renderFaceAiLegacyBanner(matchState);
|
||||
refreshFaceAiLegacyGalleryLayout(gallery);
|
||||
|
||||
$(document).trigger("faceai:gallery-ready", [matchState]);
|
||||
|
||||
logFaceAiDebug("Applied legacy FaceAI filter", {
|
||||
matchCount: matchState.matchCount,
|
||||
visibleCount: matchState.visibleCount,
|
||||
photoIds: matchState.photoIds
|
||||
});
|
||||
}
|
||||
|
||||
function loadFaceAiLegacyGallery(gallery, matchState) {
|
||||
var existingCards = collectFaceAiExistingPhotoCards(gallery, matchState);
|
||||
var orderedCards = [];
|
||||
var index;
|
||||
|
||||
updateFaceAiLegacyCount(0);
|
||||
gallery.empty().append('<div class="faceai-loading text-center w-100 py-4">FaceAI loading...</div>');
|
||||
|
||||
for (index = 0; index < matchState.photoIds.length; index += 1) {
|
||||
(function(photoId) {
|
||||
if (existingCards[photoId]) {
|
||||
orderedCards.push($.Deferred().resolve(existingCards[photoId]).promise());
|
||||
return;
|
||||
}
|
||||
|
||||
orderedCards.push(fetchFaceAiLegacyPhotoCard(photoId));
|
||||
}(matchState.photoIds[index]));
|
||||
}
|
||||
|
||||
$.when.apply($, orderedCards).then(function() {
|
||||
var resolvedCards = orderedCards.length === 1 ? [arguments[0]] : Array.prototype.slice.call(arguments);
|
||||
finalizeFaceAiLegacyGallery(gallery, matchState, resolvedCards);
|
||||
}, function() {
|
||||
finalizeFaceAiLegacyGallery(gallery, matchState, []);
|
||||
});
|
||||
}
|
||||
|
||||
function prepareFaceAiLegacyRacePage() {
|
||||
var matchState = getFaceAiMatchState();
|
||||
var gallery = $("#demo");
|
||||
var preparationKey;
|
||||
if (!matchState || !gallery.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
preparationKey = window.location.pathname + "?" + window.location.search;
|
||||
if (window.faceAiLegacyPreparationKey === preparationKey) {
|
||||
return window.faceAiMatchState || matchState;
|
||||
}
|
||||
|
||||
window.faceAiLegacyPreparationKey = preparationKey;
|
||||
window.faceAiLegacyGalleryRequestId = (window.faceAiLegacyGalleryRequestId || 0) + 1;
|
||||
matchState.requestId = window.faceAiLegacyGalleryRequestId;
|
||||
matchState.visibleCount = 0;
|
||||
hideFaceAiLegacyPagination();
|
||||
renderFaceAiLegacyBanner(matchState);
|
||||
loadFaceAiLegacyGallery(gallery, matchState);
|
||||
|
||||
return matchState;
|
||||
}
|
||||
|
||||
function buildFaceAiLaunchUrl() {
|
||||
var raceId = $("#id_gara").val() || "";
|
||||
var raceSlug = $("#garaDesc").val() || "";
|
||||
|
|
@ -261,7 +694,7 @@ function buildFaceAiLaunchUrl() {
|
|||
var raceStorageRelativeDir = $("#faceAiRaceStorageRelativeDir").val() || [raceYear, raceMonthFolder, raceFolder].filter(Boolean).join("/");
|
||||
var lang = getCurrentLangValue();
|
||||
var handoffUrl = (window.faceAiSimulator && window.faceAiSimulator.handoffUrl) || "faceai_handoff.php";
|
||||
var returnUrl = (window.faceAiSimulator && window.faceAiSimulator.returnUrl) || window.location.href;
|
||||
var returnUrl = stripFaceAiStateFromUrl((window.faceAiSimulator && window.faceAiSimulator.returnUrl) || window.location.href);
|
||||
var query = [
|
||||
"raceId=" + encodeURIComponent(raceId),
|
||||
"raceSlug=" + encodeURIComponent(raceSlug),
|
||||
|
|
@ -558,6 +991,7 @@ function goPage()
|
|||
|
||||
$(function() {
|
||||
clearLegacyLoadingState();
|
||||
prepareFaceAiLegacyRacePage();
|
||||
initFaceAiRaceSearchButton();
|
||||
initFaceAiErrorModal();
|
||||
logFaceAiDebug("Legacy race page ready");
|
||||
|
|
|
|||
299
www/faceai_photo_lookup.jsp
Normal file
299
www/faceai_photo_lookup.jsp
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
<%@ page contentType="application/json; charset=UTF-8" %>
|
||||
<%@ page language="java" import="java.lang.reflect.Constructor" %>
|
||||
<%@ page language="java" import="java.lang.reflect.Method" %>
|
||||
<%!
|
||||
private String faceAiLookupTrim(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
private String faceAiLookupEscapeJson(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder(value.length() + 16);
|
||||
for (int index = 0; index < value.length(); index++) {
|
||||
char current = value.charAt(index);
|
||||
switch (current) {
|
||||
case '\\':
|
||||
builder.append("\\\\");
|
||||
break;
|
||||
case '"':
|
||||
builder.append("\\\"");
|
||||
break;
|
||||
case '\b':
|
||||
builder.append("\\b");
|
||||
break;
|
||||
case '\f':
|
||||
builder.append("\\f");
|
||||
break;
|
||||
case '\n':
|
||||
builder.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
builder.append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
builder.append("\\t");
|
||||
break;
|
||||
default:
|
||||
if (current < 0x20) {
|
||||
String hex = Integer.toHexString(current);
|
||||
builder.append("\\u");
|
||||
for (int padding = hex.length(); padding < 4; padding++) {
|
||||
builder.append('0');
|
||||
}
|
||||
builder.append(hex);
|
||||
} else {
|
||||
builder.append(current);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private Object faceAiLookupInvoke(Object target, String methodName, Class[] paramTypes, Object[] args) {
|
||||
if (target == null || methodName == null || methodName.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
Method method = target.getClass().getMethod(methodName, paramTypes == null ? new Class[0] : paramTypes);
|
||||
return method.invoke(target, args == null ? new Object[0] : args);
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private long faceAiLookupLong(Object value) {
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).longValue();
|
||||
}
|
||||
if (value != null) {
|
||||
try {
|
||||
return Long.parseLong(String.valueOf(value));
|
||||
} catch (NumberFormatException ignored) {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
private String faceAiLookupString(Object value) {
|
||||
return value == null ? "" : String.valueOf(value);
|
||||
}
|
||||
|
||||
private boolean faceAiLookupIsSafeValue(String value) {
|
||||
return value == null || value.indexOf('\'') == -1;
|
||||
}
|
||||
|
||||
private String faceAiLookupNormalizePhotoId(String value) {
|
||||
return faceAiLookupTrim(value).replace('\\', '/');
|
||||
}
|
||||
|
||||
private String faceAiLookupNormalizeFileName(String value) {
|
||||
String normalized = faceAiLookupNormalizePhotoId(value);
|
||||
int lastSlash = normalized.lastIndexOf('/');
|
||||
if (lastSlash >= 0 && lastSlash < normalized.length() - 1) {
|
||||
normalized = normalized.substring(lastSlash + 1);
|
||||
}
|
||||
return faceAiLookupTrim(normalized);
|
||||
}
|
||||
|
||||
private String faceAiLookupCompositeFileName(String photoId) {
|
||||
String normalized = faceAiLookupNormalizePhotoId(photoId);
|
||||
if (normalized.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
return normalized.replace('/', '_').replace(':', '_');
|
||||
}
|
||||
|
||||
private long[] faceAiLookupParseLongList(String value) {
|
||||
if (value == null || value.trim().length() == 0) {
|
||||
return new long[0];
|
||||
}
|
||||
|
||||
String[] parts = value.split(",");
|
||||
long[] parsed = new long[parts.length];
|
||||
int count = 0;
|
||||
for (int index = 0; index < parts.length; index++) {
|
||||
String part = parts[index] == null ? "" : parts[index].trim();
|
||||
if (!part.matches("^\\d+$")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
parsed[count] = Long.parseLong(part);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == parsed.length) {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
long[] compact = new long[count];
|
||||
for (int index = 0; index < count; index++) {
|
||||
compact[index] = parsed[index];
|
||||
}
|
||||
return compact;
|
||||
}
|
||||
|
||||
private Object faceAiLookupInstantiateFoto(Class fotoClass, Constructor constructor, Object apFull) throws Exception {
|
||||
return constructor.newInstance(new Object[] { apFull });
|
||||
}
|
||||
|
||||
private boolean faceAiLookupHasResolvedPhoto(Object foto) {
|
||||
return faceAiLookupLong(faceAiLookupInvoke(foto, "getDBState", null, null)) == 1L
|
||||
&& faceAiLookupLong(faceAiLookupInvoke(foto, "getId_foto", null, null)) > 0L;
|
||||
}
|
||||
|
||||
private Object faceAiLookupResolvePhoto(Class fotoClass, Constructor constructor, Object apFull, String photoId, String normalizedPhotoId, String fileName, long raceId, long[] puntoFotoIds) throws Exception {
|
||||
Method findByPrimaryKey = fotoClass.getMethod("findByPrimaryKey", new Class[] { long.class });
|
||||
Method findByFoto = fotoClass.getMethod("findByFoto", new Class[] { String.class });
|
||||
Method findByFilenamePuntoFoto = fotoClass.getMethod("findByFilenamePuntoFoto", new Class[] { String.class, long.class });
|
||||
Method findByFilenameGara = fotoClass.getMethod("findByFilenameGara", new Class[] { String.class, long.class });
|
||||
String compositeFileName = faceAiLookupCompositeFileName(photoId);
|
||||
|
||||
if (photoId.matches("^\\d+$")) {
|
||||
Object foto = faceAiLookupInstantiateFoto(fotoClass, constructor, apFull);
|
||||
findByPrimaryKey.invoke(foto, new Object[] { Long.valueOf(Long.parseLong(photoId)) });
|
||||
if (faceAiLookupHasResolvedPhoto(foto)) {
|
||||
return foto;
|
||||
}
|
||||
}
|
||||
|
||||
String[] fotoCandidates = new String[] {
|
||||
photoId,
|
||||
normalizedPhotoId,
|
||||
compositeFileName,
|
||||
fileName
|
||||
};
|
||||
for (int index = 0; index < fotoCandidates.length; index++) {
|
||||
String candidate = faceAiLookupTrim(fotoCandidates[index]);
|
||||
if (candidate.length() == 0 || !faceAiLookupIsSafeValue(candidate)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object foto = faceAiLookupInstantiateFoto(fotoClass, constructor, apFull);
|
||||
findByFoto.invoke(foto, new Object[] { candidate });
|
||||
if (faceAiLookupHasResolvedPhoto(foto)) {
|
||||
return foto;
|
||||
}
|
||||
}
|
||||
|
||||
if (fileName.length() > 0 && faceAiLookupIsSafeValue(fileName)) {
|
||||
for (int index = 0; index < puntoFotoIds.length; index++) {
|
||||
if (puntoFotoIds[index] <= 0L) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object foto = faceAiLookupInstantiateFoto(fotoClass, constructor, apFull);
|
||||
findByFilenamePuntoFoto.invoke(foto, new Object[] { fileName, Long.valueOf(puntoFotoIds[index]) });
|
||||
if (faceAiLookupHasResolvedPhoto(foto)) {
|
||||
return foto;
|
||||
}
|
||||
}
|
||||
|
||||
if (raceId > 0L) {
|
||||
Object foto = faceAiLookupInstantiateFoto(fotoClass, constructor, apFull);
|
||||
findByFilenameGara.invoke(foto, new Object[] { fileName, Long.valueOf(raceId) });
|
||||
if (faceAiLookupHasResolvedPhoto(foto)) {
|
||||
return foto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (compositeFileName.length() > 0 && raceId > 0L && faceAiLookupIsSafeValue(compositeFileName)) {
|
||||
Object foto = faceAiLookupInstantiateFoto(fotoClass, constructor, apFull);
|
||||
findByFilenameGara.invoke(foto, new Object[] { compositeFileName, Long.valueOf(raceId) });
|
||||
if (faceAiLookupHasResolvedPhoto(foto)) {
|
||||
return foto;
|
||||
}
|
||||
}
|
||||
|
||||
return faceAiLookupInstantiateFoto(fotoClass, constructor, apFull);
|
||||
}
|
||||
|
||||
private Object faceAiLookupResolveApFull(javax.servlet.jsp.PageContext pageContext) {
|
||||
if (pageContext == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object[] candidates = new Object[] {
|
||||
pageContext.findAttribute("user"),
|
||||
pageContext.findAttribute("utenteLogon")
|
||||
};
|
||||
|
||||
for (int index = 0; index < candidates.length; index++) {
|
||||
Object candidate = candidates[index];
|
||||
Object apFull = faceAiLookupInvoke(candidate, "getApFull", null, null);
|
||||
if (apFull != null) {
|
||||
return apFull;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
%>
|
||||
<%
|
||||
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
|
||||
String rawPhotoId = request.getParameter("photoId");
|
||||
String photoId = faceAiLookupTrim(rawPhotoId);
|
||||
String normalizedPhotoId = faceAiLookupNormalizePhotoId(request.getParameter("normalizedPhotoId"));
|
||||
String fileName = faceAiLookupNormalizeFileName(request.getParameter("fileName"));
|
||||
long raceId = faceAiLookupLong(request.getParameter("raceId"));
|
||||
long[] puntoFotoIds = faceAiLookupParseLongList(request.getParameter("puntoFotoIds"));
|
||||
|
||||
if (photoId.length() == 0) {
|
||||
response.setStatus(400);
|
||||
out.print("{\"found\":false,\"error\":\"missing-photo-id\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!faceAiLookupIsSafeValue(photoId) || !faceAiLookupIsSafeValue(normalizedPhotoId) || !faceAiLookupIsSafeValue(fileName)) {
|
||||
response.setStatus(400);
|
||||
out.print("{\"found\":false,\"photoId\":\"" + faceAiLookupEscapeJson(photoId) + "\",\"error\":\"invalid-photo-id\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
Object apFull = faceAiLookupResolveApFull(pageContext);
|
||||
if (apFull == null) {
|
||||
response.setStatus(503);
|
||||
out.print("{\"found\":false,\"photoId\":\"" + faceAiLookupEscapeJson(photoId) + "\",\"error\":\"missing-apfull\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Class fotoClass = Class.forName("it.acxent.pg.Foto");
|
||||
Constructor constructor = fotoClass.getConstructor(new Class[] { apFull.getClass() });
|
||||
Object foto = faceAiLookupResolvePhoto(fotoClass, constructor, apFull, photoId, normalizedPhotoId, fileName, raceId, puntoFotoIds);
|
||||
|
||||
long dbState = faceAiLookupLong(faceAiLookupInvoke(foto, "getDBState", null, null));
|
||||
long legacyId = faceAiLookupLong(faceAiLookupInvoke(foto, "getId_foto", null, null));
|
||||
|
||||
if (dbState != 1L || legacyId <= 0L) {
|
||||
response.setStatus(404);
|
||||
out.print("{\"found\":false,\"photoId\":\"" + faceAiLookupEscapeJson(photoId) + "\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
Method getFileName = fotoClass.getMethod("getFileName", new Class[] { String.class });
|
||||
String thumbnailBase = faceAiLookupString(getFileName.invoke(foto, new Object[] { ".jpg" }));
|
||||
String thumbSrc = "foto/" + thumbnailBase + "+tn-" + legacyId + ".jpg";
|
||||
|
||||
out.print("{"
|
||||
+ "\"found\":true,"
|
||||
+ "\"photoId\":\"" + faceAiLookupEscapeJson(photoId) + "\","
|
||||
+ "\"resolvedFile\":\"" + faceAiLookupEscapeJson(faceAiLookupString(faceAiLookupInvoke(foto, "getFile", null, null))) + "\","
|
||||
+ "\"legacyId\":" + legacyId + ","
|
||||
+ "\"thumbSrc\":\"" + faceAiLookupEscapeJson(thumbSrc) + "\""
|
||||
+ "}");
|
||||
} catch (Exception error) {
|
||||
log("FaceAI photo lookup failed for " + photoId, error);
|
||||
response.setStatus(500);
|
||||
out.print("{\"found\":false,\"photoId\":\"" + faceAiLookupEscapeJson(photoId) + "\",\"error\":\"lookup-failed\"}");
|
||||
}
|
||||
%>
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__ . '/faceai_config.php';
|
||||
require_once __DIR__ . '/faceai_simulator_view.php';
|
||||
|
||||
$config = faceai_config();
|
||||
|
||||
|
|
@ -39,31 +38,28 @@ try {
|
|||
'token' => $token
|
||||
));
|
||||
$result = faceai_fetch_json($bridgeUrl);
|
||||
$returnUrl = (string) ($result['returnUrl'] ?? '');
|
||||
$matches = is_array($result['matches'] ?? null) ? $result['matches'] : array();
|
||||
$photos = array_map(static function ($match) {
|
||||
$photoId = (string) ($match['photoId'] ?? ($match['id'] ?? ''));
|
||||
|
||||
return array(
|
||||
'id' => $photoId,
|
||||
'photoId' => $photoId,
|
||||
'label' => (string) ($match['label'] ?? $photoId),
|
||||
'checkpoint' => (string) ($match['checkpoint'] ?? '-'),
|
||||
'previewUrl' => (string) ($match['previewUrl'] ?? ''),
|
||||
'score' => $match['score'] ?? null,
|
||||
);
|
||||
}, $matches);
|
||||
if ($returnUrl === '') {
|
||||
throw new RuntimeException('Missing legacy return URL.');
|
||||
}
|
||||
|
||||
faceai_sim_render_page(array(
|
||||
'raceId' => (string) ($result['raceId'] ?? ($payload['raceId'] ?? '')),
|
||||
'lang' => (string) ($result['lang'] ?? 'it'),
|
||||
'raceSlug' => (string) ($result['raceId'] ?? ($payload['raceId'] ?? '')),
|
||||
'raceName' => (string) ($result['raceName'] ?? ('Race ' . ($payload['raceId'] ?? ''))),
|
||||
'returnUrl' => (string) ($result['returnUrl'] ?? 'faceai_simulator.php'),
|
||||
'banner' => 'Vista filtrata da FaceAI. Sono state trovate <strong>' . count($photos) . '</strong> foto corrispondenti per l utente corrente.',
|
||||
'totalLabel' => count($photos) . ' foto da FaceAI',
|
||||
'photos' => $photos,
|
||||
'showSimulatorBootstrap' => false
|
||||
));
|
||||
$photoIds = array();
|
||||
foreach ($matches as $match) {
|
||||
$photoId = trim((string) ($match['photoId'] ?? ($match['id'] ?? '')));
|
||||
if ($photoId === '') {
|
||||
continue;
|
||||
}
|
||||
$photoIds[$photoId] = true;
|
||||
}
|
||||
|
||||
header('Location: ' . faceai_build_url($returnUrl, array(
|
||||
'faceaiMatchSource' => 'faceai',
|
||||
'faceaiMatchCount' => count($photoIds),
|
||||
'faceaiPhotoIds' => implode(',', array_keys($photoIds))
|
||||
)), true, 302);
|
||||
exit;
|
||||
} catch (Throwable $error) {
|
||||
faceai_render_message_page('Errore return FaceAI', $error->getMessage(), array(), 500);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ if (!faceAiRaceYear.isEmpty()) {
|
|||
<hr>
|
||||
</div>
|
||||
<div class="col-md-4 col-inline">
|
||||
<p class="lead"><acx:lang>Sono state trovate</acx:lang> <%=list.getTotNumberOfRecords()%> <acx:lang>foto</acx:lang>
|
||||
<p class="lead" id="faceAiResultsSummary"><span id="faceAiPhotoCountLabel"><acx:lang>Sono state trovate</acx:lang></span> <span id="faceAiPhotoCountValue"><%=list.getTotNumberOfRecords()%></span> <span id="faceAiPhotoCountSuffix"><acx:lang>foto</acx:lang></span>
|
||||
<acx:if wherecondition="<%=CR.getFlgVisCompatta()==0%>"><a href='<%=bean.getDescrizioneGaraHtml()+"_garaC-"+bean.getId_gara()+"-"+CR.getId_puntoFoto()+"-"+CR.getTipoPuntoFoto()+"-"+CR.getPageRow()+"-"+CR.getPageNumber()+"-"+langpay ><i class="fa fa-search-minus" title="<acx:lang>visualizzazione compatta</acx:lang>"></i></a></acx:if>
|
||||
<acx:else><a href='<%=bean.getDescrizioneGaraHtml()+"_garaE-"+bean.getId_gara()+"-"+CR.getId_puntoFoto()+"-"+CR.getTipoPuntoFoto()+"-"+CR.getPageRow()+"-"+CR.getPageNumber()+"-"+lang+".html"%>' ><i class="fa fa-search-plus" title="<acx:lang>visualizzazione standard</acx:lang>"></i></a></acx:else>
|
||||
<div id="vis" style="visibility: hidden"></div>
|
||||
|
|
@ -258,10 +258,10 @@ if (!faceAiRaceYear.isEmpty()) {
|
|||
<div class="col-md-10" style="min-height: 500px">
|
||||
<div id="demo">
|
||||
<acx:whilevec rowbeanclass="it.acxent.pg.Foto" vectumerator="list">
|
||||
<acx:if_logon_ok> <a href="javascript:mostraFoto(<%=rowBean.getId_foto()%>)"> <img src="foto/<%=rowBean.getFileName(".jpg")%>+tn-<%=rowBean.getId_foto()%>.jpg" alt="" class="thumb" />
|
||||
<acx:if_logon_ok> <a href="javascript:mostraFoto(<%=rowBean.getId_foto()%>)" data-faceai-photo-id="<%=rowBean.getId_foto()%>"> <img src="foto/<%=rowBean.getFileName(".jpg")%>+tn-<%=rowBean.getId_foto()%>.jpg" alt="" class="thumb" />
|
||||
<div class="caption"><acx:lang>Hits</acx:lang>: <%=rowBean.getImpression()%> - <%=df.format(rowBean.getDataUltimaVisual())%> </div>
|
||||
</a> </acx:if_logon_ok>
|
||||
<acx:else_logon> <a data-toggle="modal" data-target="#ModalNoLog"> <img src="foto/<%=rowBean.getFile()%>?id_foto=<%=rowBean.getId_foto()%>" alt="" class="thumb" />
|
||||
<acx:else_logon> <a data-toggle="modal" data-target="#ModalNoLog" data-faceai-photo-id="<%=rowBean.getId_foto()%>"> <img src="foto/<%=rowBean.getFile()%>?id_foto=<%=rowBean.getId_foto()%>" alt="" class="thumb" />
|
||||
<div class="caption"><acx:lang>Hits</acx:lang>: <%=rowBean.getImpression()%> - <%=df.format(rowBean.getDataUltimaVisual())%> </div>
|
||||
</a> </acx:else_logon>
|
||||
</acx:whilevec>
|
||||
|
|
@ -376,6 +376,8 @@ if (!faceAiRaceYear.isEmpty()) {
|
|||
<script>
|
||||
window.faceAiConfig = window.faceAiConfig || {};
|
||||
window.faceAiConfig.enabled = <%= faceAiFeatureEnabled ? "true" : "false" %>;
|
||||
window.faceAiConfig.lang = "<%= lang %>";
|
||||
window.faceAiConfig.galleryMode = '<%= CR.getFlgVisCompatta()==1 ? "compact" : "standard" %>';
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ if (!faceAiRaceYear.isEmpty()) {
|
|||
<hr>
|
||||
</div>
|
||||
<div class="col-md-4 col-inline">
|
||||
<p class="lead"><acx:lang>Sono state trovate</acx:lang> <%=list.getTotNumberOfRecords()%> <acx:lang>foto</acx:lang>
|
||||
<p class="lead" id="faceAiResultsSummary"><span id="faceAiPhotoCountLabel"><acx:lang>Sono state trovate</acx:lang></span> <span id="faceAiPhotoCountValue"><%=list.getTotNumberOfRecords()%></span> <span id="faceAiPhotoCountSuffix"><acx:lang>foto</acx:lang></span>
|
||||
<acx:if wherecondition="<%=CR.getFlgVisCompatta()==0%>"><a href="<%=bean.getDescrizioneGaraHtml()+"_garaC-"+bean.getId_gara()+"-"+CR.getId_puntoFoto()+"-"+CR.getTipoPuntoFoto()+"-"+CR.getPageRow()+"-"+CR.getPageNumber()+".html"%>"><i class="fa fa-search-minus" title="<acx:lang>visualizzazione compatta</acx:lang>"></i></a></acx:if>
|
||||
<acx:else><a href="<%=bean.getDescrizioneGaraHtml()+"_garaE-"+bean.getId_gara()+"-"+CR.getId_puntoFoto()+"-"+CR.getTipoPuntoFoto()+"-"+CR.getPageRow()+"-"+CR.getPageNumber()+".html"%>"><i class="fa fa-search-plus" title="<acx:lang>visualizzazione standard</acx:lang>"></i></a></acx:else>
|
||||
<div id="vis" style="visibility: hidden"></div>
|
||||
|
|
@ -258,10 +258,10 @@ if (!faceAiRaceYear.isEmpty()) {
|
|||
<div class="col-md-10" style="min-height: 500px">
|
||||
<div id="demo">
|
||||
<acx:whilevec rowbeanclass="it.acxent.pg.Foto" vectumerator="list">
|
||||
<acx:if_logon_ok> <a href="javascript:mostraFoto(<%=rowBean.getId_foto()%>)"> <img src="foto/<%=rowBean.getFileName(".jpg")%>+tn-<%=rowBean.getId_foto()%>.jpg" alt="" class="thumb" />
|
||||
<acx:if_logon_ok> <a href="javascript:mostraFoto(<%=rowBean.getId_foto()%>)" data-faceai-photo-id="<%=rowBean.getId_foto()%>"> <img src="foto/<%=rowBean.getFileName(".jpg")%>+tn-<%=rowBean.getId_foto()%>.jpg" alt="" class="thumb" />
|
||||
<div class="caption"><acx:lang>Hits</acx:lang>: <%=rowBean.getImpression()%> - <%=df.format(rowBean.getDataUltimaVisual())%> </div>
|
||||
</a> </acx:if_logon_ok>
|
||||
<acx:else_logon> <a data-toggle="modal" data-target="#ModalNoLog"> <img src="foto/<%=rowBean.getFile()%>?id_foto=<%=rowBean.getId_foto()%>" alt="" class="thumb" />
|
||||
<acx:else_logon> <a data-toggle="modal" data-target="#ModalNoLog" data-faceai-photo-id="<%=rowBean.getId_foto()%>"> <img src="foto/<%=rowBean.getFile()%>?id_foto=<%=rowBean.getId_foto()%>" alt="" class="thumb" />
|
||||
<div class="caption"><acx:lang>Hits</acx:lang>: <%=rowBean.getImpression()%> - <%=df.format(rowBean.getDataUltimaVisual())%> </div>
|
||||
</a> </acx:else_logon>
|
||||
</acx:whilevec>
|
||||
|
|
@ -376,6 +376,8 @@ if (!faceAiRaceYear.isEmpty()) {
|
|||
<script>
|
||||
window.faceAiConfig = window.faceAiConfig || {};
|
||||
window.faceAiConfig.enabled = <%= faceAiFeatureEnabled ? "true" : "false" %>;
|
||||
window.faceAiConfig.lang = "<%= lang %>";
|
||||
window.faceAiConfig.galleryMode = '<%= CR.getFlgVisCompatta()==1 ? "compact" : "standard" %>';
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue