Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions dms_libreoffice_preview/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

=========================
DMS — LibreOffice Preview
=========================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:81baba4c980b32e56a3e208ba841264571d907763fa987650db3d700e2592292
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fdms-lightgray.png?logo=github
:target: https://github.com/OCA/dms/tree/19.0/dms_libreoffice_preview
:alt: OCA/dms
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/dms-19-0/dms-19-0-dms_libreoffice_preview
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/dms&target_branch=19.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

Adds in-browser preview of office file formats (Word, Excel, PowerPoint,
OpenDocument, RTF) to OCA DMS by converting them to PDF on the server
with a headless LibreOffice subprocess. The converted PDF is cached as a
child ``ir.attachment`` of the source ``dms.file`` and served via the
existing side-pane preview registry (``dms.preview_handlers``), so the
browser's native PDF viewer renders the result with no new UI code.

Without this module, office files in DMS fall back to a download-only
card. Install this module on any deployment where LibreOffice can be
installed system-wide and you don't need full in-browser editing (use
``dms_onlyoffice`` for that).

**Table of contents**

.. contents::
:local:

Installation
============

System dependencies
-------------------

LibreOffice must be installed on the Odoo server. On Debian / Ubuntu:

::

apt-get install libreoffice fonts-noto fonts-liberation

The ``fonts-noto`` and ``fonts-liberation`` packages are recommended
even if your container already has a font set — headless LibreOffice
falls back to ugly substitutes when common fonts are missing, which
produces unreadable PDFs for typical office documents.

Once LibreOffice is on the ``PATH``, install this module as usual. The
preview is lazy: nothing converts until the first time a user opens an
office file in the DMS side-pane. Subsequent opens of the same file
(same ``write_date``) hit the ``ir.attachment`` cache.

Usage
=====

No configuration required. With LibreOffice on the server and this
module installed, opening any office file (``.doc{x}``, ``.odt``,
``.xls{x}``, ``.ods``, ``.ppt{x}``, ``.odp``, ``.rtf``) from the DMS
kanban or list view shows the rendered PDF in the side-pane preview.

The first open takes 1–5 seconds (LibreOffice conversion); subsequent
opens hit the cached attachment and feel instant. If the source file
changes (new content, new name, etc.), the cache invalidates and the
next open triggers a fresh conversion.

If LibreOffice fails to convert a file (corrupt source, unusual format
variation), the side-pane shows a brief error message. The original file
is always downloadable via the side-pane toolbar's Download button
regardless of preview success.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/dms/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/dms/issues/new?body=module:%20dms_libreoffice_preview%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* ledoent

Contributors
------------

- Don Kendall <dkendall@ledoweb.com>

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

.. |maintainer-dnplkndll| image:: https://github.com/dnplkndll.png?size=40px
:target: https://github.com/dnplkndll
:alt: dnplkndll

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-dnplkndll|

This module is part of the `OCA/dms <https://github.com/OCA/dms/tree/19.0/dms_libreoffice_preview>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
2 changes: 2 additions & 0 deletions dms_libreoffice_preview/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import controllers
from . import models
30 changes: 30 additions & 0 deletions dms_libreoffice_preview/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright 2026 ledoent — Don Kendall
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

{
"name": "DMS — LibreOffice Preview",
"summary": (
"In-browser preview of office files in DMS via "
"server-side LibreOffice→PDF conversion"
),
"version": "19.0.1.0.0",
"category": "Document Management",
"license": "LGPL-3",
"website": "https://github.com/OCA/dms",
"author": "ledoent, Odoo Community Association (OCA)",
"maintainers": ["dnplkndll"],
"depends": ["dms", "dms_preview_pane"],
"external_dependencies": {
"deb": ["libreoffice", "fonts-noto", "fonts-liberation"],
},
"assets": {
"web.assets_backend": [
"dms_libreoffice_preview/static/src/js/libreoffice_preview.esm.js",
"dms_libreoffice_preview/static/src/js/libreoffice_preview.xml",
],
"web.assets_unit_tests": [
"dms_libreoffice_preview/static/tests/**/*.test.js",
],
},
"installable": True,
}
1 change: 1 addition & 0 deletions dms_libreoffice_preview/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import main
51 changes: 51 additions & 0 deletions dms_libreoffice_preview/controllers/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright 2026 ledoent — Don Kendall
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

from odoo import http
from odoo.exceptions import AccessError, UserError
from odoo.http import request


class DmsLibreofficePreviewController(http.Controller):
@http.route(
"/dms/file/<int:file_id>/libreoffice_preview",
type="http",
auth="user",
methods=["GET"],
# Not readonly: cache-miss path writes a new ir.attachment via
# _ensure_libreoffice_preview(). Marking readonly=True triggers
# Odoo 19's "retry with r/w cursor" warning which checklog-odoo
# promotes to a build error.
)
def libreoffice_preview(self, file_id, **kwargs):
"""Serve a cached or freshly-converted PDF preview inline.

The `?v=<write_date>` query parameter is not validated server-side
— it exists purely as a cache-buster for the browser (the iframe
URL changes when `dms.file.write_date` changes, forcing a refetch
instead of pulling a stale render from the HTTP cache). Cache
validity on the server is owned by `_libreoffice_preview_attachment`.
"""
dms_file = request.env["dms.file"].browse(file_id).exists()
if not dms_file:
raise request.not_found()
try:
dms_file.check_access("read")
except AccessError as e:
raise request.not_found() from e
if not dms_file._libreoffice_preview_supported():
raise request.not_found()
try:
attachment = dms_file.sudo()._ensure_libreoffice_preview()
except UserError as e:
# Conversion errors are surfaced as 502 with the user-facing
# message — the side-pane handler can render this as an empty
# state via the existing error path.
return request.make_response(
str(e), status=502, headers=[("Content-Type", "text/plain")]
)
return (
request.env["ir.binary"]
._get_stream_from(attachment, "raw")
.get_response(as_attachment=False)
)
1 change: 1 addition & 0 deletions dms_libreoffice_preview/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import dms_file
Loading
Loading