Skip to content

When downloading events from the Events page. If the download file was deleted after downloading, we make the download link for the file inactive #4861

Merged
connortechnology merged 15 commits into
ZoneMinder:masterfrom
IgorA100:patch-731409
Jun 10, 2026

Conversation

@IgorA100

Copy link
Copy Markdown
Contributor

In continuation: #4488

IgorA100 added 5 commits May 30, 2026 23:02
Added the DIR_EXPORTS_DOWNLOAD constant from PHP to JS
Added a style for "#downloadModal a.disabled" on the Events page
@IgorA100 IgorA100 marked this pull request as ready for review May 30, 2026 20:38
@IgorA100

Copy link
Copy Markdown
Contributor Author

Please verify.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the Events-page export/download workflow (from #4488) by polling the server for whether generated temporary download files still exist, and visually disabling download links in the modal once the files have been deleted.

Changes:

  • Exposes DIR_EXPORTS_DOWNLOAD to the browser and uses it client-side to build file paths for polling.
  • Adds client-side polling in export.js to periodically check file existence and mark download links as disabled.
  • Adds a new AJAX action (file_existence_check) to return file_exists() results, plus CSS styling for disabled download links.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

File Description
web/skins/classic/js/skin.js.php Exposes DIR_EXPORTS_DOWNLOAD as a JS constant (server filesystem path).
web/skins/classic/js/export.js Adds polling + UI disabling logic for download links after file deletion.
web/skins/classic/css/base/views/events.css Styles disabled download links in the download modal.
web/ajax/event.php Adds file_existence_check AJAX endpoint to check file presence.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread web/ajax/event.php
Comment thread web/skins/classic/js/export.js Outdated
Comment thread web/skins/classic/js/export.js
Comment thread web/skins/classic/js/export.js
Comment thread web/skins/classic/js/skin.js.php Outdated
Comment thread web/skins/classic/css/base/views/events.css
@IgorA100 IgorA100 marked this pull request as draft May 31, 2026 19:02
- When making an AJAX request, we pass an array of file paths relative to DIR_EXPORTS_DOWNLOAD , not absolute ones.
- Check $fileName for a non-empty string.
- Clear fileExistencePollingInterval if it exists before calling again.
- More correctly retrieve parameters from the "el.href" string using "new URL(el.href)".
- Disabled the cursor for "a.disabled".
@IgorA100 IgorA100 marked this pull request as ready for review June 1, 2026 09:48
@IgorA100

IgorA100 commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

Please recheck.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

Comment thread web/skins/classic/js/export.js
Comment thread web/skins/classic/js/export.js Outdated
Comment thread web/skins/classic/js/export.js Outdated
Comment thread web/ajax/event.php
Comment thread web/skins/classic/js/export.js
@IgorA100

IgorA100 commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

Please recheck.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

Comment thread web/skins/classic/js/export.js
Comment thread web/skins/classic/js/export.js Outdated
Comment thread web/ajax/event.php Outdated
@IgorA100 IgorA100 marked this pull request as draft June 5, 2026 08:12
IgorA100 added 3 commits June 5, 2026 11:49
…revious one hasn't yet completed. (export.js)

And also compare the full relative path (export_root/file, or just file when there's no export_root) against the server response entry.
Well, that's why you can't use curly braces for a single-line expression...
Saves three times the space...
@IgorA100 IgorA100 marked this pull request as ready for review June 5, 2026 09:10
@IgorA100

IgorA100 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

Please recheck.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

web/skins/classic/js/export.js:46

  • fileName is inserted using $j(nodeCopy).html(...), which treats it as HTML. Since the filename can include monitor names/user-controlled characters, this can introduce an XSS vector in the download modal. Use .text(...) (or build DOM nodes) and insert the <br> as a separate element instead of concatenating HTML.
          nodeCopy = downloadLink.cloneNode(true);
          nodeCopy.id = 'downloadLink'+i;
          downloadLink.parentNode.insertBefore(nodeCopy, downloadLink.nextSibling);
          $j(nodeCopy).html('<br>' + (i+1) + '. Download ' + '"' + fileName + '"');
          $j(nodeCopy).attr("href", thisUrl + file);

web/skins/classic/js/export.js:147

  • fileExistencePollingInterval is only cleared when a new exportResponse() arrives. If the user clicks "Generate Download" again while the previous polling is still active (e.g., while the new export request is running), the old interval can keep polling and disabling links based on stale filenames. Clear the existing interval at the start of exportEvent() to stop stale polling immediately.
function exportEvent() {
  $j('#exportProgress').html('<span class="spinner-grow" role="status" aria-hidden="true"></span>Exporting...');
  $j('#exportProgress').removeClass( 'text-success text-danger text-warning' );
  $j('#exportProgress').addClass( 'text-warning invisible' );
  $j('#downloadLink').html( '' );

@IgorA100 IgorA100 marked this pull request as draft June 6, 2026 20:44
@IgorA100

IgorA100 commented Jun 6, 2026

Copy link
Copy Markdown
Contributor Author

If the user clicks "Generate Download" again while the previous polling is still active

This PR doesn't fix the algorithm.
The next PR will implement replay protection.

@IgorA100 IgorA100 marked this pull request as ready for review June 6, 2026 21:12
@IgorA100

IgorA100 commented Jun 6, 2026

Copy link
Copy Markdown
Contributor Author

Ready for verification.

@connortechnology connortechnology merged commit 7c93a10 into ZoneMinder:master Jun 10, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants