feat: Enhance FaceAI functionality and improve login process
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:
MaddoScientisto 2026-04-19 14:18:00 +02:00
commit bba8026b7c
17 changed files with 1077 additions and 95 deletions

299
www/faceai_photo_lookup.jsp Normal file
View 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\"}");
}
%>