Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[17.0] fs_storage: Port from 16.0 to 17.0 #400

Closed
5 changes: 5 additions & 0 deletions .oca/oca-port/blacklist/fs_storage.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"pull_requests": {
"OCA/storage#252": "Don't need initial requirements.txt"
}
}
1 change: 1 addition & 0 deletions fs_storage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

# then add normal imports
from . import models
from . import wizards
1 change: 1 addition & 0 deletions fs_storage/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"data": [
"views/fs_storage_view.xml",
"security/ir.model.access.csv",
"wizards/fs_test_connection.xml",
],
"demo": ["demo/fs_storage_demo.xml"],
"external_dependencies": {"python": ["fsspec>=2024.5.0"]},
Expand Down
66 changes: 61 additions & 5 deletions fs_storage/models/fs_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@
protocol = fields.Selection(
selection="_get_protocols",
required=True,
default="odoofs",
help="The protocol used to access the content of filesystem.\n"
"This list is the one supported by the fsspec library (see "
"https://filesystem-spec.readthedocs.io/en/latest). A filesystem protocol"
Expand Down Expand Up @@ -147,6 +146,15 @@
compute="_compute_options_properties",
store=False,
)
check_connection_method = fields.Selection(
selection="_get_check_connection_method_selection",
default="marker_file",
help="Set a method if you want the connection to remote to be checked every "
"time the storage is used, in order to remove the obsolete connection from"
" the cache.\n"
"* Create Marker file : Create a file on remote and check it exists\n"
"* List File : List all files from root directory",
)

_sql_constraints = [
(
Expand All @@ -158,6 +166,13 @@

_server_env_section_name_field = "code"

@api.model
def _get_check_connection_method_selection(self):
return [
("marker_file", _("Create Marker file")),
("ls", _("List File")),
]

@property
def _server_env_fields(self):
return {"protocol": {}, "options": {}, "directory_path": {}}
Expand Down Expand Up @@ -265,12 +280,41 @@
doc = inspect.getdoc(cls.__init__)
rec.options_properties = f"__init__{signature}\n{doc}"

def _get_marker_file_name(self):
return ".odoo_fs_storage_%s.marker" % self.id

Check warning on line 284 in fs_storage/models/fs_storage.py

View check run for this annotation

Codecov / codecov/patch

fs_storage/models/fs_storage.py#L284

Added line #L284 was not covered by tests

def _marker_file_check_connection(self, fs):
marker_file_name = self._get_marker_file_name()
try:
fs.info(marker_file_name)
except FileNotFoundError:
fs.touch(marker_file_name)

Check warning on line 291 in fs_storage/models/fs_storage.py

View check run for this annotation

Codecov / codecov/patch

fs_storage/models/fs_storage.py#L287-L291

Added lines #L287 - L291 were not covered by tests

def _ls_check_connection(self, fs):
fs.ls("", detail=False)

Check warning on line 294 in fs_storage/models/fs_storage.py

View check run for this annotation

Codecov / codecov/patch

fs_storage/models/fs_storage.py#L294

Added line #L294 was not covered by tests

def _check_connection(self, fs, check_connection_method):
if check_connection_method == "marker_file":
self._marker_file_check_connection(fs)

Check warning on line 298 in fs_storage/models/fs_storage.py

View check run for this annotation

Codecov / codecov/patch

fs_storage/models/fs_storage.py#L298

Added line #L298 was not covered by tests
elif check_connection_method == "ls":
self._ls_check_connection(fs)
return True

Check warning on line 301 in fs_storage/models/fs_storage.py

View check run for this annotation

Codecov / codecov/patch

fs_storage/models/fs_storage.py#L300-L301

Added lines #L300 - L301 were not covered by tests

@property
def fs(self) -> fsspec.AbstractFileSystem:
"""Get the fsspec filesystem for this backend."""
self.ensure_one()
if not self.__fs:
self.__fs = self._get_filesystem()
self.__fs = self.sudo()._get_filesystem()
if not tools.config["test_enable"]:
# Check whether we need to invalidate FS cache or not.
# Use a marker file to limit the scope of the LS command for performance.
try:
self._check_connection(self.__fs, self.check_connection_method)
except Exception as e:
self.__fs.clear_instance_cache()
self.__fs = None
raise e

Check warning on line 317 in fs_storage/models/fs_storage.py

View check run for this annotation

Codecov / codecov/patch

fs_storage/models/fs_storage.py#L312-L317

Added lines #L312 - L317 were not covered by tests
return self.__fs

def _get_filesystem_storage_path(self) -> str:
Expand Down Expand Up @@ -407,7 +451,8 @@
return []
regex = re.compile(pattern)
for file_path in self.fs.ls(relative_path, detail=False):
if regex.match(file_path):
# fs.ls returns a relative path
if regex.match(os.path.basename(file_path)):
result.append(file_path)
return result

Expand All @@ -430,9 +475,20 @@
def delete(self, relative_path) -> None:
self.fs.rm_file(relative_path)

def action_test_config(self) -> None:
def action_test_config(self):
self.ensure_one()

Check warning on line 479 in fs_storage/models/fs_storage.py

View check run for this annotation

Codecov / codecov/patch

fs_storage/models/fs_storage.py#L479

Added line #L479 was not covered by tests
if self.check_connection_method:
return self._test_config(self.check_connection_method)

Check warning on line 481 in fs_storage/models/fs_storage.py

View check run for this annotation

Codecov / codecov/patch

fs_storage/models/fs_storage.py#L481

Added line #L481 was not covered by tests
else:
action = self.env["ir.actions.actions"]._for_xml_id(

Check warning on line 483 in fs_storage/models/fs_storage.py

View check run for this annotation

Codecov / codecov/patch

fs_storage/models/fs_storage.py#L483

Added line #L483 was not covered by tests
"fs_storage.act_open_fs_test_connection_view"
)
action["context"] = {"active_model": "fs.storage", "active_id": self.id}
return action

Check warning on line 487 in fs_storage/models/fs_storage.py

View check run for this annotation

Codecov / codecov/patch

fs_storage/models/fs_storage.py#L486-L487

Added lines #L486 - L487 were not covered by tests

def _test_config(self, connection_method):
try:
self.fs.ls("", detail=False)
self._check_connection(self.fs, connection_method)

Check warning on line 491 in fs_storage/models/fs_storage.py

View check run for this annotation

Codecov / codecov/patch

fs_storage/models/fs_storage.py#L491

Added line #L491 was not covered by tests
title = _("Connection Test Succeeded!")
message = _("Everything seems properly set up!")
msg_type = "success"
Expand Down
1 change: 1 addition & 0 deletions fs_storage/readme/newsfragments/320.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Invalidate FS filesystem object cache when the connection fails, forcing a reconnection.
1 change: 1 addition & 0 deletions fs_storage/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_fs_storage_edit,fs_storage edit,model_fs_storage,base.group_system,1,1,1,1
access_fs_test_connection,fs.test.connection.access,model_fs_test_connection,base.group_system,1,1,1,1
11 changes: 7 additions & 4 deletions fs_storage/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@

/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.

See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
Expand Down Expand Up @@ -274,7 +275,7 @@
margin-left: 2em ;
margin-right: 2em }

pre.code .ln { color: grey; } /* line numbers */
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
Expand All @@ -300,7 +301,7 @@
span.pre {
white-space: pre }

span.problematic {
span.problematic, pre.problematic {
color: red }

span.section-subtitle {
Expand Down Expand Up @@ -619,7 +620,9 @@ <h2><a class="toc-backref" href="#toc-entry-13">Contributors</a></h2>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-14">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>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.</p>
Expand Down
1 change: 1 addition & 0 deletions fs_storage/views/fs_storage_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
options="{'mode': 'python'}"
placeholder="Enter you fsspec options here."
/>
<field name="check_connection_method" />
</group>
<group>
<notebook colspan="2">
Expand Down
1 change: 1 addition & 0 deletions fs_storage/wizards/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import fs_test_connection
26 changes: 26 additions & 0 deletions fs_storage/wizards/fs_test_connection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

from odoo import api, fields, models


class FSTestConnection(models.TransientModel):
_name = "fs.test.connection"
_description = "FS Test Connection Wizard"

def _get_check_connection_method_selection(self):
return self.env["fs.storage"]._get_check_connection_method_selection()

Check warning on line 11 in fs_storage/wizards/fs_test_connection.py

View check run for this annotation

Codecov / codecov/patch

fs_storage/wizards/fs_test_connection.py#L11

Added line #L11 was not covered by tests

storage_id = fields.Many2one("fs.storage")
check_connection_method = fields.Selection(
selection="_get_check_connection_method_selection",
required=True,
)

@api.model
def default_get(self, field_list):
res = super().default_get(field_list)
res["storage_id"] = self.env.context.get("active_id", False)
return res

Check warning on line 23 in fs_storage/wizards/fs_test_connection.py

View check run for this annotation

Codecov / codecov/patch

fs_storage/wizards/fs_test_connection.py#L21-L23

Added lines #L21 - L23 were not covered by tests

def action_test_config(self):
return self.storage_id._test_config(self.check_connection_method)

Check warning on line 26 in fs_storage/wizards/fs_test_connection.py

View check run for this annotation

Codecov / codecov/patch

fs_storage/wizards/fs_test_connection.py#L26

Added line #L26 was not covered by tests
31 changes: 31 additions & 0 deletions fs_storage/wizards/fs_test_connection.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="fs_test_connection_form_view" model="ir.ui.view">
<field name="name">fs.test.connection.form</field>
<field name="model">fs.test.connection</field>
<field name="arch" type="xml">
<form string="Test Connection">
<group>
<field name="storage_id" readonly="1" />
<field name="check_connection_method" />
</group>
<footer>
<button
type="object"
name="action_test_config"
string="Test connection"
/>
<button string="Close" class="btn-secondary" special="cancel" />

</footer>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="act_open_fs_test_connection_view">
<field name="name">FS Test Connection</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">fs.test.connection</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</odoo>
Loading