odoo18/addons_extensions/universal_attachment_preview/models/ir_attachment.py

89 lines
3.2 KiB
Python

from odoo import models
import mimetypes
import base64
import io
import zipfile
class IrAttachment(models.Model):
_inherit = "ir.attachment"
def _detect_mimetype(self, datas):
# direct copy of the above function
try:
raw = base64.b64decode(datas)
except:
return "application/octet-stream"
# office zip check
if raw.startswith(b"PK"):
try:
z = zipfile.ZipFile(io.BytesIO(raw))
names = z.namelist()
if "ppt/presentation.xml" in names:
return "application/vnd.openxmlformats-officedocument.presentationml.presentation"
if "word/document.xml" in names:
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
if "xl/workbook.xml" in names:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
return "application/zip"
except:
pass
if raw.startswith(b"%PDF-"):
return "application/pdf"
return "application/octet-stream"
def _get_extension_from_mimetype(self, mimetype):
mapping = {
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": ".docx",
"application/vnd.openxmlformats-officedocument.presentationml.presentation": ".pptx",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": ".xlsx",
"application/pdf": ".pdf",
"application/zip": ".zip",
}
return mapping.get(mimetype, False)
def write(self, vals):
res = super().write(vals)
# ----------------------------------------------------
# 1) Fix incorrect mimetype (ex: .pptx → zip)
# ----------------------------------------------------
if "datas" in vals or "mimetype" in vals:
for rec in self:
datas = vals.get("datas", rec.datas)
mimetype = self._detect_mimetype(datas)
# Update mimetype if wrong
if mimetype != rec.mimetype:
rec.sudo().write({"mimetype": mimetype})
# ----------------------------------------------------
# 2) Fix the filename extension based on correct mimetype
# ----------------------------------------------------
# Detect extension from mimetype
correct_ext = self._get_extension_from_mimetype(mimetype) or ".bin"
filename = rec.name or ""
current_ext = ""
if "." in filename:
current_ext = "." + filename.split(".")[-1].lower()
# CASE 1: No filename or no extension
if not filename or "." not in filename:
new_name = f"{rec.res_field or 'file'}_{rec.id}{correct_ext}"
rec.sudo().write({"name": new_name})
# CASE 2: Wrong extension → Replace it
elif current_ext != correct_ext:
base = filename.rsplit(".", 1)[0]
new_name = f"{base}{correct_ext}"
rec.sudo().write({"name": new_name})
return res