Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
ca3f611
[ADD] fs_file: New field to store files
lmignon Apr 27, 2023
c49fd3b
[IMP] fs_file: Remove storage code; rename FSFileBytesIO -> FSFileValue
marielejeune Aug 3, 2023
9eb4865
[UPD] Update fs_file.pot
Aug 24, 2023
c9329a7
[UPD] README.rst
OCA-git-bot Aug 24, 2023
c6f13c3
[IMP] fs_file: Improves UI
lmignon Sep 3, 2023
29ebfd4
[IMP] fs_file: Add missing description
lmignon Sep 3, 2023
d458924
[IMP] fs_file: Improves extensibility
lmignon Sep 3, 2023
0bdbe15
[UPD] README.rst
OCA-git-bot Sep 3, 2023
102ea80
[ADD] fs_image: Field to store images
lmignon Sep 3, 2023
5d54e7a
[UPD] Update fs_file.pot
Sep 22, 2023
3326ef3
[BOT] post-merge updates
OCA-git-bot Sep 22, 2023
92c377a
[IMP] fs_file: Directory for HISTORY.rst generation
lmignon Sep 28, 2023
fc97994
[IMP] fs_file: New property 'url_path' on FSFileValue object
lmignon Sep 29, 2023
d02db51
[FIX] fs_file: url, url_path and internal_url must return None
lmignon Sep 29, 2023
777e2d7
[FIX] fs_file: url property refers to the filesystem url
lmignon Sep 29, 2023
d24766f
[BOT] post-merge updates
OCA-git-bot Sep 29, 2023
77bc9d5
[FIX] fs_file: Uses anonymous reference in rst files
lmignon Oct 4, 2023
57713cb
[BOT] post-merge updates
OCA-git-bot Oct 4, 2023
70200b5
[16.0][FIX] fs_file: guess mimetype based on name
glitchov Oct 4, 2023
d370dbd
[FIX] fs_file: Improves mimetype computation
lmignon Oct 5, 2023
fafbad1
[BOT] post-merge updates
OCA-git-bot Oct 5, 2023
dcae4de
[FIX] fs_file: Browse attachment with sudo to avoid read access errors
rousseldenis Oct 16, 2023
552fe2c
[BOT] post-merge updates
OCA-git-bot Oct 17, 2023
2d288c5
[FIX] fs_file: Invalidate cache on write
lmignon Oct 22, 2023
92338e3
Added translation using Weblate (Italian)
mymage Nov 28, 2023
1141210
Translated using Weblate (Italian)
mymage Nov 28, 2023
9fc6577
Translated using Weblate (Italian)
mymage Nov 29, 2023
4e286dc
[BOT] post-merge updates
OCA-git-bot Nov 30, 2023
90163df
Added translation using Weblate (Spanish)
Ivorra78 Jan 27, 2024
fd92ded
Translated using Weblate (Spanish)
Ivorra78 Jan 27, 2024
eb2dd2e
[FIX] fs_file: Support for empty file
lmignon Feb 21, 2024
2490958
[BOT] post-merge updates
OCA-git-bot Feb 23, 2024
08ee42e
[IMP] fs_file: pre-commit auto fixes
nguyenminhchien Feb 23, 2024
efa5d38
[MIG] fs_file: Migration to 17.0
nguyenminhchien Feb 28, 2024
071fd52
[UPD] Update fs_file.pot
Apr 25, 2024
3533d9f
[BOT] post-merge updates
OCA-git-bot Apr 25, 2024
bd54d16
Update translation files
weblate Apr 25, 2024
735cc00
Translated using Weblate (Italian)
mymage Apr 29, 2024
4223d73
[MIG] fs_file: Migration to 18.0
rousseldenis Feb 19, 2025
086a16c
[IMP] fs_file: Improve tests
rousseldenis Feb 19, 2025
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
283 changes: 283 additions & 0 deletions fs_file/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
=======
Fs File
=======

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

.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
:target: https://odoo-community.org/page/development-status
:alt: Alpha
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstorage-lightgray.png?logo=github
:target: https://github.com/OCA/storage/tree/18.0/fs_file
:alt: OCA/storage
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/storage-18-0/storage-18-0-fs_file
: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/storage&target_branch=18.0
:alt: Try me on Runboat

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

This addon defines a new field type FSFile which is a file field that
stores a file in an external filesystem instead of the odoo's filestore.
This is useful for large files that you don't want to store in the
filestore. Moreover, the field value provides you an interface to access
the file's contents and metadata.

.. IMPORTANT::
This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
`More details on development status <https://odoo-community.org/page/development-status>`_

**Table of contents**

.. contents::
:local:

Usage
=====

The new field **FSFile** has been developed to allows you to store files
in an external filesystem storage. Its design is based on the following
principles:

- The content of the file must be read from the filesystem only when
needed.
- It must be possible to manipulate the file content as a stream by
default.
- Unlike Odoo's Binary field, the content is the raw file content by
default (no base64 encoding).
- To allows to exchange the file content with other systems, writing the
content as base64 is possible. The read operation will return a json
structure with the filename, the mimetype, the size and a url to
download the file.

This design allows to minimize the memory consumption of the server when
manipulating large files and exchanging them with other systems through
the default jsonrpc interface.

Concretely, this design allows you to write code like this:

.. code:: python

from IO import BytesIO
from odoo import models, fields
from odoo.addons.fs_file.fields import FSFile

class MyModel(models.Model):
_name = 'my.model'

name = fields.Char()
file = FSFile()

