-
-
Notifications
You must be signed in to change notification settings - Fork 165
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 hparfr
- Loading branch information
Showing
15 changed files
with
872 additions
and
0 deletions.
There are no files selected for viewing
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,92 @@ | ||
================================ | ||
DB attachments saved by checksum | ||
================================ | ||
|
||
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
!! This file is generated by oca-gen-addon-readme !! | ||
!! changes will be overwritten. !! | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
.. |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/licence-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%2Fstorage-lightgray.png?logo=github | ||
:target: https://github.com/OCA/storage/tree/14.0/attachment_db_by_checksum | ||
:alt: OCA/storage | ||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png | ||
:target: https://translation.odoo-community.org/projects/storage-14-0/storage-14-0-attachment_db_by_checksum | ||
:alt: Translate me on Weblate | ||
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png | ||
:target: https://runbot.odoo-community.org/runbot/275/14.0 | ||
:alt: Try me on Runbot | ||
|
||
|badge1| |badge2| |badge3| |badge4| |badge5| | ||
|
||
Allow to identify database attachments through their hash, avoiding duplicates. | ||
|
||
This is typically useful when you want to save attachments to database but you want to save space avoiding to write the same content in several attachments (think of email attachments, for example, or any file uploaded more than once). | ||
|
||
**Table of contents** | ||
|
||
.. contents:: | ||
:local: | ||
|
||
Configuration | ||
============= | ||
|
||
Set system parameter ``ir_attachment.location`` to ``hashed_db`` to activate saving by checksum. | ||
|
||
Run ``force_storage``, method of ``ir.attachment``, to move existing attachments. | ||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/storage/issues>`_. | ||
In case of trouble, please check there if your issue has already been reported. | ||
If you spotted it first, help us smashing it by providing a detailed and welcomed | ||
`feedback <https://github.com/OCA/storage/issues/new?body=module:%20attachment_db_by_checksum%0Aversion:%2014.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 | ||
~~~~~~~ | ||
|
||
* TAKOBI | ||
|
||
Contributors | ||
~~~~~~~~~~~~ | ||
|
||
* `TAKOBI <https://takobi.online>`_: | ||
|
||
* Lorenzo Battistini | ||
|
||
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-eLBati| image:: https://github.com/eLBati.png?size=40px | ||
:target: https://github.com/eLBati | ||
:alt: eLBati | ||
|
||
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__: | ||
|
||
|maintainer-eLBati| | ||
|
||
This module is part of the `OCA/storage <https://github.com/OCA/storage/tree/14.0/attachment_db_by_checksum>`_ project on GitHub. | ||
|
||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
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,3 @@ | ||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). | ||
|
||
from . import models |
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,21 @@ | ||
# Copyright 2021 Lorenzo Battistini @ TAKOBI | ||
# Copyright 2023 Simone Rubino - TAKOBI | ||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). | ||
{ | ||
"name": "DB attachments saved by checksum", | ||
"summary": "Allow to identify database attachments through their hash, avoiding duplicates", | ||
"version": "14.0.1.0.0", | ||
"category": "Storage", | ||
"website": "https://github.com/OCA/storage", | ||
"author": "TAKOBI, Odoo Community Association (OCA)", | ||
"maintainers": [ | ||
"eLBati", | ||
], | ||
"license": "LGPL-3", | ||
"depends": [ | ||
"base", | ||
], | ||
"data": [ | ||
"security/ir.model.access.csv", | ||
], | ||
} |
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,4 @@ | ||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). | ||
|
||
from . import ir_attachment_content | ||
from . import ir_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,136 @@ | ||
# Copyright 2023 Simone Rubino - TAKOBI | ||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
import logging | ||
|
||
from odoo import _, api, models | ||
from odoo.exceptions import AccessError | ||
from odoo.osv import expression | ||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
HASHED_STORAGE_PARAMETER = "hashed_db" | ||
|
||
|
||
class Attachment(models.Model): | ||
_inherit = "ir.attachment" | ||
|
||
@api.model | ||
def _file_write_by_checksum(self, bin_value, checksum): | ||
"""Store attachment content in `Attachment content by hash`.""" | ||
fname, full_path = self._get_path(bin_value, checksum) | ||
attachment_content = self.env["ir.attachment.content"].search_by_checksum(fname) | ||
if not attachment_content: | ||
self.env["ir.attachment.content"].create( | ||
{ | ||
"checksum": fname, | ||
"db_datas": bin_value, | ||
} | ||
) | ||
return fname | ||
|
||
@api.model | ||
def _file_write(self, bin_value, checksum): | ||
location = self._storage() | ||
if location == HASHED_STORAGE_PARAMETER: | ||
return self._file_write_by_checksum(bin_value, checksum) | ||
return super()._file_write(bin_value, checksum) | ||
|
||
@api.model | ||
def _file_read_by_checksum(self, fname): | ||
"""Read attachment content from `Attachment content by hash`.""" | ||
attachment_content = self.env["ir.attachment.content"].search_by_checksum(fname) | ||
if attachment_content: | ||
bin_value = attachment_content.db_datas | ||
else: | ||
# Fallback on standard behavior | ||
_logger.debug("File %s not found" % fname) | ||
bin_value = super()._file_read(fname) | ||
return bin_value | ||
|
||
@api.model | ||
def _file_read(self, fname): | ||
location = self._storage() | ||
if location == HASHED_STORAGE_PARAMETER: | ||
return self._file_read_by_checksum(fname) | ||
return super()._file_read(fname) | ||
|
||
@api.model | ||
def _get_all_attachments_by_checksum_domain(self, fname=None): | ||
"""Get domain for finding all the attachments. | ||
If `checksum` is provided, | ||
get domain for finding all the attachments having checksum `checksum`. | ||
""" | ||
# trick to get every attachment, see _search method of ir.attachment | ||
domain = [ | ||
("id", "!=", 0), | ||
] | ||
if fname is not None: | ||
checksum_domain = [ | ||
("store_fname", "=", fname), | ||
] | ||
domain = expression.AND( | ||
[ | ||
domain, | ||
checksum_domain, | ||
] | ||
) | ||
return domain | ||
|
||
@api.model | ||
def _get_all_attachments_by_checksum(self, fname=None): | ||
"""Get all attachments. | ||
If `checksum` is provided, | ||
get all the attachments having checksum `checksum`. | ||
""" | ||
domain = self._get_all_attachments_by_checksum_domain(fname) | ||
invisible_menu_context = { | ||
"ir.ui.menu.full_list": True, | ||
} | ||
attachments = self.with_context(**invisible_menu_context).search(domain) | ||
return attachments | ||
|
||
@api.model | ||
def _file_delete_by_checksum(self, fname): | ||
"""Delete attachment content in `Attachment content by hash`.""" | ||
attachments = self._get_all_attachments_by_checksum(fname=fname) | ||
if not attachments: | ||
attachment_content = self.env["ir.attachment.content"].search_by_checksum( | ||
fname | ||
) | ||
attachment_content.unlink() | ||
|
||
@api.model | ||
def _file_delete(self, fname): | ||
location = self._storage() | ||
if location == HASHED_STORAGE_PARAMETER: | ||
self._file_delete_by_checksum(fname) | ||
return super()._file_delete(fname) | ||
|
||
@api.model | ||
def force_storage_by_checksum(self): | ||
"""Copy all the attachments to `Attachment content by hash`.""" | ||
if not self.env.is_admin(): | ||
raise AccessError(_("Only administrators can execute this action.")) | ||
|
||
# we don't know if previous storage was file system or DB: | ||
# we run for every attachment | ||
all_attachments = self._get_all_attachments_by_checksum() | ||
for attach in all_attachments: | ||
attach.write( | ||
{ | ||
"datas": attach.datas, | ||
# do not try to guess mimetype overwriting existing value | ||
"mimetype": attach.mimetype, | ||
} | ||
) | ||
return True | ||
|
||
@api.model | ||
def force_storage(self): | ||
location = self._storage() | ||
if location == HASHED_STORAGE_PARAMETER: | ||
return self.force_storage_by_checksum() | ||
return super().force_storage() |
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,43 @@ | ||
from odoo import fields, models | ||
|
||
|
||
class AttachmentContent(models.Model): | ||
_name = "ir.attachment.content" | ||
_rec_name = "checksum" | ||
_description = "Attachment content by hash" | ||
|
||
checksum = fields.Char( | ||
string="Checksum/SHA1", | ||
help="Checksum in the shape 2a/2a...\n", | ||
index=True, | ||
readonly=True, | ||
required=True, | ||
) | ||
db_datas = fields.Binary( | ||
string="Database Data", | ||
attachment=False, | ||
) | ||
|
||
_sql_constraints = [ | ||
( | ||
"checksum_uniq", | ||
"unique(checksum)", | ||
"The checksum of the file must be unique!", | ||
), | ||
] | ||
|
||
def search_by_checksum(self, fname): | ||
"""Get Attachment content, searching by `fname`. | ||
Note that `fname` is the relative path of the attachment | ||
as it would be saved by the core, for example 2a/2a..., | ||
this is the same value that we store | ||
in field `ir.attachment.content.checksum`. | ||
""" | ||
attachment_content = self.env["ir.attachment.content"].search( | ||
[ | ||
("checksum", "=", fname), | ||
], | ||
limit=1, | ||
) | ||
return attachment_content |
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,3 @@ | ||
Set system parameter ``ir_attachment.location`` to ``hashed_db`` to activate saving by checksum. | ||
|
||
Run ``force_storage``, method of ``ir.attachment``, to move existing attachments. |
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,4 @@ | ||
* `TAKOBI <https://takobi.online>`_: | ||
|
||
* Lorenzo Battistini | ||
* Simone Rubino <sir@takobi.online> |
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,3 @@ | ||
Allow to identify database attachments through their hash, avoiding duplicates. | ||
|
||
This is typically useful when you want to save attachments to database but you want to save space avoiding to write the same content in several attachments (think of email attachments, for example, or any file uploaded more than once). |
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,4 @@ | ||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" | ||
"access_ir_attachment_all","Everyone can read Attachment Contents","model_ir_attachment_content",,1,0,0,0 | ||
"access_ir_attachment_group_user","Internal Users can manage Attachment Contents","model_ir_attachment_content","base.group_user",1,1,1,1 | ||
"access_ir_attachment_portal","Portal Users can read and create Attachment Contents","model_ir_attachment_content","base.group_portal",1,0,1,0 |
Oops, something went wrong.