Skip to content

Commit f6ea3a3

Browse files
author
Gaetan Semet
committed
fix: attachment filename
Signed-off-by: Gaetan Semet <gaetan.semet@ampere.cars>
1 parent 9e53e3d commit f6ea3a3

File tree

1 file changed

+42
-6
lines changed

1 file changed

+42
-6
lines changed

confluence_markdown_exporter/confluence.py

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -231,25 +231,44 @@ class Attachment(Document):
231231

232232
@property
233233
def extension(self) -> str:
234+
# Prefer explicit draw.io markers
234235
if self.comment == "draw.io diagram" and self.media_type == "application/vnd.jgraph.mxfile":
235236
return ".drawio"
236237
if self.comment == "draw.io preview" and self.media_type == "image/png":
237238
return ".drawio.png"
238239

239-
return mimetypes.guess_extension(self.media_type) or ""
240+
# First try to guess from media_type
241+
guessed = mimetypes.guess_extension(self.media_type) or ""
242+
if guessed:
243+
return guessed
244+
245+
# Fallback to using the title's suffix (if present)
246+
try:
247+
title_suffix = Path(self.title).suffix
248+
except Exception:
249+
title_suffix = ""
250+
251+
return title_suffix or ""
240252

241253
@property
242254
def filename(self) -> str:
243-
return f"{self.file_id}{self.extension}"
255+
# If file_id is available use it, otherwise fall back to a sanitized title stem
256+
if self.file_id:
257+
return f"{self.file_id}{self.extension}"
258+
# Use the title stem (filename without extension), sanitized for filesystem
259+
stem = sanitize_filename(Path(self.title).stem)
260+
return f"{stem}{self.extension}"
244261

245262
@property
246263
def _template_vars(self) -> dict[str, str]:
247264
return {
248265
**super()._template_vars,
249266
"attachment_id": str(self.id),
250267
"attachment_title": sanitize_filename(self.title),
251-
# file_id is a GUID and does not need sanitized.
252-
"attachment_file_id": self.file_id,
268+
# file_id is a GUID and does not need sanitized. When missing, fall back to
269+
# a sanitized title stem so templates that only reference {attachment_file_id}
270+
# don't end up with filenames like ".png".
271+
"attachment_file_id": self.file_id or sanitize_filename(Path(self.title).stem),
253272
"attachment_extension": self.extension,
254273
}
255274

@@ -317,8 +336,25 @@ def export(self) -> None:
317336
logger.warning(f"There is no attachment with title '{self.title}'. Skipping export.")
318337
return
319338

339+
# If the configured template produced a filepath without an extension
340+
# but the response content is JSON (or the content-type indicates JSON),
341+
# save the file with a .json suffix so consumers can recognise it.
342+
content_type = (response.headers.get("Content-Type") or "").lower()
343+
target_filepath = filepath
344+
looks_like_json = False
345+
try:
346+
# Quick binary check for JSON-like content
347+
body_start = response.content.lstrip()[:1]
348+
if body_start in (b"{", b"["):
349+
looks_like_json = True
350+
except Exception:
351+
looks_like_json = False
352+
353+
if not filepath.suffix and ("json" in content_type or looks_like_json):
354+
target_filepath = filepath.with_suffix(".json")
355+
320356
save_file(
321-
filepath,
357+
target_filepath,
322358
response.content,
323359
)
324360

@@ -782,7 +818,7 @@ def convert_jira_issue(self, el: BeautifulSoup, text: str, parent_tags: list[str
782818
try:
783819
issue = JiraIssue.from_key(str(issue_key))
784820
return f"[[{issue.key}] {issue.summary}]({link.get('href')})"
785-
except HTTPError:
821+
except (HTTPError, AttributeError):
786822
return f"[[{issue_key}]]({link.get('href')})"
787823

788824
def convert_pre(self, el: BeautifulSoup, text: str, parent_tags: list[str]) -> str:

0 commit comments

Comments
 (0)