fix: Support multiple file types (PNG, PDF, JPEG) for DokuWiki media uploads

- Make upload_media accept ir.attachment records, IDs, or raw bytes
- Detect file extension from binary content using imghdr
- Build media_id with correct extension (.png, .jpg, .pdf)
- Prevent DokuWiki 'file extension mismatch' error
- Improve temp file cleanup with proper error handling
This commit is contained in:
Matthias Lotz 2026-01-08 17:13:34 +01:00
parent 38d0becfad
commit b26e70dbe9
2 changed files with 105 additions and 21 deletions

View File

@ -278,27 +278,93 @@ class DokuWikiClient(models.AbstractModel):
UserError: Bei Fehler beim Upload
"""
wiki = self._get_wiki_connection()
import tempfile
import os
# Temporäre Datei erstellen (dokuwiki.py erwartet Datei-Pfad)
with tempfile.NamedTemporaryFile(delete=False, suffix='.jpg') as tmp_file:
tmp_file.write(file_content)
tmp_path = tmp_file.name
import base64
import imghdr
tmp_path = None
# Unterstütze mehrere Eingabetypen:
# - ir.attachment record (Recordset)
# - attachment id (int)
# - rohe Bytes
# - base64-codierter String
try:
wiki.medias.add(media_id, tmp_path, overwrite=overwrite)
_logger.info(f"Mediendatei hochgeladen: {media_id}")
return True
except DokuWikiError as e:
error_msg = f"Fehler beim Hochladen der Mediendatei {media_id}: {e}"
_logger.error(error_msg)
raise UserError(error_msg)
content_bytes = None
ext = ''
# ir.attachment Record
if hasattr(file_content, '_name') and getattr(file_content, '_name') == 'ir.attachment':
att = file_content.sudo()
if not att.datas:
raise UserError(f"Attachment {att.id} enthält keine Daten")
content_bytes = base64.b64decode(att.datas)
fname = att.datas_fname or ''
ext = os.path.splitext(fname)[1]
# attachment id
elif isinstance(file_content, int):
att = self.env['ir.attachment'].sudo().browse(file_content)
if not att.exists() or not att.datas:
raise UserError(f"Attachment {file_content} nicht gefunden oder leer")
content_bytes = base64.b64decode(att.datas)
fname = att.datas_fname or ''
ext = os.path.splitext(fname)[1]
# base64 string
elif isinstance(file_content, str):
try:
content_bytes = base64.b64decode(file_content)
except Exception:
# Fallback: treat as empty
raise UserError("Übergebener String konnte nicht als base64 decodiert werden")
ext = os.path.splitext(media_id)[1]
# rohe bytes
else:
# assume bytes-like
content_bytes = file_content
# try extension from media_id
ext = os.path.splitext(media_id)[1]
# Wenn noch keine Extension, versuche Bildtyp zu erkennen
if not ext:
try:
img_type = imghdr.what(None, content_bytes)
if img_type:
ext = f'.{img_type}'
except Exception:
ext = ''
if not ext:
ext = '.bin'
# Sicherstellen, dass ext mit Punkt beginnt
if not ext.startswith('.'):
ext = f'.{ext}'
# Temporäre Datei erstellen (dokuwiki.py erwartet Datei-Pfad)
with tempfile.NamedTemporaryFile(delete=False, suffix=ext) as tmp_file:
tmp_file.write(content_bytes)
tmp_path = tmp_file.name
try:
wiki.medias.add(media_id, tmp_path, overwrite=overwrite)
_logger.info(f"Mediendatei hochgeladen: {media_id} (tmp={tmp_path})")
return True
except DokuWikiError as e:
error_msg = f"Fehler beim Hochladen der Mediendatei {media_id}: {e}"
_logger.error(error_msg)
raise UserError(error_msg)
finally:
# Temporäre Datei löschen
if os.path.exists(tmp_path):
os.unlink(tmp_path)
if tmp_path and os.path.exists(tmp_path):
try:
os.unlink(tmp_path)
except Exception:
_logger.warning(f"Konnte temporäre Datei nicht löschen: {tmp_path}")
@api.model
def get_media_url(self, media_id):

View File

@ -399,17 +399,35 @@ class MaintenanceEquipment(models.Model):
)
# Area-Name normalisieren (wie bei Pages)
area_name = self._normalize_wiki_name(self.ows_area_id.name) if self.ows_area_id else 'unbekannt'
media_id = f"{equipment_namespace}:{area_name}:{wiki_doku_id}.jpg"
# Bild ins Wiki hochladen
# Bild ins Wiki hochladen (erkenne Extension aus Bytes)
try:
import base64
import imghdr
# image_1920 ist base64-kodiert, in bytes umwandeln für XML-RPC
image_bytes = base64.b64decode(self.image_1920)
# Typ/Extension erkennen (jpeg -> .jpg)
img_type = None
try:
img_type = imghdr.what(None, image_bytes)
except Exception:
img_type = None
if img_type == 'jpeg':
ext = '.jpg'
elif img_type:
ext = f'.{img_type}'
elif image_bytes.startswith(b'%PDF'):
ext = '.pdf'
else:
ext = '.bin'
media_id = f"{equipment_namespace}:{area_name}:{wiki_doku_id}{ext}"
dokuwiki_client = self.env['dokuwiki.client']
dokuwiki_client.upload_media(media_id, image_bytes, overwrite=True)
# DokuWiki Image-Syntax: {{namespace:file.jpg?300}}
values['image'] = f"{{{{:{media_id}?100}}}}"
values['image_large'] = f"{{{{:{media_id}}}}}"