feat(downloads): one-click Share + downloadable-by-default links (E7 S3)
D2-A: the library row's Share button becomes a single action — quickShareLink() ensures a public link (minting on demand), copies it to the clipboard, and toasts with an "Open in new tab" action. A copy failure still toasts (warning) with that action so the link is never a dead end. Advanced controls (password/expiry/revoke/ user-ACL) stay in the existing ShareDialog, reached via a new "Manage sharing" row button. D1 (forward-only): CreateLinkIn.allow_download defaults to true, so a newly minted link is downloadable by default. The default lives in the API, not a migration — the download_links column default stays false, so no existing link flips. The ShareDialog create-default is flipped to match. Tests: TestCreateLinkDefault (default true; explicit false honored); 4 vitest cases for quickShareLink (mint-vs-reuse, copy ok/fail, create failure). HU/EN parity.
This commit is contained in:
@@ -93,6 +93,24 @@ class TestPublicMetaAudioFlag:
|
||||
assert meta["audio"] is False
|
||||
|
||||
|
||||
class TestCreateLinkDefault:
|
||||
"""D1 (E7 S3): a newly minted share link is downloadable by default. The one-click Share relies on
|
||||
this — it POSTs no `allow_download`, so the API default decides. Forward-only lives here (the API
|
||||
default), NOT in a migration: the DownloadLink column default stays False, so no existing back-
|
||||
catalogue link silently flips to downloadable."""
|
||||
|
||||
def test_omitted_allow_download_defaults_downloadable(self):
|
||||
from app.routes.downloads import CreateLinkIn
|
||||
|
||||
assert CreateLinkIn().allow_download is True
|
||||
|
||||
def test_explicit_false_is_respected(self):
|
||||
# The owner can still uncheck it to mint a stream-only link.
|
||||
from app.routes.downloads import CreateLinkIn
|
||||
|
||||
assert CreateLinkIn(allow_download=False).allow_download is False
|
||||
|
||||
|
||||
class TestIsExpired:
|
||||
def test_none_expiry_never_expires(self):
|
||||
assert is_expired(SimpleNamespace(expires_at=None)) is False
|
||||
|
||||
Reference in New Issue
Block a user