mirror of
https://github.com/suitenumerique/drive.git
synced 2026-09-30 21:45:15 +02:00
✨(backend) add legacy conversion policy helpers
Legacy Office formats need an explicit conversion policy before they can be opened for editing. Keep the mapping small and configuration-driven so the backend only converts formats intentionally forced by the WOPI client.
This commit is contained in:
@@ -1398,14 +1398,6 @@ class Base(Configuration):
|
||||
WOPI_LOCK_TIMEOUT = values.IntegerValue(
|
||||
30 * 60, environ_name="WOPI_LOCK_TIMEOUT", environ_prefix=None
|
||||
)
|
||||
<<<<<<< HEAD
|
||||
||||||| parent of f8297c68 (✨(backend) add OnlyOffice conversion backend)
|
||||
WOPI_LEGACY_CONVERSION_TARGETS = {
|
||||
"doc": "docx",
|
||||
"xls": "xlsx",
|
||||
"ppt": "pptx",
|
||||
}
|
||||
=======
|
||||
WOPI_LEGACY_CONVERSION_TARGETS = {
|
||||
"doc": "docx",
|
||||
"xls": "xlsx",
|
||||
@@ -1423,7 +1415,6 @@ class Base(Configuration):
|
||||
WOPI_ONLYOFFICE_CONVERT_DOWNLOAD_READ_TIMEOUT = values.IntegerValue(
|
||||
30, environ_name="WOPI_ONLYOFFICE_CONVERT_DOWNLOAD_READ_TIMEOUT", environ_prefix=None
|
||||
)
|
||||
>>>>>>> f8297c68 (✨(backend) add OnlyOffice conversion backend)
|
||||
WOPI_DISABLE_CHAT = values.IntegerValue(
|
||||
0, environ_name="WOPI_DISABLE_CHAT", environ_prefix=None
|
||||
)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
"""Server-to-server conversion of legacy Office files via WOPI providers."""
|
||||
@@ -0,0 +1,42 @@
|
||||
"""Forced-conversion policy for WOPI legacy formats."""
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def _normalize(value):
|
||||
return value.lower() if isinstance(value, str) else value
|
||||
|
||||
|
||||
def target_extension_for(source_extension):
|
||||
"""Return the converted extension for a legacy source extension.
|
||||
|
||||
Item.extension preserves filename case (REPORT.DOC -> "DOC"), so the
|
||||
lookup must be case-insensitive.
|
||||
"""
|
||||
if not source_extension:
|
||||
return None
|
||||
|
||||
return settings.WOPI_LEGACY_CONVERSION_TARGETS.get(source_extension.lower())
|
||||
|
||||
|
||||
def is_forced_conversion(item, client_options):
|
||||
"""Return True when the active WOPI client forces a server-side conversion.
|
||||
|
||||
The decision is product policy, not discovery-derived: a client is allowed
|
||||
to advertise an "edit" action for a legacy format and still require the
|
||||
Drive backend to convert it first.
|
||||
"""
|
||||
if not client_options:
|
||||
return False
|
||||
|
||||
extension = _normalize(item.extension)
|
||||
forced_extensions = {_normalize(e) for e in client_options.get("ForceConvertExtensions") or []}
|
||||
if extension and extension in forced_extensions:
|
||||
return True
|
||||
|
||||
mimetype = _normalize(item.mimetype)
|
||||
forced_mimetypes = {_normalize(m) for m in client_options.get("ForceConvertMimetypes") or []}
|
||||
if mimetype and mimetype in forced_mimetypes:
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -0,0 +1,74 @@
|
||||
"""Tests for the conversion policy helpers."""
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from core import factories
|
||||
from wopi.conversion.policy import is_forced_conversion, target_extension_for
|
||||
|
||||
|
||||
def _item(filename="document.doc", mimetype="application/msword"):
|
||||
"""Build a minimal in-memory Item for policy tests."""
|
||||
return factories.ItemFactory.build(filename=filename, mimetype=mimetype)
|
||||
|
||||
|
||||
def test_target_extension_for_known_legacy_formats():
|
||||
"""Map known legacy Office extensions to their modern equivalents."""
|
||||
assert target_extension_for("doc") == "docx"
|
||||
assert target_extension_for("xls") == "xlsx"
|
||||
assert target_extension_for("ppt") == "pptx"
|
||||
|
||||
|
||||
def test_target_extension_for_unknown_format_returns_none():
|
||||
"""Return None for unsupported or empty source extensions."""
|
||||
assert target_extension_for("docx") is None
|
||||
assert target_extension_for("") is None
|
||||
assert target_extension_for(None) is None
|
||||
|
||||
|
||||
def test_target_extension_for_is_case_insensitive():
|
||||
"""Match the target extension regardless of source extension case."""
|
||||
assert target_extension_for("DOC") == "docx"
|
||||
assert target_extension_for("Xls") == "xlsx"
|
||||
|
||||
|
||||
def test_legacy_conversion_targets_only_lists_legacy_formats():
|
||||
"""Restrict the conversion policy to legacy Office formats."""
|
||||
assert set(settings.WOPI_LEGACY_CONVERSION_TARGETS) == {"doc", "xls", "ppt"}
|
||||
|
||||
|
||||
def test_is_forced_conversion_true_when_extension_listed():
|
||||
"""Force conversion when the item extension is listed."""
|
||||
options = {"ForceConvertExtensions": ["doc", "xls", "ppt"]}
|
||||
assert is_forced_conversion(_item(filename="document.doc"), options) is True
|
||||
|
||||
|
||||
def test_is_forced_conversion_true_when_mimetype_listed():
|
||||
"""Force conversion when the item mimetype is listed."""
|
||||
options = {"ForceConvertMimetypes": ["application/msword"]}
|
||||
item = _item(filename="document.unknown", mimetype="application/msword")
|
||||
assert is_forced_conversion(item, options) is True
|
||||
|
||||
|
||||
def test_is_forced_conversion_false_when_neither_matches():
|
||||
"""Skip conversion when neither extension nor mimetype matches."""
|
||||
options = {
|
||||
"ForceConvertExtensions": ["doc"],
|
||||
"ForceConvertMimetypes": ["application/msword"],
|
||||
}
|
||||
item = _item(filename="document.docx", mimetype="application/vnd.openxmlformats")
|
||||
assert is_forced_conversion(item, options) is False
|
||||
|
||||
|
||||
def test_is_forced_conversion_false_when_options_missing():
|
||||
"""Skip conversion when client options are missing."""
|
||||
assert is_forced_conversion(_item(), {}) is False
|
||||
assert is_forced_conversion(_item(), None) is False
|
||||
|
||||
|
||||
def test_is_forced_conversion_extension_check_is_case_insensitive():
|
||||
"""Match forced extensions regardless of case."""
|
||||
options = {"ForceConvertExtensions": ["doc"]}
|
||||
assert is_forced_conversion(_item(filename="REPORT.DOC"), options) is True
|
||||
|
||||
options = {"ForceConvertExtensions": ["DOC"]}
|
||||
assert is_forced_conversion(_item(filename="document.doc"), options) is True
|
||||
Reference in New Issue
Block a user