-
-
Notifications
You must be signed in to change notification settings - Fork 163
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by lmignon
- Loading branch information
Showing
37 changed files
with
7,597 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from . import models | ||
from .hooks import pre_init_hook |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Copyright 2017-2021 Camptocamp SA | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) | ||
|
||
|
||
{ | ||
"name": "Base Attachment Object Store", | ||
"summary": "Store attachments on external object store", | ||
"version": "18.0.1.0.0", | ||
"author": "Camptocamp, ACSONE SA/NV, Odoo Community Association (OCA)", | ||
"license": "AGPL-3", | ||
"development_status": "Beta", | ||
"category": "Knowledge Management", | ||
"depends": ["fs_storage"], | ||
"website": "https://github.com/OCA/storage", | ||
"data": [ | ||
"security/fs_file_gc.xml", | ||
"views/fs_storage.xml", | ||
], | ||
"external_dependencies": {"python": ["python_slugify"]}, | ||
"installable": True, | ||
"auto_install": False, | ||
"maintainers": ["lmignon"], | ||
"pre_init_hook": "pre_init_hook", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
# Copyright 2023 ACSONE SA/NV | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
from __future__ import annotations | ||
|
||
from odoo.http import STATIC_CACHE_LONG, Response, Stream, request | ||
from odoo.tools import config | ||
|
||
from .models.ir_attachment import IrAttachment | ||
|
||
try: | ||
from werkzeug.utils import send_file as _send_file | ||
except ImportError: | ||
from odoo.tools._vendor.send_file import send_file as _send_file | ||
|
||
|
||
class FsStream(Stream): | ||
fs_attachment = None | ||
|
||
@classmethod | ||
def from_fs_attachment(cls, attachment: IrAttachment) -> FsStream: | ||
attachment.ensure_one() | ||
if not attachment.fs_filename: | ||
raise ValueError("Attachment is not stored into a filesystem storage") | ||
return cls( | ||
mimetype=attachment.mimetype, | ||
download_name=attachment.name, | ||
conditional=True, | ||
etag=attachment.checksum, | ||
type="fs", | ||
size=attachment.file_size, | ||
last_modified=attachment["write_date"], | ||
fs_attachment=attachment, | ||
) | ||
|
||
def read(self): | ||
if self.type == "fs": | ||
with self.fs_attachment.open("rb") as f: | ||
return f.read() | ||
return super().read() | ||
|
||
def get_response(self, as_attachment=None, immutable=None, **send_file_kwargs): | ||
if self.type != "fs": | ||
return super().get_response( | ||
as_attachment=as_attachment, immutable=immutable, **send_file_kwargs | ||
) | ||
if as_attachment is None: | ||
as_attachment = self.as_attachment | ||
if immutable is None: | ||
immutable = self.immutable | ||
send_file_kwargs = { | ||
"mimetype": self.mimetype, | ||
"as_attachment": as_attachment, | ||
"download_name": self.download_name, | ||
"conditional": self.conditional, | ||
"etag": self.etag, | ||
"last_modified": self.last_modified, | ||
"max_age": STATIC_CACHE_LONG if immutable else self.max_age, | ||
"environ": request.httprequest.environ, | ||
"response_class": Response, | ||
**send_file_kwargs, | ||
} | ||
use_x_sendfile = self._fs_use_x_sendfile | ||
# The file will be closed by werkzeug... | ||
send_file_kwargs["use_x_sendfile"] = use_x_sendfile | ||
if not use_x_sendfile: | ||
f = self.fs_attachment.open("rb") | ||
res = _send_file(f, **send_file_kwargs) | ||
else: | ||
x_accel_redirect = ( | ||
f"/{self.fs_attachment.fs_storage_code}{self.fs_attachment.fs_url_path}" | ||
) | ||
send_file_kwargs["use_x_sendfile"] = True | ||
res = _send_file("", **send_file_kwargs) | ||
# nginx specific headers | ||
res.headers["X-Accel-Redirect"] = x_accel_redirect | ||
# apache specific headers | ||
res.headers["X-Sendfile"] = x_accel_redirect | ||
res.headers["Content-Length"] = 0 | ||
|
||
if immutable and res.cache_control: | ||
res.cache_control["immutable"] = None | ||
return res | ||
|
||
@classmethod | ||
def _check_use_x_sendfile(cls, attachment: IrAttachment) -> bool: | ||
return ( | ||
config["x_sendfile"] | ||
and attachment.fs_url | ||
and attachment.fs_storage_id.use_x_sendfile_to_serve_internal_url | ||
) | ||
|
||
@property | ||
def _fs_use_x_sendfile(self) -> bool: | ||
"""Return True if x-sendfile should be used to serve the file""" | ||
return self._check_use_x_sendfile(self.fs_attachment) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# Copyright 2023 ACSONE SA/NV | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
import logging | ||
|
||
from odoo.tools.sql import column_exists | ||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
|
||
def pre_init_hook(env): | ||
"""Pre init hook.""" | ||
# add columns for computed fields to avoid useless computation by the ORM | ||
# when installing the module | ||
cr = env.cr | ||
if column_exists(cr, "ir_attachment", "fs_storage_id"): | ||
return # columns already added; update probably failed partway | ||
_logger.info("Add columns for computed fields on ir_attachment") | ||
cr.execute( | ||
""" | ||
ALTER TABLE ir_attachment | ||
ADD COLUMN fs_storage_id INTEGER; | ||
ALTER TABLE ir_attachment | ||
ADD FOREIGN KEY (fs_storage_id) REFERENCES fs_storage(id); | ||
""" | ||
) | ||
cr.execute( | ||
""" | ||
ALTER TABLE ir_attachment | ||
ADD COLUMN fs_url VARCHAR; | ||
""" | ||
) | ||
cr.execute( | ||
""" | ||
ALTER TABLE ir_attachment | ||
ADD COLUMN fs_storage_code VARCHAR; | ||
""" | ||
) | ||
_logger.info("Columns added on ir_attachment") |
Oops, something went wrong.