# Create a new record with a raw content
my_model = MyModel.create({
'name': 'My File',
'file': BytesIO(b"content"),
})

assert(my_model.file.read() == b"content")

# Create a new record with a base64 encoded content
my_model = MyModel.create({
'name': 'My File',
'file': b"content".encode('base64'),
})
assert(my_model.file.read() == b"content")

# Create a new record with a file content
my_model = MyModel.create({
'name': 'My File',
'file': open('my_file.txt', 'rb'),
})
assert(my_model.file.read() == b"content")
assert(my_model.file.name == "my_file.txt")

# create a record with a file content as base64 encoded and a filename
# This method is useful to create a record from a file uploaded
# through the web interface.
my_model = MyModel.create({
'name': 'My File',
'file': {
'filename': 'my_file.txt',
'content': base64.b64encode(b"content"),
},
})
assert(my_model.file.read() == b"content")
assert(my_model.file.name == "my_file.txt")

# write the content of the file as base64 encoded and a filename
# This method is useful to update a record from a file uploaded
# through the web interface.
my_model.write({
'file': {
'name': 'my_file.txt',
'file': base64.b64encode(b"content"),
},
})

# the call to read() will return a json structure with the filename,
# the mimetype, the size and a url to download the file.
info = my_model.file.read()
assert(info["file"] == {
"filename": "my_file.txt",
"mimetype": "text/plain",
"size": 7,
"url": "/web/content/1234/my_file.txt",
})

# use the field as a file stream
# In such a case, the content is read from the filesystem without being
# stored in memory.
with my_model.file.open("rb) as f:
assert(f.read() == b"content")

# use the field as a file stream to write the content
# In such a case, the content is written to the filesystem without being
# stored in memory. This kind of approach is useful to manipulate large
# files and to avoid to use too much memory.
# Transactional behaviour is ensured by the implementation!
with my_model.file.open("wb") as f:
f.write(b"content")

Changelog
=========

16.0.1.0.6 (2024-02-23)
-----------------------

**Bugfixes**

- Fixes the creation of empty files.

Before this change, the creation of empty files resulted in a
constraint violation error. This was due to the fact that even if a
name was given to the file it was not preserved into the FSFileValue
object if no content was given. As result, when the corresponding
ir.attachment was created in the database, the name was not set and
the 'required' constraint was violated.
(`#341 <https://github.com/OCA/storage/issues/341>`__)

16.0.1.0.5 (2023-11-30)
-----------------------

**Bugfixes**

- Ensure the cache is properly set when a new value is assigned to a
FSFile field. If the field is stored the value to the cache must be a
FSFileValue object linked to the attachment record used to store the
file. Otherwise the value must be one given since it could be the
result of a compute method.
(`#290 <https://github.com/OCA/storage/issues/290>`__)

16.0.1.0.4 (2023-10-17)
-----------------------

**Bugfixes**

- Browse attachment with sudo() to avoid read access errors

In models that have a multi fs image relation, a new line in form will
trigger onchanges and will call the fs.file model 'convert_to_cache()'
method that will try to browse the attachment with user profile that
could have no read rights on attachment model.
(`#288 <https://github.com/OCA/storage/issues/288>`__)

16.0.1.0.3 (2023-10-05)
-----------------------

**Bugfixes**

- Fix the *mimetype* property on *FSFileValue* objects.

The *mimetype* value is computed as follow:

- If an attachment is set, the mimetype is taken from the attachment.
- If no attachment is set, the mimetype is guessed from the name of
the file.
- If the mimetype cannot be guessed from the name, the mimetype is
guessed from the content of the file.
(`#284 <https://github.com/OCA/storage/issues/284>`__)

16.0.1.0.1 (2023-09-29)
-----------------------

**Features**

- Add a *url_path* property on the *FSFileValue* object. This property
allows you to easily get access to the relative path of the file on
the filesystem. This value is only available if the filesystem storage
is configured with a *Base URL* value.
(`#281 <https://github.com/OCA/storage/issues/281>`__)

**Bugfixes**

- The *url_path*, *url* and *internal_url* properties on the
*FSFileValue* object return *None* if the information is not available
(instead of *False*).

The *url* property on the *FSFileValue* object returns the filesystem
url nor the url field of the attachment.
(`#281 <https://github.com/OCA/storage/issues/281>`__)

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 to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/storage/issues/new?body=module:%20fs_file%0Aversion:%2018.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
-------

* ACSONE SA/NV

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

- Laurent Mignon <[email protected]>
- Marie Lejeune <[email protected]>
- Hugues Damry <[email protected]>
- Nguyen Minh Chien <[email protected]>
- Denis Roussel <<[email protected]>

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-lmignon| image:: https://github.com/lmignon.png?size=40px
:target: https://github.com/lmignon
:alt: lmignon

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

|maintainer-lmignon|

This module is part of the `OCA/storage <https://github.com/OCA/storage/tree/18.0/fs_file>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
Empty file added fs_file/__init__.py
Empty file.
20 changes: 20 additions & 0 deletions fs_file/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2023 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

{
"name": "Fs File",
"summary": """
Field to store files into filesystem storages""",
"version": "18.0.1.0.0",
"license": "AGPL-3",
"author": "ACSONE SA/NV,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/storage",
"depends": ["fs_attachment"],
"maintainers": ["lmignon"],
"development_status": "Alpha",
"assets": {
"web.assets_backend": [
"fs_file/static/src/**/*",
],
},
}
Loading