Compare commits
2 commits
f757f8af1d
...
bb60201ad4
| Author | SHA1 | Date | |
|---|---|---|---|
| bb60201ad4 | |||
| c88b373c73 |
29 changed files with 4554 additions and 18 deletions
|
|
@ -102,6 +102,7 @@ code example here
|
|||
- **Include Examples**: Real code snippets are more effective than descriptions
|
||||
- **Stay Current**: Reference current versions and best practices
|
||||
- **Link Resources**: Include official documentation and authoritative sources
|
||||
- **Capture validated shell quirks**: For environment-specific instruction files, record proven terminal behaviors, quoting pitfalls, failing command patterns, and the known-good command form that replaced them
|
||||
|
||||
### Instruction Altitude (Goldilocks Zone)
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,12 @@ If you need a single elevated command:
|
|||
ssh -tt -i C:\Users\Maddo\.ssh\id_rsa -p 410 marco@83.149.164.4 "sudo tcsh -c 'command here'"
|
||||
```
|
||||
|
||||
From PowerShell on Windows, prefer invoking the SSH binary directly instead of wrapping it in `cmd /c`:
|
||||
|
||||
```powershell
|
||||
& 'C:\Windows\System32\OpenSSH\ssh.exe' -tt -i 'C:\Users\Maddo\.ssh\id_rsa' -p 410 'marco@83.149.164.4'
|
||||
```
|
||||
|
||||
## Shell Behavior On This Host
|
||||
|
||||
- The remote login shell behaves as `tcsh`.
|
||||
|
|
@ -42,11 +48,15 @@ ssh -tt -i C:\Users\Maddo\.ssh\id_rsa -p 410 marco@83.149.164.4 "sudo tcsh -c 'c
|
|||
- The server `sh` does not support `-l`, so use `sh -c`, not `sh -lc`.
|
||||
- `tcsh` treats redirection and pipelines differently from POSIX shells; commands like `find ... 2>/dev/null | head` can fail with `Ambiguous output redirect` unless the whole payload runs under `sh -c`.
|
||||
- Prefer one remote command per SSH invocation when doing reconnaissance. Complex commands with pipes, grouped expressions, or escaped parentheses are much more likely to break under PowerShell-to-SSH-to-`tcsh` quoting.
|
||||
- On Windows PowerShell, avoid `cmd /c "ssh ..."` and `cmd /c "scp ..."` wrappers for anything nontrivial. Nested quoting can collapse before SSH runs and spill later tokens into the local PowerShell session, which leads to misleading local errors such as `sudo: The term 'sudo' is not recognized` or local attempts to run `cksum`.
|
||||
- Prefer the PowerShell call operator form `& 'C:\Windows\System32\OpenSSH\ssh.exe' ...` and pass the remote command as a single argument when you must stay non-interactive.
|
||||
- If PowerShell shows the continuation prompt `? >`, the command was malformed locally before SSH executed it. Cancel it and rerun a simpler command instead of trying to answer the prompt.
|
||||
- If `sudo` reports that a terminal is required, reconnect with `-tt`.
|
||||
- When running remote commands from PowerShell, quoting can break if the command contains both nested quotes and file paths with spaces.
|
||||
- For read-only verification commands from PowerShell, prefer `ssh ... --% <remote command>` so the remote command is passed verbatim.
|
||||
- For `promote-file.sh` calls that target paths with spaces, prefer a local PowerShell loop that passes the full remote command as a single SSH argument instead of building one long nested quoted command.
|
||||
- For multi-step privileged work, prefer opening one interactive SSH session, then running `sudo tcsh`, then issuing commands sequentially inside that shell. This is more reliable than trying to encode several `sudo tcsh -c 'a ; b ; c'` operations through PowerShell quoting.
|
||||
- In an interactive `tcsh` root shell, do not re-send a password or any other text starting with `!` after the password prompt has already succeeded. `tcsh` interprets `!` as history expansion and will emit `Event not found`.
|
||||
- If repeated SSH commands start cancelling or interleaving poorly in the same terminal, rerun them sequentially instead of in parallel.
|
||||
|
||||
## Mail Template Runtime Notes
|
||||
|
|
@ -88,6 +98,14 @@ ssh -tt -i C:\Users\Maddo\.ssh\id_rsa -p 410 marco@83.149.164.4 "sudo tcsh -c 'c
|
|||
- Incoming staging root: `/home/marco/regalamiunsorriso/incoming/www`
|
||||
- Live site root: `/home/sites/regalamiunsorriso/www`
|
||||
|
||||
## Tomcat Logs And Runtime Clues
|
||||
|
||||
- The active Tomcat installation on this host is under `/usr/local/apache-tomcat-9.0`.
|
||||
- The most useful live runtime log is `/usr/local/apache-tomcat-9.0/logs/catalina.out`.
|
||||
- Rotated Tomcat logs are under `/usr/local/apache-tomcat-9.0/logs/`, including files such as `catalina.YYYY-MM-DD.log` and `localhost.YYYY-MM-DD.log`.
|
||||
- Access to generated JSP work files under `/usr/local/apache-tomcat-9.0/work` may require root.
|
||||
- A broken JSP on this host can still return `HTTP 200` with a visibly truncated HTML body instead of a clean 500 response; when that happens, fetch part of the page body with `curl -L <url> | head -n ...` and compare the cutoff point with recent `catalina.out` output.
|
||||
|
||||
## Staging Workflow
|
||||
|
||||
When `www/**` files need deployment:
|
||||
|
|
@ -103,6 +121,9 @@ Example staging command pattern:
|
|||
tar -cf - -C K:\various\regalamiunsorriso <file-list-under-www> | ssh -i C:\Users\Maddo\.ssh\id_rsa -p 410 marco@83.149.164.4 "tar -xf - -C /home/marco/regalamiunsorriso/incoming"
|
||||
```
|
||||
|
||||
- The streamed tar extraction into `/home/marco/regalamiunsorriso/incoming` works as the unprivileged `marco` user and avoids the permission problems seen when uploading an archive and trying to unpack it with `sudo tar`.
|
||||
- Do not rely on `sudo tar` for staging on this host. `marco` is not permitted to run that extraction as root.
|
||||
|
||||
## Promotion Rules
|
||||
|
||||
- Promotion to the live site must happen through `sudo tcsh`.
|
||||
|
|
@ -136,6 +157,13 @@ $remote = "sudo tcsh -c \"/home/marco/promote-file.sh '<staged-path>' '<live-pat
|
|||
& ssh -tt -i 'C:\Users\Maddo\.ssh\id_rsa' -p 410 'marco@83.149.164.4' $remote
|
||||
```
|
||||
|
||||
If the deployment needs more than one privileged action or may prompt for a password, prefer this sequence instead of packing everything into one quoted SSH command:
|
||||
|
||||
1. Open an interactive SSH session with `-tt`.
|
||||
2. Run `sudo tcsh`.
|
||||
3. Run `/home/marco/promote-file.sh ...` commands one at a time.
|
||||
4. Run `ls -l`, `stat -f`, and `cksum` in that same root shell.
|
||||
|
||||
Behavior of `promote-file.sh`:
|
||||
|
||||
- If the destination already exists, it copies the file and restores that destination file's original owner, group, and mode.
|
||||
|
|
|
|||
|
|
@ -14,3 +14,8 @@ FACEAI_UPLOAD_ROOT=/data/runtime/uploads
|
|||
FACEAI_LOG_ROOT=/data/logs
|
||||
FACEAI_PKL_ROOT=/data/pkl
|
||||
FACEAI_MATCHER_BINARY=/opt/face-recognition/face_matcher
|
||||
LIVE_SITE_BASE_URL=https://www.regalamiunsorriso.it
|
||||
LIVE_SITE_LOGIN_URL=https://www.regalamiunsorriso.it/login_clienti-it.html
|
||||
LIVE_SITE_RACE_URL=https://www.regalamiunsorriso.it/42%20HALF%20MARATHON%20FIRENZE_gara-1018545---96-1.html
|
||||
LIVE_SITE_USERNAME=
|
||||
LIVE_SITE_PASSWORD=
|
||||
|
|
|
|||
1
faceai/.gitignore
vendored
1
faceai/.gitignore
vendored
|
|
@ -3,3 +3,4 @@ apps/frontend/dist/
|
|||
.env
|
||||
playwright-report/
|
||||
test-results/
|
||||
tests/live-site/.auth/
|
||||
|
|
|
|||
|
|
@ -172,6 +172,50 @@ If you want to keep the local containers running after the test for manual inspe
|
|||
FACEAI_E2E_KEEP_STACK=1
|
||||
```
|
||||
|
||||
## Live Site Playwright Checks
|
||||
|
||||
The `faceai/` workspace now also includes a separate Playwright project for the live site. It is isolated from the Docker-backed simulator suite and is intended to verify that production login still works and that a real race page loads correctly after authentication.
|
||||
|
||||
Set these environment variables before running it:
|
||||
|
||||
```bash
|
||||
LIVE_SITE_BASE_URL=https://www.regalamiunsorriso.it
|
||||
LIVE_SITE_LOGIN_URL=https://www.regalamiunsorriso.it/login_clienti-it.html
|
||||
LIVE_SITE_RACE_URL=https://www.regalamiunsorriso.it/42%20HALF%20MARATHON%20FIRENZE_gara-1018545---96-1.html
|
||||
LIVE_SITE_USERNAME=your-login
|
||||
LIVE_SITE_PASSWORD=your-password
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```bash
|
||||
npm run test:live:install
|
||||
npm run test:live
|
||||
```
|
||||
|
||||
What it does:
|
||||
|
||||
- opens the live login page
|
||||
- signs in with the supplied credentials
|
||||
- persists authenticated Playwright storage state under `tests/live-site/.auth/user.json`
|
||||
- opens the configured live race URL
|
||||
- verifies the account UI is present and the race search form renders correctly
|
||||
|
||||
Optional live FaceAI checks can also be enabled with:
|
||||
|
||||
```bash
|
||||
LIVE_FACEAI_BASE_URL=https://ai.regalamiunsorriso.it
|
||||
LIVE_SITE_PORTRAIT_PATH=../test_pkl/live/test_portrait_1.png
|
||||
LIVE_SITE_RUN_UPLOAD_FLOW=1
|
||||
```
|
||||
|
||||
When enabled, the live suite also:
|
||||
|
||||
- validates that the legacy Face ID handoff URL includes the race storage metadata expected by FaceAI
|
||||
- opens the real FaceAI app and asserts that the legacy header stylesheets load from the live legacy site
|
||||
- confirms the app does not emit the `MISSING_RACE_STORAGE` invalid-race error on launch
|
||||
- uploads the supplied portrait image and verifies that search creation succeeds
|
||||
|
||||
## Optional Backend And Frontend Dev Loop
|
||||
|
||||
If you only want to iterate on the app without the PHP simulator, you can still run the public site and the processor separately. The queue-backed flow now requires Redis and the processor, so `npm run dev` alone is no longer the full stack.
|
||||
|
|
|
|||
1116
faceai/anonymous_output.html
Normal file
1116
faceai/anonymous_output.html
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -30,6 +30,20 @@ function sanitizePathSegment(value) {
|
|||
return normalized;
|
||||
}
|
||||
|
||||
function parseRelativeStorageSegments(value) {
|
||||
const normalized = String(value || '').trim().replace(/\\/g, '/');
|
||||
|
||||
if (!normalized) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return normalized
|
||||
.split('/')
|
||||
.map((segment) => segment.trim())
|
||||
.filter(Boolean)
|
||||
.map((segment) => sanitizePathSegment(segment));
|
||||
}
|
||||
|
||||
export function normalizeRaceFolderName(value) {
|
||||
return String(value || '')
|
||||
.trim()
|
||||
|
|
@ -49,9 +63,16 @@ export function buildMonthFolder(year, monthIndex) {
|
|||
}
|
||||
|
||||
export function buildRaceStorage(storageInput = {}) {
|
||||
const year = sanitizePathSegment(storageInput.year);
|
||||
const monthFolder = sanitizePathSegment(storageInput.monthFolder);
|
||||
const raceFolder = sanitizePathSegment(normalizeRaceFolderName(storageInput.raceFolder));
|
||||
const relativeSegments = parseRelativeStorageSegments(storageInput.relativeDir);
|
||||
const relativeYear = relativeSegments[0] || '';
|
||||
const relativeMonthFolder = relativeSegments.length >= 3 ? relativeSegments[1] : '';
|
||||
const relativeRaceFolder = relativeSegments.length >= 3
|
||||
? relativeSegments[2]
|
||||
: (relativeSegments.length >= 2 ? relativeSegments[1] : '');
|
||||
|
||||
const year = sanitizePathSegment(storageInput.year || relativeYear);
|
||||
const monthFolder = sanitizePathSegment(storageInput.monthFolder || relativeMonthFolder);
|
||||
const raceFolder = sanitizePathSegment(normalizeRaceFolderName(storageInput.raceFolder || relativeRaceFolder));
|
||||
|
||||
if (!year || !monthFolder || !raceFolder) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -262,7 +262,8 @@ app.get('/dev/legacy/launch', (req, res) => {
|
|||
raceStorage: {
|
||||
year: String(req.query.raceYear || mockCatalog[raceId]?.storage?.year || ''),
|
||||
monthFolder: String(req.query.raceMonthFolder || mockCatalog[raceId]?.storage?.monthFolder || ''),
|
||||
raceFolder: String(req.query.raceFolder || mockCatalog[raceId]?.storage?.raceFolder || '')
|
||||
raceFolder: String(req.query.raceFolder || mockCatalog[raceId]?.storage?.raceFolder || ''),
|
||||
relativeDir: String(req.query.raceStorageRelativeDir || '')
|
||||
},
|
||||
lang,
|
||||
returnUrl
|
||||
|
|
|
|||
|
|
@ -1,4 +1,33 @@
|
|||
const legacyAssetBaseUrl = (import.meta.env.VITE_LEGACY_ASSET_BASE_URL || '/legacy-static').replace(/\/$/, '');
|
||||
import { getLegacyBaseUrl } from './legacyUrls.js';
|
||||
|
||||
const localHostnames = new Set(['localhost', '127.0.0.1', '::1']);
|
||||
|
||||
function trimTrailingSlash(value) {
|
||||
return String(value || '').replace(/\/$/, '');
|
||||
}
|
||||
|
||||
function currentHostname() {
|
||||
if (typeof window === 'undefined' || !window.location || !window.location.hostname) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return window.location.hostname.toLowerCase();
|
||||
}
|
||||
|
||||
function resolveLegacyAssetBaseUrl() {
|
||||
const configuredAssetBaseUrl = trimTrailingSlash(import.meta.env.VITE_LEGACY_ASSET_BASE_URL || '');
|
||||
if (configuredAssetBaseUrl) {
|
||||
return configuredAssetBaseUrl;
|
||||
}
|
||||
|
||||
if (localHostnames.has(currentHostname())) {
|
||||
return '/legacy-static';
|
||||
}
|
||||
|
||||
return getLegacyBaseUrl();
|
||||
}
|
||||
|
||||
const legacyAssetBaseUrl = resolveLegacyAssetBaseUrl();
|
||||
|
||||
export function legacyAsset(path) {
|
||||
return `${legacyAssetBaseUrl}${path.startsWith('/') ? path : `/${path}`}`;
|
||||
|
|
|
|||
1120
faceai/authenticated_output.html
Normal file
1120
faceai/authenticated_output.html
Normal file
File diff suppressed because it is too large
Load diff
0
faceai/headers.txt
Normal file
0
faceai/headers.txt
Normal file
359
faceai/login_response.html
Normal file
359
faceai/login_response.html
Normal file
|
|
@ -0,0 +1,359 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<html lang="en"><!-- InstanceBegin template="/Templates/rus.dwt" codeOutsideHTMLIsLocked="false" -->
|
||||
<head>
|
||||
<!-- _inc_lang.jsp -->
|
||||
<script>var webApp='';</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="_js/lang.js"></script>
|
||||
|
||||
|
||||
<input type="hidden" name="lang" id="lang" value="en" />
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<!-- [favicon] begin -->
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/favicon.ico"/>
|
||||
<link rel="icon" type="image/x-icon" href="images/favicon.ico" />
|
||||
<!-- [favicon] end -->
|
||||
<!-- JSP -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- InstanceBeginEditable name="Bean" -->
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- InstanceEndEditable -->
|
||||
<!-- InstanceBeginEditable name="doctitle" -->
|
||||
<title>Regalami Un Sorriso ETS - User Area</title>
|
||||
<!-- InstanceEndEditable -->
|
||||
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- FontAwesome Icons -->
|
||||
<link rel="stylesheet" href="css/font-awesome.min.css">
|
||||
<!-- Roboto Font -->
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i" rel="stylesheet">
|
||||
<!-- Custom styles for this template -->
|
||||
<link href="css/custom-style.css" rel="stylesheet">
|
||||
<!-- Css Datepicker -->
|
||||
<link href="addons/datepicker/css/bootstrap-datepicker.standalone.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href='admin/_V4/_css/ajaxLoading.css'>
|
||||
<!-- InstanceBeginEditable name="head" -->
|
||||
<!-- InstanceEndEditable -->
|
||||
<!-- _inc_cookie.jsp -->
|
||||
|
||||
|
||||
|
||||
<!-- Begin Cookie Consent plugin by Silktide - http://silktide.com/cookieconsent -->
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
window.cookieconsent_options = {
|
||||
"message": "This website or the third-party tools used here make use of cookies necessary for its operation and useful for the purposes described in the cookie policy. To learn more or refuse consent to all or some cookies, please refer to the cookie policy. By closing this banner, scrolling this page, clicking on a link, or continuing to browse otherwise, you consent to the use of cookies.",
|
||||
"dismiss": "Accept",
|
||||
"learnMore": "Cookie Policy",
|
||||
"link": "https://www.regalamiunsorriso.it/privacy-en.html",
|
||||
"theme": "dark-bottom"
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript" src="js/cookieconsent.min.js"></script>
|
||||
<!-- End Cookie Consent plugin -->
|
||||
<!-- _inc_head.jsp -->
|
||||
<!-- Matomo Tag Manager -->
|
||||
<script>
|
||||
var _mtm = window._mtm = window._mtm || [];
|
||||
_mtm.push({'mtm.startTime': (new Date().getTime()), 'event': 'mtm.Start'});
|
||||
(function() {
|
||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||
g.async=true; g.src='https://matomo.acxent.it/js/container_TKh2j1eF.js'; s.parentNode.insertBefore(g,s);
|
||||
})();
|
||||
</script>
|
||||
<!-- End Matomo Tag Manager -->
|
||||
</head>
|
||||
<body>
|
||||
<!-- Page Content -->
|
||||
<!-- InstanceBeginEditable name="main" -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<input name="id_tipoSel" type="hidden" id="id_tipoSel" value="0">
|
||||
|
||||
<!-- facebook init script-->
|
||||
<div id="fb-root"></div>
|
||||
<script>
|
||||
window.fbAsyncInit = function() {
|
||||
FB.init({
|
||||
appId : '5858950737524161',
|
||||
autoLogAppEvents : true,
|
||||
xfbml : true,
|
||||
version : 'v15.0',
|
||||
|
||||
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<script async defer crossorigin="anonymous" src="https://connect.facebook.net/it_IT/sdk.js"></script>
|
||||
|
||||
<!-- Bootstrap core JavaScript -->
|
||||
<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="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>
|
||||
<!-- google sign in -->
|
||||
<script src="https://accounts.google.com/gsi/client" async defer></script>
|
||||
<!-- -->
|
||||
<!-- owl -->
|
||||
<link rel="stylesheet" href="vendor/owl-carousel/owl.carousel.min.css">
|
||||
<link rel="stylesheet" href="vendor/owl-carousel/owl.theme.default.min.css">
|
||||
<!-- sweet alert -->
|
||||
<link rel="stylesheet" type="text/css" href="js/sweetalert/sweetalert.css">
|
||||
<script src="js/sweetalert/sweetalert.min.js"></script>
|
||||
|
||||
|
||||
<a id="top"></a>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar fixed-top navbar-expand-lg navbar-light bg-white fixed-top">
|
||||
<div class="container"> <a class="navbar-brand" href="index.html"><img src="images/layout/regalami-un-sorriso-ets-640.png" alt="Regalami_Un_Sorriso_Ets" width="100"></a>
|
||||
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button>
|
||||
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item"> <a class="nav-link " href="index.html">Home</a> </li>
|
||||
<li class="nav-item"> <a class="nav-link " href="associazione-en.html">Association</a> </li>
|
||||
<li class="nav-item"> <a class="nav-link " href=" rivista+atleticaImmagine-en.html"><img src="pics/atletica2.jpg" class="img-fluid" style="max-width: 110px"></a> </li>
|
||||
<li class="nav-item dropdown"> <a href="#" class="dropdown-toggle nav-link " data-toggle="dropdown">Photo <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu multi-column columns-2" style="overflow-y:scroll">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-6 vertical-divider">
|
||||
<h2>EVENT PHOTOS</h2>
|
||||
<ul class="multi-column-dropdown">
|
||||
|
||||
<li><a href="Carnevale-elenco_eventi-14---1-en.html">Carnival</a></li>
|
||||
|
||||
<li><a href="Defibrillatori-elenco_eventi-20---1-en.html">Defibrillators</a></li>
|
||||
|
||||
<li><a href="Feste-elenco_eventi-12---1-en.html">Parties</a></li>
|
||||
|
||||
<li><a href="Lions-elenco_eventi-4---1-en.html">Lions</a></li>
|
||||
|
||||
<li><a href="Manifestazioni-elenco_eventi-13---1-en.html">Demonstrations</a></li>
|
||||
|
||||
<li><a href="Panathlon-elenco_eventi-3---1-en.html">Panathlon</a></li>
|
||||
|
||||
<li><a href="Viaggi-elenco_eventi-18---1-en.html">Trips</a></li>
|
||||
|
||||
<li><a href="Volantini storici-elenco_eventi-21---1-en.html">Historical flyers</a></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6 ">
|
||||
<h2>SPORTS PHOTOS</h2>
|
||||
<ul class="multi-column-dropdown">
|
||||
|
||||
<li><a href="Basket-elenco_eventi-17---1-en.html">Basketball</a></li>
|
||||
|
||||
<li><a href="Ciclismo-elenco_eventi-6---1-en.html">Bike</a></li>
|
||||
|
||||
<li><a href="Golf-elenco_eventi-15---1-en.html">Golf</a></li>
|
||||
|
||||
<li><a href="Multidiscipline-elenco_eventi-11---1-en.html">Multidiscipline</a></li>
|
||||
|
||||
<li><a href="Podismo-elenco_eventi-5---1-en.html">Running</a></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown show"> <a class="nav-link btn btn-sm btn-warning dropdown-toggle" data-toggle="dropdown" href="#" aria-expanded="true">Archive <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu ">
|
||||
<li>
|
||||
<h2 style="margin: 0px;font-size: 12px;"><a style="padding-left: 0px;" href="gallery1.php">.Fino al 2011.</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2 style="margin: 0px;font-size: 12px;"><a style="padding-left: 0px;" href="gallery2.php">2012-2017</a></h2>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
||||
<a href="dettaglio_clienti-en.html"><img src="https://www.regalamiunsorriso.it/images/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The easiest and safest online payment system!"></a>
|
||||
<!--
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
||||
<input type="hidden" name="cmd" value="_s-xclick">
|
||||
<input type="hidden" name="hosted_button_id" value="4089564">
|
||||
<input type="image" src="https://www.regalamiunsorriso.it/images/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - Il sistema di pagamento online piu' facile e sicuro!">
|
||||
</form>-->
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item dropdown"> <a class="nav-link dropdown-toggle active" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <i class="fa fa-user" aria-hidden="true"></i> My account </a>
|
||||
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> <a class="dropdown-item" href="dettaglio_clienti-en.html"><i class="fa fa-user" aria-hidden="true"></i> Account Detail</a> <a class="dropdown-item" href="586291449-user_logout-en.html"><i class="fa fa-sign-out" aria-hidden="true"></i> Logout</a> </div>
|
||||
</li>
|
||||
<li class="nav-item"> <a class="nav-link" href="https://it-it.facebook.com/pg/Regalami-un-sorriso-ETS-189377806523/community/"><img src="images/FB-f-Logo__blue_29.png" class="img-fluid" alt="Facebook"></a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<ul class="navbar-nav ml-auto" data="langMenu">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="langDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <img src="images/flags/en.png" alt="English" title="English" class="flag"> </a>
|
||||
<div class="dropdown-menu" aria-labelledby="langDropdownMenuLink">
|
||||
|
||||
<a class="dropdown-item" href="index-it.html"> <img src="images/flags/it.png" class="flag" alt="Italiano" title="Italiano"> Italiano </a>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container my-3">
|
||||
<div class="row">
|
||||
<div class="col-lg-6 my-4">
|
||||
<h1 class="my-3">User Area</h1>
|
||||
<div class="col-lg-12 my-12"> <a href="index.html" class="btn btn-primary btn-block"><br>
|
||||
View photos<br>
|
||||
<br>
|
||||
</a> </div>
|
||||
<p class="mt-5 mb-4">HI <strong>Giacomelli Piero</strong><br>
|
||||
Address: <strong>Fosso del Masi n. 24, Prato 59100 (PO)</strong><br>
|
||||
Company belonging to: <strong>REGALAMI UN SORRISO ONLUS </strong><br>
|
||||
Telephone: <strong>3487258208</strong><br>
|
||||
E-mail: <strong><a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5828313d2a371828313d2a373f31393b37353d343431763b3735">[email protected]</a></strong><br>
|
||||
Tax ID code: <strong>GCMPRI58H25G999U</strong><br>
|
||||
Expiration Date: <strong>15/06/2030</strong><br>
|
||||
No. of photos displayed/No. of photos max: <strong>37045/0</strong><br>
|
||||
Number of photos viewed today: <strong>0</strong></p>
|
||||
<p class="">Please verify that the information is correct. For changes, please write to <a href="/cdn-cgi/l/email-protection#74121b001b34041d11061b131d15171b191118181d5a171b19"><span class="__cf_email__" data-cfemail="95f3fae1fad5e5fcf0e7faf2fcf4f6faf8f0f9f9fcbbf6faf8">[email protected]</span></a> or go to <a href="registrazione_utente.html">Edit Data</a> <br>
|
||||
Please note that tacit consent to the accuracy of the member personal data is required.</p>
|
||||
|
||||
<p class="">.Mancano. <strong>1518 </strong> .giorni alla scadenza..<br>
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="col-lg-6 my-4" ">
|
||||
|
||||
</div>
|
||||
<div class="col-md-12 text-danger font-weight-bold"> Login ok </div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- /.container --> <!-- InstanceEndEditable -->
|
||||
|
||||
<!-- Footer -->
|
||||
<!-- inc_footer.jsp -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- sweet alert -->
|
||||
<link rel="stylesheet" type="text/css" href="js/sweetalert/sweetalert.css">
|
||||
<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js" defer></script><script src="js/sweetalert/sweetalert.min.js"></script>
|
||||
|
||||
<footer>
|
||||
<div class="container py-3">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<h4>Contacts</h4>
|
||||
<p>ETS Regalami un sorriso<br>
|
||||
Via Torquato Tasso, 23/C<br>
|
||||
59100 Prato PO<br>
|
||||
CF 92076170486<br>
|
||||
<a href="/cdn-cgi/l/email-protection#e98f869d86a999808c9b868e80888a86848c858580c78a8684"><span class="__cf_email__" data-cfemail="b8ded7ccd7f8c8d1ddcad7dfd1d9dbd7d5ddd4d4d196dbd7d5">[email protected]</span></a><br>
|
||||
<a href="/cdn-cgi/l/email-protection#36445351575a575b5f4358455944445f45597646535518465f534459515f5755595b535a5a5f1855595b"><span class="__cf_email__" data-cfemail="7d0f181a1c111c101408130e120f0f140e123d0d181e530d14180f121a141c1e121018111114531e1210">[email protected]</span></a> <br>
|
||||
Alone <i class="fa fa-whatsapp fa-2x" aria-hidden="true" title="WhatsApp" style="color:#25e47b"></i>: 348 7258209
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<h4>Information</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li><a href="associazione-en.html">Association</a></li>
|
||||
<li><a href="privacy-en.html">Privacy</a></li>
|
||||
<li><a href="cookies-en.html">Cookies</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<p class="text-center text-secondary"><small>Copyright</small></p>
|
||||
<p class="triangle"><a href="#top"><i class="fa fa-arrow-up" aria-hidden="true"></i></a></p>
|
||||
</footer>
|
||||
<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js" defer></script><script src="_js/noTastoDx.js"></script>
|
||||
|
||||
|
||||
<script>
|
||||
$('#datepicker-sport').datepicker({
|
||||
language: "it"
|
||||
});
|
||||
$('#datepicker-eventi').datepicker({
|
||||
language: "it"
|
||||
});
|
||||
|
||||
</script>
|
||||
<!-- InstanceBeginEditable name="lastStuff" --> <!-- InstanceEndEditable -->
|
||||
<div class="modal-loading"></div>
|
||||
</body>
|
||||
<!-- InstanceEnd --></html>
|
||||
|
|
@ -16,7 +16,10 @@
|
|||
"start:processor": "npm run start --workspace @regalami/faceai-processor",
|
||||
"test:e2e": "playwright test",
|
||||
"test:e2e:headed": "playwright test --headed",
|
||||
"test:e2e:install": "playwright install chromium"
|
||||
"test:e2e:install": "playwright install chromium",
|
||||
"test:live": "playwright test -c playwright.live.config.js",
|
||||
"test:live:headed": "playwright test -c playwright.live.config.js --headed",
|
||||
"test:live:install": "playwright install chromium"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.59.1",
|
||||
|
|
|
|||
38
faceai/playwright.live.config.js
Normal file
38
faceai/playwright.live.config.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
const path = require('path');
|
||||
const { defineConfig } = require('@playwright/test');
|
||||
|
||||
const authFile = path.join(__dirname, 'tests/live-site/.auth/user.json');
|
||||
|
||||
module.exports = defineConfig({
|
||||
testDir: './tests/live-site',
|
||||
timeout: 2 * 60 * 1000,
|
||||
expect: {
|
||||
timeout: 20 * 1000
|
||||
},
|
||||
fullyParallel: false,
|
||||
workers: 1,
|
||||
reporter: [['list'], ['html', { open: 'never', outputFolder: 'playwright-report/live-site' }]],
|
||||
outputDir: 'test-results/live-site',
|
||||
use: {
|
||||
baseURL: process.env.LIVE_SITE_BASE_URL || 'https://www.regalamiunsorriso.it',
|
||||
browserName: 'chromium',
|
||||
headless: true,
|
||||
trace: 'retain-on-failure',
|
||||
screenshot: 'only-on-failure',
|
||||
video: 'retain-on-failure'
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
name: 'setup',
|
||||
testMatch: /.*\.setup\.js/
|
||||
},
|
||||
{
|
||||
name: 'live-chromium',
|
||||
dependencies: ['setup'],
|
||||
testIgnore: /.*\.setup\.js/,
|
||||
use: {
|
||||
storageState: authFile
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
47
faceai/probe.js
Normal file
47
faceai/probe.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
const { chromium } = require('playwright');
|
||||
const fs = require('fs');
|
||||
|
||||
async function run() {
|
||||
const browser = await chromium.launch();
|
||||
const context = await browser.newContext();
|
||||
const page = await context.newPage();
|
||||
|
||||
try {
|
||||
const loginUrl = process.env.LIVE_SITE_LOGIN_URL;
|
||||
const raceUrl = process.env.LIVE_SITE_RACE_URL;
|
||||
|
||||
console.log('--- Step 1: Navigating to Login ---');
|
||||
await page.goto(loginUrl, { waitUntil: 'load' });
|
||||
|
||||
console.log('--- Step 2: Filling credentials ---');
|
||||
await page.type('#login', process.env.LIVE_SITE_USERNAME);
|
||||
await page.type('#pwd', process.env.LIVE_SITE_PASSWORD);
|
||||
|
||||
console.log('--- Step 3: Clicking Accedi ---');
|
||||
await page.click('button:has-text("Accedi")');
|
||||
await page.waitForTimeout(5000); // Give it time to process and redirect
|
||||
|
||||
console.log('--- Step 4: Navigating to Race Page ---');
|
||||
const response = await page.goto(raceUrl, { waitUntil: 'load' });
|
||||
|
||||
console.log('Race Page URL:', page.url());
|
||||
console.log('HTTP Status:', response.status());
|
||||
|
||||
const cookies = await context.cookies();
|
||||
const cookieNames = cookies.map(c => c.name);
|
||||
console.log('Cookies:', cookieNames.join(', '));
|
||||
console.log('rus_faceai_identity:', cookieNames.includes('rus_faceai_identity'));
|
||||
console.log('JSESSIONID:', cookieNames.includes('JSESSIONID'));
|
||||
|
||||
const logoutCount = await page.locator('a[href*="logout"]').count();
|
||||
const loginCount = await page.locator('a[href*="login"]').count();
|
||||
console.log('Logout Link Count:', logoutCount);
|
||||
console.log('Login Link Count:', loginCount);
|
||||
|
||||
} catch (err) {
|
||||
console.error('Error occurred:', err.message);
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
run();
|
||||
1100
faceai/response.html
Normal file
1100
faceai/response.html
Normal file
File diff suppressed because it is too large
Load diff
12
faceai/tests/live-site/auth.setup.js
Normal file
12
faceai/tests/live-site/auth.setup.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
const { test } = require('@playwright/test');
|
||||
const {
|
||||
AUTH_FILE,
|
||||
ensureAuthDirectory,
|
||||
performLiveLogin
|
||||
} = require('./live-site-test-utils');
|
||||
|
||||
test('authenticate against the live site', async ({ page }) => {
|
||||
ensureAuthDirectory();
|
||||
await performLiveLogin(page);
|
||||
await page.context().storageState({ path: AUTH_FILE });
|
||||
});
|
||||
121
faceai/tests/live-site/live-race.spec.js
Normal file
121
faceai/tests/live-site/live-race.spec.js
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
const { test, expect } = require('@playwright/test');
|
||||
const {
|
||||
LIVE_FACEAI_BASE_URL,
|
||||
LIVE_SITE_BASE_URL,
|
||||
LIVE_SITE_PORTRAIT_PATH,
|
||||
LIVE_SITE_RACE_URL,
|
||||
LIVE_SITE_RUN_UPLOAD_FLOW,
|
||||
ensureLiveAuthenticatedRacePage,
|
||||
requirePortraitFixture
|
||||
} = require('./live-site-test-utils');
|
||||
|
||||
function escapeRegExp(value) {
|
||||
return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
async function openLiveFaceAi(page) {
|
||||
const consoleErrors = [];
|
||||
|
||||
page.on('console', (message) => {
|
||||
if (message.type() === 'error') {
|
||||
consoleErrors.push(message.text());
|
||||
}
|
||||
});
|
||||
|
||||
await ensureLiveAuthenticatedRacePage(page);
|
||||
await expect(page.locator('h1')).toContainText(/HALF MARATHON FIRENZE|Competitions|Gare/i);
|
||||
|
||||
const launchUrl = await page.evaluate(() => {
|
||||
return typeof buildFaceAiLaunchUrl === 'function' ? buildFaceAiLaunchUrl() : '';
|
||||
});
|
||||
|
||||
expect(launchUrl, 'Expected the legacy race page script to expose a FaceAI handoff URL builder.').toBeTruthy();
|
||||
|
||||
const parsedLaunchUrl = new URL(launchUrl, LIVE_SITE_BASE_URL);
|
||||
expect(parsedLaunchUrl.searchParams.get('raceYear')).toBeTruthy();
|
||||
expect(parsedLaunchUrl.searchParams.get('raceMonthFolder')).toBeTruthy();
|
||||
expect(parsedLaunchUrl.searchParams.get('raceFolder')).toBeTruthy();
|
||||
expect(parsedLaunchUrl.searchParams.get('raceStorageRelativeDir')).toBeTruthy();
|
||||
|
||||
await expect(page.locator('#faceaiLaunchButton')).toBeVisible();
|
||||
await page.locator('#faceaiLaunchButton').click();
|
||||
|
||||
await page.waitForURL(new RegExp(`^${escapeRegExp(LIVE_FACEAI_BASE_URL)}/`), {
|
||||
timeout: 60 * 1000
|
||||
});
|
||||
await expect(page.getByRole('heading', { name: /Trova le tue foto con un selfie|Find your photos with a selfie/i })).toBeVisible();
|
||||
|
||||
return {
|
||||
consoleErrors,
|
||||
launchUrl: parsedLaunchUrl
|
||||
};
|
||||
}
|
||||
|
||||
test('loads a live race page with an authenticated session', async ({ page }) => {
|
||||
await ensureLiveAuthenticatedRacePage(page);
|
||||
|
||||
const cookies = await page.context().cookies(LIVE_SITE_RACE_URL);
|
||||
const faceAiIdentityCookie = cookies.find((cookie) => cookie.name === 'rus_faceai_identity');
|
||||
|
||||
expect(faceAiIdentityCookie, 'Expected the race page to mint the FaceAI identity cookie for the authenticated session.').toBeTruthy();
|
||||
expect(faceAiIdentityCookie.httpOnly).toBe(true);
|
||||
expect(faceAiIdentityCookie.secure).toBe(true);
|
||||
expect(faceAiIdentityCookie.value).toMatch(/\./);
|
||||
});
|
||||
|
||||
test('launches the live FaceAI app with race storage metadata and a styled header', async ({ page }) => {
|
||||
const { consoleErrors, launchUrl } = await openLiveFaceAi(page);
|
||||
|
||||
expect(launchUrl.searchParams.get('raceStorageRelativeDir')).toContain('/');
|
||||
await expect(page.locator('nav.navbar')).toBeVisible();
|
||||
await expect(page.locator('link[data-legacy-href*="bootstrap.min.css"]')).toHaveCount(1);
|
||||
await expect(page.locator('link[data-legacy-href*="custom-style.css"]')).toHaveCount(1);
|
||||
|
||||
const legacyStylesheetHrefs = await page.locator('link[data-legacy-href]').evaluateAll((elements) => {
|
||||
return elements.map((element) => element.getAttribute('href') || '');
|
||||
});
|
||||
|
||||
expect(legacyStylesheetHrefs.some((href) => href.startsWith(`${LIVE_SITE_BASE_URL}/`))).toBe(true);
|
||||
|
||||
const navComputedStyles = await page.locator('nav.navbar').evaluate((element) => {
|
||||
const styles = window.getComputedStyle(element);
|
||||
return {
|
||||
position: styles.position,
|
||||
display: styles.display
|
||||
};
|
||||
});
|
||||
|
||||
expect(navComputedStyles.position).toBe('fixed');
|
||||
expect(navComputedStyles.display).not.toBe('block');
|
||||
expect(consoleErrors.find((entry) => entry.includes('MISSING_RACE_STORAGE')) || '').toBe('');
|
||||
expect(consoleErrors.find((entry) => entry.includes('[FaceAI] Invalid race data:')) || '').toBe('');
|
||||
});
|
||||
|
||||
test.skip(!LIVE_SITE_RUN_UPLOAD_FLOW, 'Set LIVE_SITE_RUN_UPLOAD_FLOW=1 to exercise the live upload flow.');
|
||||
|
||||
test('accepts the supplied portrait image for the live upload flow', async ({ page }) => {
|
||||
requirePortraitFixture();
|
||||
|
||||
await openLiveFaceAi(page);
|
||||
|
||||
const fileInput = page.locator('input[type="file"]');
|
||||
await expect(fileInput).toBeEnabled();
|
||||
await fileInput.setInputFiles(LIVE_SITE_PORTRAIT_PATH);
|
||||
|
||||
await expect(page.locator('.faceai-file-name')).toContainText('test_portrait_1.png');
|
||||
|
||||
const searchResponsePromise = page.waitForResponse((response) => {
|
||||
return response.request().method() === 'POST' && response.url().includes('/api/searches');
|
||||
}, {
|
||||
timeout: 60 * 1000
|
||||
});
|
||||
|
||||
await page.getByRole('button', { name: /Avvia ricerca Face ID|Start Face ID search/i }).click();
|
||||
|
||||
const searchResponse = await searchResponsePromise;
|
||||
expect(searchResponse.ok(), 'Expected the live upload flow to create a FaceAI search successfully.').toBe(true);
|
||||
|
||||
const searchPayload = await searchResponse.json();
|
||||
expect(searchPayload.id || searchPayload.searchId, 'Expected the search creation response to include a search identifier.').toBeTruthy();
|
||||
await expect(page.locator('.faceai-feedback')).not.toContainText(/Impossibile|Unable|Errore|Error/i);
|
||||
});
|
||||
123
faceai/tests/live-site/live-site-test-utils.js
Normal file
123
faceai/tests/live-site/live-site-test-utils.js
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { expect } = require('@playwright/test');
|
||||
|
||||
const WORKSPACE_ROOT = path.resolve(__dirname, '..', '..', '..');
|
||||
const LIVE_SITE_BASE_URL = process.env.LIVE_SITE_BASE_URL || 'https://www.regalamiunsorriso.it';
|
||||
const LIVE_SITE_LOGIN_URL = process.env.LIVE_SITE_LOGIN_URL || `${LIVE_SITE_BASE_URL}/login_clienti-it.html`;
|
||||
const LIVE_SITE_RACE_URL = process.env.LIVE_SITE_RACE_URL || `${LIVE_SITE_BASE_URL}/42%20HALF%20MARATHON%20FIRENZE_gara-1018545---96-1.html`;
|
||||
const LIVE_FACEAI_BASE_URL = process.env.LIVE_FACEAI_BASE_URL || 'https://ai.regalamiunsorriso.it';
|
||||
const LIVE_SITE_USERNAME = process.env.LIVE_SITE_USERNAME || '';
|
||||
const LIVE_SITE_PASSWORD = process.env.LIVE_SITE_PASSWORD || '';
|
||||
const LIVE_SITE_PORTRAIT_PATH = process.env.LIVE_SITE_PORTRAIT_PATH || path.join(WORKSPACE_ROOT, 'test_pkl', 'live', 'test_portrait_1.png');
|
||||
const LIVE_SITE_RUN_UPLOAD_FLOW = process.env.LIVE_SITE_RUN_UPLOAD_FLOW === '1';
|
||||
const AUTH_FILE = path.join(__dirname, '.auth', 'user.json');
|
||||
|
||||
function ensureAuthDirectory() {
|
||||
fs.mkdirSync(path.dirname(AUTH_FILE), { recursive: true });
|
||||
}
|
||||
|
||||
function requireCredentials() {
|
||||
if (!LIVE_SITE_USERNAME || !LIVE_SITE_PASSWORD) {
|
||||
throw new Error('LIVE_SITE_USERNAME and LIVE_SITE_PASSWORD must be set before running the live-site Playwright suite.');
|
||||
}
|
||||
}
|
||||
|
||||
async function dismissCookieBanner(page) {
|
||||
const cookieButton = page.getByRole('button', { name: /^(Accetto|Accept)$/i });
|
||||
if (await cookieButton.count()) {
|
||||
await cookieButton.first().click({ timeout: 5000 }).catch(() => {});
|
||||
return;
|
||||
}
|
||||
|
||||
const fallbackButton = page.locator('.cc-btn, .cc-dismiss, .cc-allow').filter({ hasText: /Accetto|Accept/i });
|
||||
if (await fallbackButton.count()) {
|
||||
await fallbackButton.first().click({ timeout: 5000 }).catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
function loginSubmitLocator(page) {
|
||||
return page.locator('a.btn').filter({ hasText: /Accedi|Sign in/i }).first();
|
||||
}
|
||||
|
||||
async function performLiveLogin(page) {
|
||||
requireCredentials();
|
||||
|
||||
await page.goto(LIVE_SITE_LOGIN_URL, { waitUntil: 'domcontentloaded' });
|
||||
await dismissCookieBanner(page);
|
||||
await page.locator('#login').fill(LIVE_SITE_USERNAME);
|
||||
await page.locator('#pwd').fill(LIVE_SITE_PASSWORD);
|
||||
await loginSubmitLocator(page).click();
|
||||
await waitForLoggedInUi(page);
|
||||
}
|
||||
|
||||
async function waitForLoggedInUi(page) {
|
||||
const accountMenu = page.locator('#navbarDropdownMenuLink');
|
||||
const accountLink = page.locator('a[href*="dettaglio_clienti"]');
|
||||
const logoutLink = page.locator('a[href*="user_logout"]');
|
||||
|
||||
await expect.poll(async () => {
|
||||
if (await accountMenu.count() && await accountMenu.first().isVisible().catch(() => false)) {
|
||||
return 'account-menu';
|
||||
}
|
||||
if (await accountLink.count() && await accountLink.first().isVisible().catch(() => false)) {
|
||||
return 'account-link';
|
||||
}
|
||||
if (await logoutLink.count() && await logoutLink.first().isVisible().catch(() => false)) {
|
||||
return 'logout-link';
|
||||
}
|
||||
return '';
|
||||
}, {
|
||||
timeout: 30 * 1000,
|
||||
message: 'Expected the logged-in account UI to appear after authenticating.'
|
||||
}).not.toBe('');
|
||||
}
|
||||
|
||||
async function expectRacePageLoaded(page) {
|
||||
await expect(page.locator('form[onsubmit="return searching()"]')).toBeVisible();
|
||||
await expect(page.locator('#id_gara')).toHaveValue(/\d+/);
|
||||
await expect(page.locator('script[src*="_js/rus-ecom-240621.js"]')).toHaveCount(1);
|
||||
}
|
||||
|
||||
async function ensureLiveAuthenticatedRacePage(page) {
|
||||
await page.goto(LIVE_SITE_RACE_URL, { waitUntil: 'domcontentloaded' });
|
||||
await dismissCookieBanner(page);
|
||||
|
||||
try {
|
||||
await waitForLoggedInUi(page);
|
||||
} catch (error) {
|
||||
await performLiveLogin(page);
|
||||
await page.goto(LIVE_SITE_RACE_URL, { waitUntil: 'domcontentloaded' });
|
||||
await dismissCookieBanner(page);
|
||||
await waitForLoggedInUi(page);
|
||||
}
|
||||
|
||||
await expectRacePageLoaded(page);
|
||||
}
|
||||
|
||||
function requirePortraitFixture() {
|
||||
if (!fs.existsSync(LIVE_SITE_PORTRAIT_PATH)) {
|
||||
throw new Error(`LIVE_SITE_PORTRAIT_PATH does not exist: ${LIVE_SITE_PORTRAIT_PATH}`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
AUTH_FILE,
|
||||
LIVE_FACEAI_BASE_URL,
|
||||
LIVE_SITE_BASE_URL,
|
||||
LIVE_SITE_LOGIN_URL,
|
||||
LIVE_SITE_PASSWORD,
|
||||
LIVE_SITE_PORTRAIT_PATH,
|
||||
LIVE_SITE_RACE_URL,
|
||||
LIVE_SITE_RUN_UPLOAD_FLOW,
|
||||
LIVE_SITE_USERNAME,
|
||||
dismissCookieBanner,
|
||||
ensureLiveAuthenticatedRacePage,
|
||||
ensureAuthDirectory,
|
||||
expectRacePageLoaded,
|
||||
loginSubmitLocator,
|
||||
performLiveLogin,
|
||||
requirePortraitFixture,
|
||||
requireCredentials,
|
||||
waitForLoggedInUi
|
||||
};
|
||||
45
faceai/tmp-live-state-inspection.json
Normal file
45
faceai/tmp-live-state-inspection.json
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"cookies": [
|
||||
{
|
||||
"name": "JSESSIONID",
|
||||
"value": "C78CCBD1771ACB52852817531958E96D",
|
||||
"domain": "www.regalamiunsorriso.it",
|
||||
"path": "/",
|
||||
"expires": -1,
|
||||
"httpOnly": true,
|
||||
"secure": false,
|
||||
"sameSite": "Lax"
|
||||
},
|
||||
{
|
||||
"name": "_pk_id.6.42c1",
|
||||
"value": "5710c1018f76b02c.1776585670.",
|
||||
"domain": "www.regalamiunsorriso.it",
|
||||
"path": "/",
|
||||
"expires": 1810540870,
|
||||
"httpOnly": false,
|
||||
"secure": false,
|
||||
"sameSite": "Lax"
|
||||
},
|
||||
{
|
||||
"name": "_pk_ses.6.42c1",
|
||||
"value": "1",
|
||||
"domain": "www.regalamiunsorriso.it",
|
||||
"path": "/",
|
||||
"expires": 1776587471,
|
||||
"httpOnly": false,
|
||||
"secure": false,
|
||||
"sameSite": "Lax"
|
||||
},
|
||||
{
|
||||
"name": "g_state",
|
||||
"value": "{\"i_l\":0,\"i_ll\":1776585670175,\"i_b\":\"TwramoDGp33YsAyHyO2OJCLtRobG3bzu5wR3/nYmZ0E\",\"i_e\":{\"enable_itp_optimization\":0},\"i_et\":1776585670056}",
|
||||
"domain": "www.regalamiunsorriso.it",
|
||||
"path": "/",
|
||||
"expires": 1792137670,
|
||||
"httpOnly": false,
|
||||
"secure": false,
|
||||
"sameSite": "Lax"
|
||||
}
|
||||
],
|
||||
"origins": []
|
||||
}
|
||||
|
|
@ -10,20 +10,17 @@ All files in this rollout are deployed from the current working tree.
|
|||
|
||||
## New Files
|
||||
|
||||
- None in this rollout.
|
||||
- `www/_inc_faceai_identity.jsp`
|
||||
- `www/_js/lang.js`
|
||||
|
||||
## Updated Files
|
||||
|
||||
- `www/faceai_config.php`
|
||||
- `www/faceai_handoff.php`
|
||||
- `www/faceai_return.php`
|
||||
- `www/fotoCR.jsp`
|
||||
- `www/fotoCR-en.jsp`
|
||||
- `www/fotoCR.jsp`
|
||||
|
||||
## Excluded Files
|
||||
|
||||
- `www/faceai_simulator.php`
|
||||
- `www/faceai_simulator_view.php`
|
||||
- None in this rollout.
|
||||
|
||||
## Remote Copy Target
|
||||
|
||||
|
|
@ -31,7 +28,7 @@ All files in this rollout are deployed from the current working tree.
|
|||
- Remote host: `marco@83.149.164.4:410`
|
||||
- Remote staging path: `/home/marco/regalamiunsorriso/incoming/www`
|
||||
- Remote live path: `/home/sites/regalamiunsorriso/www`
|
||||
- Total files in this manifest: `5`
|
||||
- Total files in this manifest: `4`
|
||||
|
||||
## Transfer Method
|
||||
|
||||
|
|
|
|||
BIN
test_pkl/live/test_portrait_1.png
Normal file
BIN
test_pkl/live/test_portrait_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 166 KiB |
260
www/_inc_faceai_identity.jsp
Normal file
260
www/_inc_faceai_identity.jsp
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
<%@ page language="java" import="java.nio.charset.StandardCharsets" %>
|
||||
<%@ page language="java" import="java.util.Base64" %>
|
||||
<%@ page language="java" import="java.lang.reflect.Method" %>
|
||||
<%@ page language="java" import="javax.crypto.Mac" %>
|
||||
<%@ page language="java" import="javax.crypto.spec.SecretKeySpec" %>
|
||||
<%!
|
||||
private String faceAiCookieEnv(String key, String defaultValue) {
|
||||
String value = System.getenv(key);
|
||||
if (value == null || value.trim().length() == 0) {
|
||||
value = System.getProperty(key, defaultValue);
|
||||
}
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
value = value.trim();
|
||||
return value.length() == 0 ? defaultValue : value;
|
||||
}
|
||||
|
||||
private String faceAiBase64Url(byte[] value) {
|
||||
return Base64.getUrlEncoder().withoutPadding().encodeToString(value);
|
||||
}
|
||||
|
||||
private String faceAiJsonEscape(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 faceAiInvoke(Object bean, String methodName) {
|
||||
if (bean == null || methodName == null || methodName.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
Method method = bean.getClass().getMethod(methodName, new Class[0]);
|
||||
return method.invoke(bean, new Object[0]);
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private long faceAiUserId(Object user) {
|
||||
Object value = faceAiInvoke(user, "getId_users");
|
||||
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 faceAiUserString(Object user, String methodName) {
|
||||
Object value = faceAiInvoke(user, methodName);
|
||||
return value == null ? "" : String.valueOf(value).trim();
|
||||
}
|
||||
|
||||
private boolean faceAiUserDaRinnovare(Object user) {
|
||||
Object value = faceAiInvoke(user, "isDaRinnovare");
|
||||
return value instanceof Boolean ? ((Boolean) value).booleanValue() : false;
|
||||
}
|
||||
|
||||
private String faceAiCookieDisplayName(Object user) {
|
||||
String nome = faceAiUserString(user, "getNome");
|
||||
String cognome = faceAiUserString(user, "getCognome");
|
||||
String displayName = (nome + " " + cognome).trim();
|
||||
if (displayName.length() > 0) {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
String email = faceAiUserString(user, "getEMail");
|
||||
if (email.length() > 0) {
|
||||
return email;
|
||||
}
|
||||
|
||||
return String.valueOf(faceAiUserId(user));
|
||||
}
|
||||
|
||||
private String faceAiIdentityToken(Object user, String secret, long expiresAt) throws Exception {
|
||||
String email = faceAiUserString(user, "getEMail");
|
||||
String membershipStatus = faceAiUserDaRinnovare(user) ? "inactive" : "active";
|
||||
String payload = "{"
|
||||
+ "\"type\":\"legacy-identity\","
|
||||
+ "\"userId\":\"" + faceAiJsonEscape(String.valueOf(faceAiUserId(user))) + "\","
|
||||
+ "\"displayName\":\"" + faceAiJsonEscape(faceAiCookieDisplayName(user)) + "\","
|
||||
+ "\"email\":\"" + faceAiJsonEscape(email) + "\","
|
||||
+ "\"membershipStatus\":\"" + membershipStatus + "\","
|
||||
+ "\"expiresAt\":" + expiresAt
|
||||
+ "}";
|
||||
|
||||
String body = faceAiBase64Url(payload.getBytes(StandardCharsets.UTF_8));
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
|
||||
String signature = faceAiBase64Url(mac.doFinal(body.getBytes(StandardCharsets.UTF_8)));
|
||||
return body + "." + signature;
|
||||
}
|
||||
|
||||
private boolean faceAiRequestIsSecure(javax.servlet.http.HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
return false;
|
||||
}
|
||||
if (request.isSecure()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String forwardedProto = request.getHeader("X-Forwarded-Proto");
|
||||
if (forwardedProto != null && "https".equalsIgnoreCase(forwardedProto.trim())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String frontEndHttps = request.getHeader("Front-End-Https");
|
||||
return frontEndHttps != null && "on".equalsIgnoreCase(frontEndHttps.trim());
|
||||
}
|
||||
|
||||
private void faceAiWriteCookieHeader(javax.servlet.http.HttpServletResponse response, String cookieName, String cookieValue, int maxAgeSeconds, boolean secureCookie) {
|
||||
StringBuilder headerValue = new StringBuilder();
|
||||
headerValue.append(cookieName).append('=').append(cookieValue == null ? "" : cookieValue);
|
||||
headerValue.append("; Max-Age=").append(maxAgeSeconds);
|
||||
headerValue.append("; Path=/; HttpOnly; SameSite=Lax");
|
||||
if (secureCookie) {
|
||||
headerValue.append("; Secure");
|
||||
}
|
||||
response.addHeader("Set-Cookie", headerValue.toString());
|
||||
}
|
||||
|
||||
private Object faceAiResolveUser(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];
|
||||
if (candidate != null && faceAiUserId(candidate) > 0L) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Object faceAiResolveUserFromSession(javax.servlet.jsp.PageContext pageContext) {
|
||||
if (pageContext == null || pageContext.getSession() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object loginUserId = pageContext.getSession().getAttribute("loginUser_id");
|
||||
long resolvedLoginUserId = 0L;
|
||||
if (loginUserId instanceof Number) {
|
||||
resolvedLoginUserId = ((Number) loginUserId).longValue();
|
||||
} else if (loginUserId != null) {
|
||||
try {
|
||||
resolvedLoginUserId = Long.parseLong(String.valueOf(loginUserId));
|
||||
} catch (NumberFormatException ignored) {
|
||||
resolvedLoginUserId = 0L;
|
||||
}
|
||||
}
|
||||
|
||||
if (resolvedLoginUserId <= 0L) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object sessionUser = pageContext.findAttribute("utenteLogon");
|
||||
if (sessionUser == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (faceAiUserId(sessionUser) == resolvedLoginUserId) {
|
||||
return sessionUser;
|
||||
}
|
||||
|
||||
try {
|
||||
Method findByPrimaryKey = sessionUser.getClass().getMethod("findByPrimaryKey", long.class);
|
||||
findByPrimaryKey.invoke(sessionUser, Long.valueOf(resolvedLoginUserId));
|
||||
} catch (NoSuchMethodException missingPrimitiveOverload) {
|
||||
try {
|
||||
Method findByPrimaryKey = sessionUser.getClass().getMethod("findByPrimaryKey", Long.class);
|
||||
findByPrimaryKey.invoke(sessionUser, new Long(resolvedLoginUserId));
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return faceAiUserId(sessionUser) > 0L ? sessionUser : null;
|
||||
}
|
||||
%>
|
||||
<%
|
||||
String faceAiCookieName = faceAiCookieEnv("FACEAI_IDENTITY_COOKIE", "rus_faceai_identity");
|
||||
String faceAiCookieSecret = faceAiCookieEnv("FACEAI_SHARED_SECRET", "disagio-spaghetti-science-lol-boh");
|
||||
Object faceAiRequestUser = pageContext.findAttribute("user");
|
||||
Object faceAiSessionUser = pageContext.findAttribute("utenteLogon");
|
||||
long faceAiRequestUserId = faceAiUserId(faceAiRequestUser);
|
||||
long faceAiSessionUserId = faceAiUserId(faceAiSessionUser);
|
||||
Object faceAiCookieUser = faceAiRequestUserId > 0L ? faceAiRequestUser : (faceAiSessionUserId > 0L ? faceAiSessionUser : faceAiResolveUserFromSession(pageContext));
|
||||
boolean faceAiSecureCookie = faceAiRequestIsSecure(request);
|
||||
|
||||
if (faceAiFeatureEnabled && faceAiCookieUser != null && faceAiUserId(faceAiCookieUser) > 0L) {
|
||||
long faceAiExpiresAt = System.currentTimeMillis() + (30L * 60L * 1000L);
|
||||
try {
|
||||
String faceAiToken = faceAiIdentityToken(faceAiCookieUser, faceAiCookieSecret, faceAiExpiresAt);
|
||||
faceAiWriteCookieHeader(response, faceAiCookieName, faceAiToken, 30 * 60, faceAiSecureCookie);
|
||||
} catch (Exception faceAiIdentityError) {
|
||||
faceAiWriteCookieHeader(response, faceAiCookieName, "", 0, faceAiSecureCookie);
|
||||
log("Unable to mint FaceAI identity cookie", faceAiIdentityError);
|
||||
}
|
||||
} else {
|
||||
faceAiWriteCookieHeader(response, faceAiCookieName, "", 0, faceAiSecureCookie);
|
||||
}
|
||||
%>
|
||||
55
www/_js/lang.js
Normal file
55
www/_js/lang.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// JavaScript Document
|
||||
////////////////////////////////////////////
|
||||
// gestione cambio lingua
|
||||
////////////////////////////////////////////
|
||||
var userLang = navigator.language || navigator.userLanguage;
|
||||
console.log(userLang);
|
||||
|
||||
function changeLang(lang) {
|
||||
var page = window.location.href;
|
||||
var idx = page.lastIndexOf(".");
|
||||
|
||||
if (idx > 0) {
|
||||
var ext = page.substring(idx, page.length);
|
||||
|
||||
if (ext.indexOf("eu") >= 0 || ext.indexOf("com") >= 0 || ext.indexOf("net") >= 0 || ext.indexOf("it") >= 0) {
|
||||
ext = "";
|
||||
var page1 = page;
|
||||
}
|
||||
else
|
||||
|
||||
var page1 = page.substring(0, idx);
|
||||
}
|
||||
else {
|
||||
// caso di pagina root www.xxxx.com/
|
||||
var ext = "";
|
||||
var page1 = page;
|
||||
}
|
||||
// 1 se ho pagine del tipo xxx.html --> aggiungo -lang.html
|
||||
// 2 se ho pagine del tipo xxx_xxx-xxx-xxx-.html --> sostituisco l'ultima parte con xxx-lang.html
|
||||
// 3 se ho pagine del tipo xxx_xxx-xx-xx-lang.html --> sostituisco l'ultima parte
|
||||
// 4 se non ho estensione sono nella root e finisce con /(www.xxxx.com/) --> vado su index-lang
|
||||
// 5 altrimenti vado su index-lang.jsp
|
||||
// 6 caso Ordine.abl --> ritorno alla home
|
||||
|
||||
if (ext == ".abl") {
|
||||
theSvlt = "index-" + lang + ".html";
|
||||
}
|
||||
else if (ext == "") {
|
||||
theSvlt = page1 + "index-" + lang + ".html";
|
||||
}
|
||||
else if (page1.lastIndexOf("-") == (page1.length - 1)) {
|
||||
theSvlt = page1 + lang + ext;
|
||||
}
|
||||
else if (page1.lastIndexOf("-") == (page1.length - 3)) {
|
||||
theSvlt = page1.substring(0, page1.length - 2) + lang + ext;
|
||||
}
|
||||
else if (page1.substring(page1.length - 1, page1.length) != "-") {
|
||||
theSvlt = page1 + "-" + lang + ext;
|
||||
}
|
||||
else {
|
||||
theSvlt = "index-" + lang + ".jsp";
|
||||
}
|
||||
|
||||
location.href = theSvlt;
|
||||
}
|
||||
|
|
@ -258,6 +258,7 @@ function buildFaceAiLaunchUrl() {
|
|||
var raceYear = getFaceAiStorageValue("faceAiRaceYear", "year");
|
||||
var raceMonthFolder = getFaceAiStorageValue("faceAiRaceMonthFolder", "monthFolder");
|
||||
var raceFolder = getFaceAiStorageValue("faceAiRaceFolder", "raceFolder");
|
||||
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;
|
||||
|
|
@ -268,6 +269,7 @@ function buildFaceAiLaunchUrl() {
|
|||
"raceYear=" + encodeURIComponent(raceYear),
|
||||
"raceMonthFolder=" + encodeURIComponent(raceMonthFolder),
|
||||
"raceFolder=" + encodeURIComponent(raceFolder),
|
||||
"raceStorageRelativeDir=" + encodeURIComponent(raceStorageRelativeDir),
|
||||
"lang=" + encodeURIComponent(lang),
|
||||
"returnUrl=" + encodeURIComponent(returnUrl)
|
||||
];
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ try {
|
|||
$raceYear = faceai_request_value('raceYear');
|
||||
$raceMonthFolder = faceai_request_value('raceMonthFolder');
|
||||
$raceFolder = faceai_request_value('raceFolder');
|
||||
$raceStorageRelativeDir = faceai_request_value('raceStorageRelativeDir');
|
||||
$lang = faceai_request_value('lang', 'it');
|
||||
$returnUrl = faceai_request_value('returnUrl');
|
||||
|
||||
|
|
@ -45,11 +46,12 @@ try {
|
|||
'name' => $raceName !== '' ? $raceName : $raceId
|
||||
);
|
||||
|
||||
if ($raceYear !== '' && $raceMonthFolder !== '' && $raceFolder !== '') {
|
||||
if ($raceYear !== '' || $raceMonthFolder !== '' || $raceFolder !== '' || $raceStorageRelativeDir !== '') {
|
||||
$racePayload['storage'] = array(
|
||||
'year' => $raceYear,
|
||||
'monthFolder' => $raceMonthFolder,
|
||||
'raceFolder' => strtoupper(trim($raceFolder))
|
||||
'raceFolder' => strtoupper(trim($raceFolder)),
|
||||
'relativeDir' => $raceStorageRelativeDir
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
<%@ taglib uri="/WEB-INF/cc.tld" prefix="cc" %>
|
||||
<html lang="<%=lang%>"><!-- InstanceBegin template="/Templates/rus.dwt" codeOutsideHTMLIsLocked="false" -->
|
||||
<head>
|
||||
<jsp:include page="_inc_lang.jsp" flush="true" />
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
|
@ -57,6 +56,10 @@ if (faceAiFeatureEnabledValue == null || faceAiFeatureEnabledValue.trim().length
|
|||
}
|
||||
String faceAiFeatureEnabledNormalized = faceAiFeatureEnabledValue != null ? faceAiFeatureEnabledValue.trim() : "";
|
||||
boolean faceAiFeatureEnabled = !("0".equals(faceAiFeatureEnabledNormalized) || "false".equalsIgnoreCase(faceAiFeatureEnabledNormalized) || "no".equalsIgnoreCase(faceAiFeatureEnabledNormalized) || "off".equalsIgnoreCase(faceAiFeatureEnabledNormalized));
|
||||
%>
|
||||
<%@ include file="_inc_faceai_identity.jsp" %>
|
||||
<jsp:include page="_inc_lang.jsp" flush="true" />
|
||||
<%
|
||||
java.util.Date faceAiRaceDate = CR.getGara().getDataGaraInizio();
|
||||
String faceAiRacePathBase = CR.getGara().getPathBase() != null ? CR.getGara().getPathBase().trim() : "";
|
||||
String faceAiRaceYear = "";
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
<%@ taglib uri="/WEB-INF/cc.tld" prefix="cc" %>
|
||||
<html lang="<%=lang%>"><!-- InstanceBegin template="/Templates/rus.dwt" codeOutsideHTMLIsLocked="false" -->
|
||||
<head>
|
||||
<jsp:include page="_inc_lang.jsp" flush="true" />
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
|
@ -57,6 +56,10 @@ if (faceAiFeatureEnabledValue == null || faceAiFeatureEnabledValue.trim().length
|
|||
}
|
||||
String faceAiFeatureEnabledNormalized = faceAiFeatureEnabledValue != null ? faceAiFeatureEnabledValue.trim() : "";
|
||||
boolean faceAiFeatureEnabled = !("0".equals(faceAiFeatureEnabledNormalized) || "false".equalsIgnoreCase(faceAiFeatureEnabledNormalized) || "no".equalsIgnoreCase(faceAiFeatureEnabledNormalized) || "off".equalsIgnoreCase(faceAiFeatureEnabledNormalized));
|
||||
%>
|
||||
<%@ include file="_inc_faceai_identity.jsp" %>
|
||||
<jsp:include page="_inc_lang.jsp" flush="true" />
|
||||
<%
|
||||
java.util.Date faceAiRaceDate = CR.getGara().getDataGaraInizio();
|
||||
String faceAiRacePathBase = CR.getGara().getPathBase() != null ? CR.getGara().getPathBase().trim() : "";
|
||||
String faceAiRaceYear = "";
|
||||
|
|
|
|||
BIN
www_staged.tar
Normal file
BIN
www_staged.tar
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue