Защита загрузок от переходов по меню была добавлена
Этот коммит содержится в:
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python3
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
app_dir = Path(sys.argv[1]).resolve().parent if len(sys.argv) > 1 else Path('/opt/virtuality/web')
|
||||
templates_dir = app_dir / 'templates'
|
||||
changed = []
|
||||
|
||||
guard_script = r'''
|
||||
|
||||
function setUploadNavigationGuard(active) {
|
||||
window.virtualityUploadActive = Boolean(active);
|
||||
document.body.classList.toggle('upload-locked', window.virtualityUploadActive);
|
||||
}
|
||||
|
||||
window.addEventListener('beforeunload', function (event) {
|
||||
if (!window.virtualityUploadActive) return;
|
||||
event.preventDefault();
|
||||
event.returnValue = 'Идёт загрузка файла. Переход остановит передачу.';
|
||||
return event.returnValue;
|
||||
});
|
||||
|
||||
document.addEventListener('click', function (event) {
|
||||
if (!window.virtualityUploadActive) return;
|
||||
const target = event.target.closest('a, button, input[type="submit"]');
|
||||
if (!target) return;
|
||||
if (target.id === 'iso-upload-button' || target.id === 'disk-upload-button') return;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
alert('Идёт загрузка файла. Дождись завершения или нажми «Отменить загрузку». Переход по меню сейчас заблокирован, чтобы файл не оборвался.');
|
||||
}, true);
|
||||
|
||||
document.addEventListener('submit', function (event) {
|
||||
if (!window.virtualityUploadActive) return;
|
||||
if (event.target && (event.target.id === 'iso-upload-form' || event.target.id === 'disk-upload-form')) return;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
alert('Идёт загрузка файла. Дождись завершения или нажми «Отменить загрузку».');
|
||||
}, true);
|
||||
'''
|
||||
|
||||
|
||||
def patch_template(path: Path, active_token: str, form_id: str) -> None:
|
||||
if not path.exists():
|
||||
return
|
||||
text = path.read_text()
|
||||
original = text
|
||||
|
||||
if 'function setUploadNavigationGuard(active)' not in text:
|
||||
marker = ' function bytesText(bytes) {'
|
||||
if marker not in text:
|
||||
raise SystemExit(f'bytesText marker not found in {path}')
|
||||
text = text.replace(marker, guard_script + '\n' + marker, 1)
|
||||
|
||||
text = text.replace(' uploadActive = active;\n', ' uploadActive = active;\n setUploadNavigationGuard(active);\n')
|
||||
|
||||
# During server-side post-processing after upload, file transfer is done, so page navigation is safe again.
|
||||
text = text.replace(" window.location.href = '/iso';", " setUploadNavigationGuard(false);\n window.location.href = '/iso';")
|
||||
text = text.replace(" window.location.href = '/disk-images';", " setUploadNavigationGuard(false);\n window.location.href = '/disk-images';")
|
||||
|
||||
# Conversion polling is not an active browser upload anymore; allow navigation while backend operation continues.
|
||||
text = text.replace(" setUploadMode(false);\n fileInput.disabled = true;", " setUploadMode(false);\n setUploadNavigationGuard(false);\n fileInput.disabled = true;")
|
||||
|
||||
if text != original:
|
||||
path.write_text(text)
|
||||
changed.append(str(path))
|
||||
|
||||
patch_template(templates_dir / 'iso.html', 'iso-upload-button', 'iso-upload-form')
|
||||
patch_template(templates_dir / 'disk_images.html', 'disk-upload-button', 'disk-upload-form')
|
||||
|
||||
print('upload navigation guard patch applied:')
|
||||
for item in changed or ['already applied']:
|
||||
print(f'- {item}')
|
||||
Ссылка в новой задаче
Block a user