The regression test used temporary_user(login=True) on a passwordless
temp user, so the form login failed (check_password_hash(None) ->
AttributeError) and the request came back 401 instead of 202, failing
CI on all backends. Clone the Gamma user instead: it has a valid login
password and already carries dashboard can_export by default (the exact
principal the frontend shows the Excel menu to), so the test faithfully
reproduces the FE/BE gate the fix aligns.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address review of #41133:
- Reuse the dashboard can_export permission for export_xlsx via
method_permission_name instead of the inert @permission_name decorator,
which FAB ignored and which derived an unassigned can_export_xlsx perm
that the frontend never checks. Drop the decorator and the stale test
assertion; add a regression test proving a can_export-only role is
admitted (202) not rejected (403).
- Reject mode="images" with 404 when the webdriver screenshot flags are
off, mirroring the UI gate and validate_feature_flags behavior; add
flag-on/off regression tests.
- Frontend: distinguish the throttle 202 (no job_id) from a real enqueue
and show an "already in progress" toast instead of the misleading
"being prepared" one.
- Drop personal verification scaffolding (VERIFY_EXCEL_EXPORT.md,
docker-compose-excel-verify.yml) and revert the check-yaml exclusion
that only that compose file required.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Addresses @EnxDev's review on #41133:
- Soft timeouts now abort the export instead of being caught per chart: the
per-chart SoftTimeLimitExceeded handler (and screenshot.py's broad except)
re-raise, so the outer handler emails a failure and runs cleanup rather than
running to the hard limit (leaking temp files, holding the lock). Removes the
now-dead ERROR_TIMEOUT reason.
- Concurrency guard uses a shared, atomic DistributedLock (Redis when
configured, metadata DB otherwise) instead of cache_manager.cache, which is a
no-op under the default NullCache and process-local under SimpleCache. The
lock is released if apply_async fails so a broker outage can't block exports
until the TTL expires.
- boto3 is declared via a new `excel-export` optional extra; superset.utils.s3
raises an actionable install hint when it is missing.
- "Export Images to Excel" is gated on the webdriver screenshot feature flags
(it renders via the headless webdriver); documents EXCEL_EXPORT_TABLE_VIZ_TYPES
and the image mode in the config docs and UPDATING.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resolves betodealmeida's review comments on PR #41133:
- i18n: wrap all user-facing email strings in gettext with named
placeholders (build_subject / errored section / success + failure bodies).
- Human-readable link expiry via a pluralized, translatable helper, fixing
the sub-hour "0 hours" underreporting.
- Group charts that could not be exported by reason
(no-query-context / timeout / general-exception) instead of a flat
"skipped" list; render one labelled section per reason in the email.
- Replace deprecated datetime.utcnow() with datetime.now(tz=timezone.utc).
- Throttle concurrent exports per user+dashboard via a cache lock: return
202 "already in progress" if one is in flight, clear the lock in the
task's finally block (TTL is the backstop).
- Tests: switch the export API tests to the @with_config decorator; add
unit coverage for grouped errors and the throttle-lock cleanup.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- export_xlsx: use request.get_json(silent=True) so a POST with no JSON
content-type no longer raises 415/500 (returns 400/404/501 as intended).
- api_tests: register the FAB-generated can_export_xlsx permission in
test_info_security_dashboard; replace the gamma test (Gamma has can_export)
with a deterministic 404-for-inaccessible-dashboard check.
- type-annotate dict literals in the filter-context tests (mypy var-annotated).
- move MenuWrapperWithProps above first use (oxlint no-use-before-define).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add POST /api/v1/dashboard/<pk>/export_xlsx/ which validates the request and
enqueues the async Excel export task, returning 202 with a job id. Gated on the
Dashboard can_export permission (@permission_name("export")); returns 501 when
EXCEL_EXPORT_S3_BUCKET is unset, 404 for inaccessible/missing dashboards,
403 on object-level access denial, and 400 for guest/no-email users or empty
dashboards. The job id is used as the Celery task id for correlation. Adds the
request/response marshmallow schemas and integration tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>